[The Old New Thing] Can I use my stack as I like?

Original author: Raymond Chen
  • Transfer

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.

ArchitectureRed zone size
x860 bytes
x640 bytes
Itanium16 bytes *
Alpha AXP0 bytes
Mips320 bytes
PowerPC232 bytes **
ARM328 bytes
ARM6416 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: случилось что-то безумное

Explanation of a comment for JNZ instructions

The coding convention for assembler 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.

Соглашение о кодировании для ассемблера?

Да, у нас есть соглашение о кодировании для ассемблера.

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 is waiting to resume execution, the memory manager temporarily takes a physical page out from your code. 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 pushes the exception frame STATUS_IN_PAGE_ERRORonto the stack, which leads to data corruption that you have 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 register ecx. But this is not the value that was saved by the previous instruction, since the exception STATUS_IN_PAGE_ERRORoverwritten 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.

Also popular now: