C ++ глотание ошибок - PullRequest
       47

C ++ глотание ошибок

0 голосов
/ 24 декабря 2011

Я пишу приложение, которое взаимодействует через механизм 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).

Может ли кто-нибудь объяснить это поведение?

Edit:

замена цикла печати на:

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 ]

3 голосов
/ 24 декабря 2011

Вы уверены, что unicode_str содержит действительные данные Unicode?

Мой опыт работы с std::wcoutstd::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 s для этой цели.Я надеюсь, что это поможет вам с вашей проблемой.

2 голосов
/ 24 декабря 2011

На самом деле, я достаточно уверен, что это ваша проблема, что я собираюсь сделать это ответом, а не задавать вопрос в комментариях.

Большую часть времени, когда iostream ведет себякак ни странно, это потому что failbit или eofbit (или иногда badbit) установлены.Когда в одном из этих плохих состояний операции ввода-вывода обычно (всегда?) Немедленно возвращаются без каких-либо действий.

Я предполагаю, что неверные данные Unicode приведут к установке failbit или badbit.

В качестве общего принципа отладки, когда я вижу, что iostream ведет себя загадочно, самое первое, что я проверяю, это чтобы убедиться, что поток все еще хорош.И почти каждый раз, когда я обнаруживаю, что поток, на самом деле, не очень хороший, он полностью объясняет загадочное поведение.

Как только вы узнаете, что поток плохой, вы можете выбрать какое-то действие.Для плохих данных Unicode, возможно, достаточно просто вернуть состояние потока обратно в хорошее - я не знаю достаточно о Unicode I / O, чтобы быть уверенным.

...