Пример win32 исключения исключения несоответствия типов данных - PullRequest
0 голосов
/ 11 ноября 2018

Может кто-нибудь показать простой пример на c ++, который вызовет исключение смещения типа данных?Я хочу увидеть пример без использования функции RaiseException.

Ответы [ 3 ]

0 голосов
/ 12 ноября 2018

Это стало сложнее с последними версиями MSVC, потому что они больше не учитывают выровненные встроенные функции, такие как _mm_load_ps или _mm_store_ps, они компилируются, как если бы вы запрашивали невыровненные версии. Но у потоковых загрузок есть только выровненная версия, поэтому мы можем использовать ее здесь, чтобы заставить ее завершиться с ошибкой по невыровненному адресу. Например, как это:

__m128i test()
{
    char buffer[17];
    __m128i a = _mm_stream_load_si128((__m128i*)buffer);
    __m128i b = _mm_stream_load_si128((__m128i*)(buffer + 1));
    return _mm_or_si128(a, b);
}

Есть две нагрузки, которые находятся на расстоянии 1 байта, адрес не может быть выровнен оба раза, поэтому он терпит неудачу. Фактическое исключение будет отображаться как «Место чтения нарушения доступа 0xFFFFFFFF».

0 голосов
/ 12 ноября 2018

Я хочу увидеть пример без использования функции RaiseException.

Без , кто , использующий функцию RaiseException? Кто-то должен ... потому что единственный способ получить исключение, перехватываемое конструкцией C ++ (будь то ___ попытка SEH или попытка исключений C ++ ), это если что-то где-то это поднимает.

На аппаратном уровне процессор x86 имеет флаг Alignment Check (AC). Если флаг установлен, тогда прерывание 17 выполняется , когда происходит непривязанный доступ. Но в Windows вы можете перехватить такое прерывание только в режиме ядра .

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

Для того, чтобы проверить, не могу ли я вызвать какие-либо сбои при плохом выравнивании, я попытался адаптировать некоторые встроенные сборки из этого ответа в MSVC. (Синтаксис MSVC отличается, но я понимаю, что это должно быть сделано ... по крайней мере, сделать последующий pushfd и изучить его с извлеченными локальными переменными, предположив, что бит AC действительно изменяется в процессе):

#include <iostream>

int main() {
    __asm {
        pushfd
        mov eax, [esp]
        or eax, 0x40000
        mov [esp], eax
        popfd
    }

    char *data = new char[sizeof(int) + 1];
    int *p = reinterpret_cast<int*>(data + 1);
    *p = 304;
    std::cout << *p;
}

Но, похоже, новые ошибки не появляются. Я не могу прочитать регистр cr0 , чтобы увидеть, установлена ​​ли маска выравнивания, она мне не даст (mov eax, cr0 вызывает ошибку «привилегированная инструкция»). И я не знаю, что Windows использует для ответа на прерывание 17 по умолчанию, может быть, нет? Или, скорее всего, программы x86 в 64-битной сборке Windows не обращают на это внимания, но я не могу выполнить 64-битную инструкцию, потому что MSVC не поддерживает встроенную сборку в 64-битной . : - /

Несмотря ни на что, остаётся вопрос: чтобы ваша Win32 C ++ программа получала уведомление через исключение ошибки выравнивания, что-то должно это сказать ... и Windows не настроена реагировать на проблемы выравнивания, замеченные самим процессором. Таким образом, все ваши уведомления будут поступать от таких вещей, как предупреждения компилятора или добавленные пользователем проверки во время выполнения самих значений указателя.

0 голосов
/ 12 ноября 2018

Это не приведет к исключению, но и g ++, и clang ++ выдают сообщение об ошибке смещения. Возможно, VS тоже.

#include <iostream>
#include <stdexcept>

struct example {
    uint64_t a;
    uint64_t b;
};

int main() {
    example A;
    A.a = 1;
    A.b = 2;
    example* B = (example*)((char*)&A+1);
    try {
        std::cout << B->a << "\n";
        std::cout << "no exception thrown\n";
    } catch(const std::exception& ex) {
        std::cout << "exception: " << ex.what() << "\n";
    }
}

Пример вывода:

test.cpp:15:25: runtime error: member access within misaligned address 0x7ffd3f7cbe21 for type 'struct example', which requires 8 byte alignment
0x7ffd3f7cbe21: note: pointer points here
 00 00 00  01 00 00 00 00 00 00 00  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 0f 40 00 00
              ^
144115188075855872
no exception thrown
...