The CreateThread () error in 64-bit Windows runs on 32-bit Windows. What for?

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.

+4
source share
2 answers

The only reason a 64-bit value matters is because streaming on a 64-bit system requires 64-bit aligned values. If the threadID is not 64 bit consistent, you can cause this problem.


Well, this idea is not so. Are you really sure you want to call CreateThread before main / WinMain? This explains why it works in the menu, because after main / WinMain.

Also, I would check myParam's lifespan three times. CreateThread returns (I know from experience) long before you call the function that you pass.


Send the code for the current line (or several lines).


It suddenly occurs to me: are you sure that you are entering your 64-bit code into a 64-bit process? Because if you had a 64-bit CreateThread call and tried to inject it into a 32-bit process under WOW64, bad things could happen.


It starts seriously ending with ideas. Does the compiler report any warnings?


Can an error be caused by an error in the main program, and not in the DLL? There is other code, for example, loading a DLL, if you used __declspec (import / export), which occurs before main / WinMain. If this DLLMain, for example, had an error in it.

+1
source

Try using _beginthread () or _beginthreadex () instead, you should not use CreateThread directly.

See the previous question.

-1
source

Source: https://habr.com/ru/post/1312884/


All Articles