New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows split stack complications? #3445

Closed
brson opened this Issue Sep 10, 2012 · 8 comments

Comments

Projects
None yet
7 participants
@brson
Contributor

brson commented Sep 10, 2012

This reddit thread suggests that there are extra precautions necessary for split stacks on Windows.

http://www.reddit.com/r/programming/comments/zk05a/a_trip_down_the_gcc_split_stack_rabbithole/c65bezg

@brson

This comment has been minimized.

Show comment
Hide comment
@brson

brson Sep 10, 2012

Contributor

Full text of reddit comment:

If anyone's thinking of doing this on Windows, please make sure you do it correctly:

Use CreateFiber() and SwitchToFiber() to create and swap in new stack segments. Do not attempt to allocate stack space yourself. This is the only supported way to update the stack bounds in the thread environment block (TEB).

Maintain the singly-linked Structured Exception Handling (SEH) chain pointed to by FS:[0]. This must always consist of singly linked nodes at ascending addresses within the current OS stack. If you are copying out stack blocks, you must either add handlers to bridge across the segments or appropriately link and unlink nodes in each segment. Debugging this problem in Stackless Python was not fun.

Failure to handle either case will lead to hard termination of the process on an exception due to corrupted stack state. I'm not sure if Go handles this in its version, but I didn't see FS: updating code....

Contributor

brson commented Sep 10, 2012

Full text of reddit comment:

If anyone's thinking of doing this on Windows, please make sure you do it correctly:

Use CreateFiber() and SwitchToFiber() to create and swap in new stack segments. Do not attempt to allocate stack space yourself. This is the only supported way to update the stack bounds in the thread environment block (TEB).

Maintain the singly-linked Structured Exception Handling (SEH) chain pointed to by FS:[0]. This must always consist of singly linked nodes at ascending addresses within the current OS stack. If you are copying out stack blocks, you must either add handlers to bridge across the segments or appropriately link and unlink nodes in each segment. Debugging this problem in Stackless Python was not fun.

Failure to handle either case will lead to hard termination of the process on an exception due to corrupted stack state. I'm not sure if Go handles this in its version, but I didn't see FS: updating code....

@metajack

This comment has been minimized.

Show comment
Hide comment
@metajack

metajack May 16, 2013

Contributor

Nominating for production ready.

Contributor

metajack commented May 16, 2013

Nominating for production ready.

@graydon

This comment has been minimized.

Show comment
Hide comment
@graydon

graydon May 16, 2013

Contributor

accepted for production-ready milestone

Contributor

graydon commented May 16, 2013

accepted for production-ready milestone

@vadimcn

This comment has been minimized.

Show comment
Hide comment
@vadimcn

vadimcn Jun 21, 2013

Contributor

Fibers are designed for cooperative multitasking, not for segmented stacks, and will likely create too much overhead to be useful for implementing the latter. Specifically:

  • Fiber stack sizes will be rounded up to the nearest page boundary, so super-small stacks become impossible.
  • SwitchToFiber swaps out the entire CPU context (just like a thread switch would), whereas for segmented stacks you actually need to only switch the stack and keep the rest. You'd probably have to update thread context saved in the other fiber before switching to it (which isn't supported via Win32 API, BTW). Not to mention that it would be orders of magnitude slower than the current morestack() implementation.
Contributor

vadimcn commented Jun 21, 2013

Fibers are designed for cooperative multitasking, not for segmented stacks, and will likely create too much overhead to be useful for implementing the latter. Specifically:

  • Fiber stack sizes will be rounded up to the nearest page boundary, so super-small stacks become impossible.
  • SwitchToFiber swaps out the entire CPU context (just like a thread switch would), whereas for segmented stacks you actually need to only switch the stack and keep the rest. You'd probably have to update thread context saved in the other fiber before switching to it (which isn't supported via Win32 API, BTW). Not to mention that it would be orders of magnitude slower than the current morestack() implementation.
@pnkfelix

This comment has been minimized.

Show comment
Hide comment
@pnkfelix

pnkfelix Aug 14, 2013

Member

visiting for bug triage, email 2013-08-05.

I don't have anything to add beyond what's written on the bug currently, though there certainly seem to be a lot of interesting nitty gritty details here.

Member

pnkfelix commented Aug 14, 2013

visiting for bug triage, email 2013-08-05.

I don't have anything to add beyond what's written on the bug currently, though there certainly seem to be a lot of interesting nitty gritty details here.

@graydon

This comment has been minimized.

Show comment
Hide comment
@graydon

graydon Aug 15, 2013

Contributor

Page boundaries may well be a requirement anyways. I believe they were in the last version of segmented stacks we had. Beyond that, the original poster seems to be trying to help us write non-crashy code when handling exception not fast code. If it's truly the only way to live through an SEH call, we'll have to do something like the recommended thing. Maybe not exactly it, but something that preserves the SEH chain.

Contributor

graydon commented Aug 15, 2013

Page boundaries may well be a requirement anyways. I believe they were in the last version of segmented stacks we had. Beyond that, the original poster seems to be trying to help us write non-crashy code when handling exception not fast code. If it's truly the only way to live through an SEH call, we'll have to do something like the recommended thing. Maybe not exactly it, but something that preserves the SEH chain.

@klutzy

This comment has been minimized.

Show comment
Hide comment
@klutzy

klutzy Oct 11, 2013

Contributor

The comment says we must be aware of stack info at TEB (TIB) which is only officially available by using fiber functions.
However, the internal is well-known (wikipedia link) and the structure is defined at winnt.h (both mingw and msvc).
In the header, struct NT_TIB has two members named StackBase and StackLimit. They indicates the stack range (StackLimit~StackBase) and Windows internally uses them for page check.
Also msvcrt functions (e.g. puts or MessageBoxW) may buzz if ESP is below StackLimit (I got it on win64).

When I did mingw-w64 work (#8488), I added management code for them.
However we lack of TIB support on 32-bit Windows. I'm not totally sure why it even works well :-/ Maybe msvcrt does not use TIB for stack checking.

Factor and Go do similar to what I did. Factor developer left a blog post which is great source for this issue. Here is relevant Factor code I guess.
Go does somewhat tricky: they just sets StacLimit = 0; StackBase = 0xffffffffffff. (sys_windows_amd64.s, setstacklimits routine) This is simple but there may be some issues regarding ffi (e.g. what if Go routine calls C function then it exceeds the stack limit?)

Contributor

klutzy commented Oct 11, 2013

The comment says we must be aware of stack info at TEB (TIB) which is only officially available by using fiber functions.
However, the internal is well-known (wikipedia link) and the structure is defined at winnt.h (both mingw and msvc).
In the header, struct NT_TIB has two members named StackBase and StackLimit. They indicates the stack range (StackLimit~StackBase) and Windows internally uses them for page check.
Also msvcrt functions (e.g. puts or MessageBoxW) may buzz if ESP is below StackLimit (I got it on win64).

When I did mingw-w64 work (#8488), I added management code for them.
However we lack of TIB support on 32-bit Windows. I'm not totally sure why it even works well :-/ Maybe msvcrt does not use TIB for stack checking.

Factor and Go do similar to what I did. Factor developer left a blog post which is great source for this issue. Here is relevant Factor code I guess.
Go does somewhat tricky: they just sets StacLimit = 0; StackBase = 0xffffffffffff. (sys_windows_amd64.s, setstacklimits routine) This is simple but there may be some issues regarding ffi (e.g. what if Go routine calls C function then it exceeds the stack limit?)

@alexcrichton

This comment has been minimized.

Show comment
Hide comment
@alexcrichton

alexcrichton Oct 29, 2013

Member

In today's meeting we have decided to jettison segmented stacks. Additionally, we are currently managing custom stack bounds in the TEB/TIB on win64 (as pointed out by @klutzy), so I believe that this is closed.

If this should stay open though, then feel free to reopen!

Member

alexcrichton commented Oct 29, 2013

In today's meeting we have decided to jettison segmented stacks. Additionally, we are currently managing custom stack bounds in the TEB/TIB on win64 (as pointed out by @klutzy), so I believe that this is closed.

If this should stay open though, then feel free to reopen!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment