Closed
Description
From bug 22637, glibc 2.27 will be allocating the stack guard page for new threads just past the end of the stack, rather than within it. This has also reached Fedora 27 from rhbz 1527887.
With these versions of glibc, the location calculated in guard::current()
will be incorrect. This causes run-pass/out-of-stack to fail, as our SIGSEGV handler thinks the fault is something other than a guard page. (rather than identifying it as a stack overflow and using rtabort!
)
We could get out of this guessing game by allocating the thread stack and guard page ourselves. If there's no objection, I will attempt this approach. Other ideas are welcome!
(note: this doesn't affect the main thread, as that stack and guard page are managed by the kernel.)
Activity
nagisa commentedon Jan 30, 2018
We should not change how one of the core tasks are done (stack allocation) for the purpose of giving users nicer diagnostics when the stack is overflowed (what the
guard::current
is used for IIRC).If it is possible to adjust the
guard::current
logic to return a correct value – great. Alternatively, we should just live with the notion that this check may be false-negative.cuviper commentedon Jan 30, 2018
I'm having trouble seeing how to cleanly free a manual stack allocation anyway -- when the thread may be detached from where it was spawned, no one but libpthread really knows about it anymore.
I was thinking of trying something like
pthread_attr_setguardsize(attr, 0)
, leaving libpthread to allocate the stack, and then alter the last page withmprotect(PROT_NONE)
ourselves. But that too may be fragile, if libpthread tries to do anything more thanmunmap
with that area on cleanup, when it doesn't know it's protected there.I'll take another look at
guard::current
. One thought is to have this return an address range, rather than just an edge, and then for Linux targets we can cover both within and just past the end of stack. Worst case is that this would misdiagnose an unrelated segv that just happened to be right below the thread stack.cuviper commentedon Jan 30, 2018
BTW, android is ignored in this test due to #20004. #41618 tried to enable it again, and the log has the same
assertion failed: `(left == right)` (left: `Some(11)`, right: `Some(6)`)
, which isSIGSEGV
vs.SIGABRT
. Android probably puts the guard below the stack, as that's really the proper way to do it.Actually musl is ignored too, and probably for the same reason. The glibc-focused assumption that the guard was within the stack is likely wrong for any other libc. (and now glibc is finally fixing this.)
alexcrichton commentedon Jan 31, 2018
@cuviper it seems reasonable to me to print out a message for anything within a range of the predicted guard page, if a fault happens and it wasn't actually a stack overflow, yet we printed, it's probably not the end of the world
cuviper commentedon Jan 31, 2018
Great, I have a patch that does just that. 😀
I'll clean it up and send a PR tomorrow.
Use a range to identify SIGSEGV in stack guards
Rollup merge of rust-lang#47912 - cuviper:glibc-stack-guard, r=alexcr…
Rollup merge of rust-lang#47912 - cuviper:glibc-stack-guard, r=alexcr…
Rollup merge of rust-lang#47912 - cuviper:glibc-stack-guard, r=alexcr…
2 remaining items