Операционная система: Windows XP 64 bit, SP2.
У меня необычная проблема.Я портирую некоторый код с 32 бит на 64 бит.32-битный код работает просто отлично.Но когда я вызываю CreateThread () для 64-битной версии, вызов не выполняется.У меня есть три места, где это не удается.2 вызвать CreateThread ().1 вызывает метод beginthreadex (), который вызывает метод CreateThread ().
Все три вызова завершаются ошибкой с кодом ошибки 0x3E6, «Недопустимый доступ к ячейке памяти».
Проблема в том, что все входные параметры верны.
HANDLE h;
DWORD threadID;
h = CreateThread(0, // default security
0, // default stack size
myThreadFunc, // valid function to call
myParam, // my param
0, // no flags, start thread immediately
&threadID);
Все три вызова CreateThread () выполняются из библиотеки DLL, которую я вставил в целевую программу в начале выполнения программы (это происходит до того, как программа дойдет до начала main () / WinMain ()).Если я вызываю CreateThread () из целевой программы (те же параметры), скажем через меню, это работает.Те же параметры и т.д. Причудливый.
Если я передаю NULL вместо & threadID, он все равно не работает.
Если я передаю NULL как myParam, он все равно не работает.
Яне вызывая CreateThread из DllMain (), так что это не проблема.Я запутался, и поиск в Google и т. Д. Не дал соответствующих ответов.
Если кто-то видел это раньше или у вас есть идеи, пожалуйста, дайте мне знать.
Спасибо за чтение.
ОТВЕТ
Краткий ответ: стековые рамки на x64 должны быть выровнены на 16 байт.
Более длинный ответ: после долгого удара головой об стену отладчикаи публикуя ответы на различные предложения (все из которых помогли в некотором роде, подтолкнув меня к пробованию новых указаний), я начал изучать что-если о том, что было в стеке, до вызова CreateThread ().Это оказалась красная сельдь, но это привело к решению.
Добавление дополнительных данных в стек изменяет выравнивание кадров стека.Рано или поздно один из тестов возвращает вас к 16-байтовому выравниванию стека.На тот момент код работал.Поэтому я пересмотрел свои шаги и начал помещать в стек NULL-данные, а не то, что считал правильными (я выдвигал адреса возврата, чтобы подделать кадр вызова).Это все еще работало - поэтому данные не важны, это должны быть фактические адреса стека.
Я быстро понял, что это было 16-байтовое выравнивание для стека.Ранее я знал только о 8-байтовом выравнивании данных.В этом документе Microsoft объясняются все требования к выравниванию .
Если в x64 не выровнен кадр стека на x64, компилятор может поместить большие (8 или более) данные в неправильные границы выравнивания, когда онпомещает данные в стек.
Отсюда проблема, с которой я столкнулся - код перехвата вызывался со стеком, который не был выровнен по границе 16 байт.
Краткий обзор требований к выравниванию, выраженный в виде размера: выравнивание
- 1: 1
- 2: 2
- 4: 4
- 8: 8
- 10: 16
- 16: 16
Все, что больше 8 байт, выровнено по следующей степени 2.
Я думаю, что код ошибки Microsoft немного вводит в заблуждение.Начальный STATUS_DATATYPE_MISALIGNMENT может быть выражен как STATUS_STACK_MISALIGNMENT, что было бы более полезным.Но затем превращение STATUS_DATATYPE_MISALIGNMENT в ERROR_NOACCESS - это фактически маскирует и вводит в заблуждение относительно того, в чем проблема.Очень бесполезно
Спасибо всем, кто разместил предложения.Даже если я не согласен с предложениями, они побудили меня протестировать в самых разных направлениях (включая те, с которыми я не согласен).
Более подробное описание проблемы несовпадения типов данных написано здесь: 64-битное портирование, погрешность №1!x64 Несовпадение типов данных.