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::wostreams в общем) заключается в том, что они попадают в плохое состояние всякий раз, когда им дают недопустимые данные 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, чтобы быть уверенным.

Другие вопросы по тегам