C++ глотание ошибок
Я пишу приложение, которое взаимодействует через механизм Windows RPC с размещенным интерфейсом в другом процессе.
Маршалинг обрабатывается с помощью стандартного встроенного NDR. Интерфейс предоставляет несколько функций, одна из которых возвращает строку (UNICODE_STRING
) через параметр.
Функция возвращает 0 в случае успеха или код ошибки в противном случае. Теперь, когда я вызываю функцию RPC, она завершается успешно, и параметр UNICODE_STRING заполняется.
Проблема в том, что либо C++, либо среда выполнения проглатывает ошибку, возникающую при попытке прочитать строку, возвращаемую функцией. Чтобы сэкономить на чтении большого количества кода, вот сокращенная версия моего кода:
void func()
{
UNICODE_STRING unicode_str;
HMODULE hLib = LoadLibrary(L"Ntdll.dll");
RtlInitUnicodeStringFn fn;
fn = (RtlInitUnicodeStringFn) GetProcAddress(hLib, "RtlInitUnicodeString");
fn(&unicode_str, NULL);
std::cout << "Before calling RPC the buffer was pointing at: " << std::hex << unicode_str.Buffer << std::endl;
if(call(binding.get_binding_handle(), &unicode_str))
{
std::cout << "len: " << unicode_str.Length << " maxlen: " << unicode_str.MaximumLength << std::endl;
std::cout << "After calling RPC the buffer is pointing at: " << std::hex << unicode_str.Buffer << std::endl;
try
{
for(int i = 0; i < unicode_str.Length; i++)
std::wcout << i << ": " << unicode_str.Buffer[i] << std::endl;
}
catch(...)
{
std::cout << "Caught an exception";
}
std::wcout << "I won't be written" << std::endl;
}
}
bool call(void* handle, PUNICODE_STRING str)
{
__try
{
std::cout << "RPC call returned: " << RpcInterfaceFunction(handle, str) << std::endl;
return true;
}
__except(1)
{
std::cout << "Error: " << std::dec << GetExceptionCode() << std::endl;
return false;
}
}
После выполнения этого кода, вывод:
Before calling RPC the buffer is pointing at : 000000000
RPC call returned: 0
len:68, maxlen: 70
After calling RPC the buffer is pointing at: 00746168
0: #
1: t
2:
и возвращается. Я прошел с отладчиком через эту функцию, и он правильно проходит через все 68 символов (независимо от того, что находится в буфере - это мусорные данные) и переходит к последнему I won't be written
Wcout инструкция правильно. Я задавался вопросом, была ли проблема с нечитаемыми символами, которые консоль не может обработать, и эти символы могли изменить поведение следующего символа или курсор консоли - и это сделало бы вывод невидимым, но нет - я обменял поток вывода и установил это в файл (wofstream), а размер файла составлял 47 байт - это ровно столько же, сколько записано в поток консоли.
Я не получаю никаких нарушений прав доступа, никаких исключений, никаких записей в журнале, ничего. Даже отладчик (VS2010) не замечает никаких исключений после выбора разбиения на все возможные типы исключений - еще более удивительным является то, что пошаговое выполнение кода с помощью отладчика и просмотр локальных там дает ожидаемые значения (из 0 до 68 и текущее значение wchar_t в буфере имеет значение (мусорный символ в кодировке Unicode).
Кто-нибудь может объяснить это поведение?
Редактировать:
поменять местами цикл печати:
for(int i = 0; i < unicode_str.Length; i++)
{
std::wcout << "I'm writing the " << i << "th character" << std::endl;
unsigned short temp = unicode_str.Buffer[i];
std::wcout << i << ": " << temp << std::endl;
}
Печатает значения temp
правильно до 67.
Но все же, почему печать версии этих символов wchar_t останавливает поток вывода от принятия чего-либо?
2 ответа
Вы уверены, что unicode_str
содержит действительные данные Unicode?
Мой опыт работы с std::wcout
(а также std::wostream
s в общем) заключается в том, что они попадают в плохое состояние всякий раз, когда им дают недопустимые данные Unicode И по умолчанию они не генерируют исключения, когда это происходит: они просто устанавливают свой внутренний failbit или badbit и перестают работать. Вы можете проверить, находится ли поток в плохом состоянии, вызвав std::wcout.fail()
или же std::wcout.bad()
и вы можете очистить флаги состояния ошибки, вызвав std::wcout.clear()
,
Кроме того, если вы хотите, чтобы исключение было выброшено, когда установлен бит или бит, вы можете вызвать std::wcout.exceptions(std::wostream::failbit | std::wostream::badbit)
,
Таким образом, суть в том, что я бы рекомендовал не использовать std::wostream
с этой целью. Я надеюсь, что это поможет вам с вашей проблемой.
На самом деле, я достаточно уверен, что это ваша проблема, что я собираюсь сделать это ответом, а не задавать вопрос в комментариях.
Большую часть времени, когда iostream
ведет себя загадочно, потому что failbit
или же eofbit
(или иногда badbit
) устанавливается. Когда в одном из этих плохих состояний операции ввода / вывода обычно (всегда?) Немедленно возвращаются, ничего не делая.
Я предполагаю, что плохие данные Unicode вызовут failbit
или же badbit
чтобы установить.
Как общий принцип отладки, когда я вижу iostream
ведя себя таинственно, самое первое, что я проверяю, это чтобы убедиться, что поток все еще хорош. И почти каждый раз, когда я обнаруживаю, что поток на самом деле не очень хороший, он полностью объясняет загадочное поведение.
Как только вы узнаете, что поток плохой, вы можете принять решение о некоторых действиях. Для плохих данных Unicode, возможно, достаточно просто вернуть состояние потока обратно в хорошее - я не знаю достаточно о Unicode I/O, чтобы быть уверенным.