0.20.0 --- a context can say where it stands, so the C library stops refusing - #50
Merged
Merged
Conversation
…refusing 0.19.3 answered `pthread_getattr_np` with `ENOSYS` for every thread, because musl's own answer was wrong in both directions: for the first context it began at the auxiliary vector, which this port points at a static array, and found a bottom by growing a mapping the dispatcher refuses; for a started one it named the mapping `pthread_create` allocated, which `kal_task_start` supplies the stack instead of. A caller that trusted either walked off the stack it was on. That was honest and was not an answer. OPENKAL 0.15 LETS A RUNNING CONTEXT SAY WHERE IT STANDS, so the port answers with the region the CALLING thread is actually on --- `kal_task_stack`, measured by the implementation beneath --- and refuses for any other thread, uniformly and never with a range. The refusal is not a gap left here: a context can only be asked about itself, because a handle is meaningful only to the party that obtained it and there is no handle to a context at all. `ENOSYS` is also what an implementation that cannot measure produces, and it is what `getrlimit(RLIMIT_STACK)` already answers here. WHAT IS WRITTEN TO THE ATTRIBUTE IS MUSL'S OWN ARRANGEMENT: the stack address is the high end and the size the distance down from it, which is what `pthread_attr_getstack` subtracts to answer POSIX's lowest usable address. The guard size is zero because the region reported has no guard inside it, and on failure nothing is written at all --- not even zeroed, because zero is a value this structure can legitimately hold and a caller that ignored the return would read "no stack recorded" rather than "this call did not answer". The `[c-abi-absent]` row is WITHDRAWN with its reasoning left where the row was, and the README's absent-table row with it: no single form describes the call as a whole, since `enosys` would be false of the common spelling and `accepted-no-effect` false of the general case. The assertion moved to the example that reads it rather than being dropped. `examples/stack-bounds` now asserts CONTAINMENT --- the region contains a local of the context that asked, for the first context and for a started one, and the two are not the same region --- and asserts the refusal for another thread, whose identifier is already joined and is compared rather than read. Numbers are not compared: lengths and addresses are the system's, and containment is the property both wrong answers violated. Measured here on x86_64 Linux against openkal-linux 0.16.0: the first context is reported a 3280896-byte region containing its own stack, a started context the 262144-byte region it was allocated, and another thread is refused.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A context can say where it stands, so the C library stops refusing
pthread_getattr_npanswers with the region the calling thread is actually on, and refuses for any other thread. The specification half is mcpplibs/openkal#45; the design is in that repository's.agents/docs/2026-10-02-stack-bounds-of-a-context-design.md.What this replaces
0.19.3 answered
ENOSYSfor every thread, because musl's own answer was wrong in both directions: for the first context it began at the auxiliary vector, which this port points at a static array, and found a bottom by growing a mapping the dispatcher refuses; for a started one it named the mappingpthread_createallocated, whichkal_task_startsupplies the stack instead of. A caller that trusted either walked off the stack it was on — WebAssembly Micro Runtime 2.4.5 did, and died withSIGSEGVinsidewasm_runtime_init. That refusal was honest and was not an answer.openkal 0.15 lets a running context say where it stands, so the port answers from it.
The refusal that remains is the shape of the interface, not a gap here
A context can only be asked about itself: a handle is meaningful only to the party that obtained it, and there is no handle to a context at all. So another
pthread_tis refused — uniformly, never with a range — and that is also the answer an implementation beneath that cannot measure produces.What is written to the attribute is musl's own arrangement
The stack address is the high end and the size the distance down from it, which is what
pthread_attr_getstacksubtracts to answer POSIX's lowest usable address. The guard size is zero because the region reported has no guard inside it, and on failure nothing is written at all — not even zeroed, because zero is a value this structure can legitimately hold and a caller that ignored the return would read "no stack recorded" rather than "this call did not answer".The absent row is withdrawn, with its reasoning
[c-abi-absent]no longer carriespthread_getattr_np: no single form describes the call as a whole, sinceenosyswould be false of the common spelling andaccepted-no-effectfalse of the general case. The reasoning is left where the row was, and the README's table row with it. The assertion moved to the example that reads it rather than being dropped —tools/check-absent.shstill passes, with 24 rows.Verification
examples/stack-boundsasserts containment — the region contains a local of the context that asked, for the first context and for a started one, and the two are not the same region — and asserts the refusal for another thread. Measured here on x86_64 Linux againstopenkal-linux0.16.0:The first context is reported a region containing its own stack, a started context the 262144-byte region
kal_task_startallocated it, and another thread is refused. The continuous integration step greps for those three readings rather than for a number, becauseENOSYSis 38 on Linux and 78 on Darwin and the step runs on both rows.