Re: x86 exception handling and stack demand



When an exception occurs that will be passed down to user mode as an SEH exception, the kernel arranges for control to return to user mode at a special function in NTDLL, with several parameters on the stack (as defined by the current user mode stack pointer) containing information about the exception. When control finally returns to user mode, the NTDLL function calls the exception dispatcher so that user mode SEH frames can be searched and called accordingly.

(Keep in mind that these are implementation details for NT-based systems and are theoretically subject to change. However, they may be useful for understanding what happens in the cases you mentioned, in current implementations.)

You may not have a chance to expand the stack in these scenarios as there will already need to be enough stack available for exception dispatching to occur. Therefore, it might be a good idea to keep some reserve stack space so that if you get an SEH exception, you won't be in so much danger of overflowing the stack you currently have committed.

In the case of system allocated stacks using guard pages, the memory manager in kernel mode is responsible for noticing guard page exceptions caused by the current thread in reference to a stack address and committing additional pages, so the built-in stack expansion strategy seamlessly works with SEH. I doubt you'll be able to accomplish this in your implementation since any user mode exception handling requires some stack space available, so it would probably be best to always keep some in reserve.

As far as thread termination via TerminateThread, prior to Windows XP, any stack you had allocated would be leaked permanently in that case. (Don't use TerminateThread!)

In XP and later, the system stores a pointer to the initial stack allocation block in the TEB that is used by the kernel to decommit the stack via NtFreeVirtualMemory when the thread is terminated in a non-graceful fashion, closing this leak (this doesn't mean that it is okay to use TerminateThread though, as there are a number of other "Broken by design" problems with it, in general, outside of the context of special case programs like debuggers). This pointer is stored during CreateThread and is normally never updated throughout the threads lifetime.

I agree with Jakob, though, in general. You'd likely be better off using the built in stack allocation mechanisms. Among other things, stuff like minidumps may work better if you don't change the stack out from under the thread like that without updating all references to it (e.g. in the NT_TIB).

--
Ken Johnson (Skywing)
Windows SDK MVP
http://www.nynaeve.net
"Ira Baxter" <idbaxter@xxxxxxxxxxxxxx> wrote in message news:uIfe1tHyHHA.3564@xxxxxxxxxxxxxxxxxxxxxxx
I've implemented a language running under Windows
that allocates stack frames from a heap.
The present implementation run on x86-32, not x86-64.
I'd like to minimize the size of these frames for x86-32.

To compute the size of a stack frame, the compiler has to know
what the demand for stack space is. It can compute the demand
induced by source code it is compiling straightfowardly and does so.
It can control the demand caused by calls on system services by
providing a modest allocation of some fixed size, and switching
to a big conventional stack in those few cases where the modest allocation
isn't enough.

What I don't understand is the demands placed on the stack by exceptions
and asynchronous thread stop/start operations, and I don't know where
to look for this information. I know generally about structured exception
handling
(via Matt Pietrek's articles http://msdn2.microsoft.com/en-us/default.aspx)
and have running exception handlers for the language.

What I don't understand well:
1) When a hardware exception occurs (e.g., division by zero), where is
the Context information stored? I'd guess on the stack because "push" is
so easy.
2) When a floating point exception occurs, where does floating point
state get placed? Also on the stack? (If so, it makes for huge stack
demands)
3) When a thread is stopped (SuspendThread), what state (see 1 and 2 above)
gets stored, and where?

Can I control where this state gets stored? It would be useful if I could
tell
Windows on a thread-specific basis, to store this in preallocated buffers.

Any information or suggestions on documentation?

-- IDB






.



Relevant Pages

  • Re: x86 exception handling and stack demand
    ... All of the state there is maintained in kernel-mode-only store locations and is not stored on the user mode stack. ... This varies based on all installed SEH frames, and that can vary based on OS version, third party programs installed, CRT version, and many other things. ... However, consider that in the case of a STATUS_STACK_OVERFLOW exception, the only stack available is the last committed page that was formerly marked as a guard page. ...
    (microsoft.public.win32.programmer.kernel)
  • [PATCH] x86: style fascism for xen assemblies
    ... * a view to being able to inline as much as possible. ... push %eax ... * This is run where a normal iret would be run, with the same stack setup: ... In order to deliver the nested exception properly, ...
    (Linux-Kernel)
  • RE: System.AccessViolationException in .NET 2.0 application
    ... Based on the call stack, there is an AV exception in the ... Microsoft Online Community Support ...
    (microsoft.public.dotnet.general)
  • Controlled types and exception safety
    ... I can classify the stack's operations by assigning them any of the above four levels, so that I know what can be expected when an exception is thrown for any reason (like inability to allocate more memory, or alike). ... For example, if the Push method of the stack gives me the strong guarantee, then I *know* that by calling this method either the new element will be appended to the stack, or the stack will remain unchanged, so that even if the exception is thrown, I don't have to worry about the stack's internal consistency. ... Since stack can be a dynamic data structure, assigning one stack object to another may involve destroying one existing data structure *and* creating a new one in its place. ...
    (comp.lang.ada)
  • Re: x86 exception handling and stack demand
    ... Can I side step the SEH completely? ... directly if it means I don't have to choke on stack bloat. ... will already need to be enough stack available for exception dispatching ... the built in stack allocation mechanisms. ...
    (microsoft.public.win32.programmer.kernel)

Loading