On Windows, the stack grows from large to smaller addresses. Sometimes this is defined architecturally, and sometimes it is just an accepted agreement. The value of the stack pointer (processor register) is a pointer to the value at the top of the stack. And the values located deeper in the stack, respectively, are located at large addresses. But what happens to data that is located at addresses smaller than the stack pointer?
Conventions for some (but not all) architectures define a red zone, which is the memory area under the stack pointer, but which is still valid for use by the application.
For Windows, the size of the red zone varies depending on the hardware architecture and is often zero.
Architecture | Red zone size |
---|---|
x86 | 0 bytes |
x64 | 0 bytes |
Itanium | 16 bytes * |
Alpha AXP | 0 bytes |
Mips32 | 0 bytes |
PowerPC | 232 bytes ** |
ARM32 | 8 bytes |
ARM64 | 16 bytes |
* It is worth noting a feature on the Itanium platform: there is a red zone located above the stack pointer , and not under it.
** In the case of PowerPC, the red zone is a side effect of the calling convention .
Any memory behind the red zone (downstream) is considered volatile and can be changed by the operating system at any time.
But seriously, why does the operating system in general care about what I do with my stack? I mean, this is my stack! The operating system does not tell me what to do with the memory that I allocate through VirtualAlloc
. What makes a stack different from any other memory?
Consider the following code for the x86 platform :
MOV [esp-4], eax ; eax MOV ecx, [esp-4] ; ecx CMP ecx, eax ; ? JNZ panic ; N: -
The coding convention for assembly language says that comments for transition instructions should describe the result if the transition is completed. In the example above, the CMP instruction asks the question "Are they the same?". And the JNZ instruction goes if they are not equal. Thus, the comment starts with “N:”, which means that the transition will be executed if the answer to the previous question is “No”, and the situation in the remainder of the comment describes the transition itself.
Yes, we have a coding agreement for the assembler.
Is it possible that the conditional transition will be implemented?
Since there is no red zone on x86, the memory with negative offsets relative to the stack pointer can be overwritten at any time. Therefore, for the above code, you can go to the label panic
.
The debugger can use the memory behind the red zone as a convenient place to store its data. For example, if you use the .call command , the debugger will make the nested call in the same stack and will probably use part of this stack space to save the registers so that they can be restored after returning from the called function. Therefore, any data stored outside the red zone will be destroyed.
Even during normal operation, the operating system can overwrite data outside the red zone at any time. Here, for example, how this can happen:
Suppose that your thread (thread) has worked its time quantum immediately after saving the data outside the red zone. While your thread waits for the ability to resume execution, the memory manager temporarily takes a physical page out of your code (page out). In the end, your thread gets control again and the memory manager tries to load the code page back (page in). Oh no, an I / O error occurs during the swap! The operating system puts an exception frame for STATUS_IN_PAGE_ERROR
on the stack, which leads to the corruption of the data that you saved behind the red zone.
The operating system dispatches this exception. It refers to the vector exception handler ( VEH ), which is another part of your program. The handler was installed specifically to handle exceptions arising from the possible launch of your program directly from a CD-ROM or an unreliable network file system. The program displays a prompt asking the user to re-insert the CD and offers to try again. If the user says that he needs to repeat, the vector exception handler returns EXCEPTION_CONTINUE_EXECUTION
, and the operating system restarts the instruction on which the exception occurred.
This time the restart completes successfully, because the CD-ROM is present (and readable) and the code can be successfully paged into memory. The following instruction is executed, which loads the value outside the red zone into the ecx
. But this is not the same value that was saved by the previous instruction, since the exception STATUS_IN_PAGE_ERROR
overwritten it. The comparison says that the data is different, and we go to the label panic
.
If you want to keep the data on the stack, put it there correctly: first, decrement the stack pointer, and then save the value in the valid part of the stack. Do not hide the data behind the red zone, this memory can be changed at any time without your knowledge.
Source: https://habr.com/ru/post/435814/
All Articles