Operating System: Windows XP 64 bit, SP2.
I have an unusual problem. I port the code from 32 to 64 bits. 32 bit code works just fine. But when I call CreateThread () for the 64-bit version, the call fails. I have three places where this fails. 2 call CreateThread (). 1 calls beginthreadex (), which calls CreateThread ().
All three calls fail with error code 0x3E6, "Invalid memory access."
The problem is that all input parameters are correct.
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);
All three calls to CreateThread () are created from the DLL that I entered into the target program at the beginning of the program execution (this is before the program reached the start of main () / WinMain ()), if I call CreateThread () from the target program (those same parameters), say in the menu, it works. The same parameters, etc. Bizarre
If I pass NULL instead of & threadID, it still doesn't work.
If I pass NULL as myParam, it still doesn't work.
I do not call CreateThread from inside DllMain (), so this is not a problem. I am confused and google search etc. Did not show relevant answers.
If anyone has seen this before or has any ideas, please let me know.
Thank you for reading.
ANSWER
Short answer: Stack Frames on x64 should be aligned by 16 bytes.
Longer answer: After I hit my head hard on the wall of the debugger and posted answers to various suggestions (all this helped me in some way, pushing me to new directions), I began to study something about what was on the stack, before calling CreateThread (). It turned out to be a red herring, but it led to a decision.
Adding additional data to the stack changes the alignment of the stack frame. Sooner or later, one of the tests gives you the ability to align frames in 16 bytes. At this point, the code worked. So I repeated the steps and started pushing NULL data onto the stack, not what I thought was the right values ββ(I clicked the return addresses to fake the call frame). It still worked - so the data is not important, it should be the actual address of the stack.
I quickly realized that for the stack it was 16-byte alignment. I used to know about 8-byte alignment for data. This microsoft document explains all alignment requirements .
If the stack frame is not 16 bytes aligned with x64, the compiler can push large (8 bytes or more) data onto incorrect alignment boundaries when it pushes data onto the stack.
Therefore, the problem I encountered was that the connection code was called with a stack that was not aligned on a 16 byte boundary.
Summary of alignment requirements expressed as size: alignment
- 1: 1
- 2: 2
- 4: 4
- 8: 8
- 10: 16
- 16: 16
Everything that exceeds 8 bytes is aligned at the next power of 2 boundaries.
I think the Microsoft error code is a bit misleading. The initial STATUS_DATATYPE_MISALIGNMENT could be expressed as STATUS_STACK_MISALIGNMENT, which would be more useful. But then turn STATUS_DATATYPE_MISALIGNMENT to ERROR_NOACCESS - which in fact disguises and misleads the problem. Very useless.
Thanks to everyone who posted the suggestions. Even if I do not agree with these proposals, they prompted me to test in a variety of ways (including those with which I did not agree).
A more detailed description of the data inconsistency problem is written: 64-bit porting gotcha # 1! x64 Datatype Inconsistency.