Пример win32 исключения исключения несоответствия типов данных

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

3 ответа

Это стало сложнее с последними версиями 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".

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

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

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

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

Чтобы понять, могу ли я вызвать какие-либо сбои при плохом выравнивании, я попытался адаптировать некоторые встроенные сборки из этого ответа в 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 не настроена реагировать на проблемы выравнивания, замеченные самим процессором. Таким образом, все ваши уведомления будут поступать от таких вещей, как предупреждения компилятора или добавленные пользователем проверки во время выполнения самих значений указателя.

Это не приведет к исключению, но и 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
Другие вопросы по тегам