PERRY_SHADOW_STACK=0 combined with PERRY_STATEPOINTS=1 produces a binary with no precise frame roots at all, silently.
Measured: the statepoint + shadow-off build emits no __perry_gcmap section and is the same size as the plain shadow-off build — yet it ran and printed the correct answer, so nothing about the run suggests the roots are gone.
Why this happens, and why it matters more than the knob
reserve_shadow_slot() is the single entry point that, under native_stack_roots_enabled(), allocates a stack-map slot instead of a shadow-stack slot. Turning the shadow stack off therefore turns statepoints off with it.
Statepoints are an alternative lowering of the shadow stack's root-set analysis, not an independent mechanism. That has a consequence well beyond this knob: "delete the shadow stack and keep statepoints" is not currently expressible. Any plan that treats them as two interchangeable mechanisms — including the adoption plan in docs/engine-plan.md — rests on a premise the code does not support.
Asks
- Make this combination a hard error. A rootless binary that runs and prints the right answer is the worst possible failure mode: it fails open, and nothing observable distinguishes it from a correct build until a collection frees a live object.
- Record in the plan that the two mechanisms share their root-set analysis, so the "swap one for the other" framing gets corrected before anyone builds on it.
Found during the statepoint adoption soak.
PERRY_SHADOW_STACK=0combined withPERRY_STATEPOINTS=1produces a binary with no precise frame roots at all, silently.Measured: the statepoint + shadow-off build emits no
__perry_gcmapsection and is the same size as the plain shadow-off build — yet it ran and printed the correct answer, so nothing about the run suggests the roots are gone.Why this happens, and why it matters more than the knob
reserve_shadow_slot()is the single entry point that, undernative_stack_roots_enabled(), allocates a stack-map slot instead of a shadow-stack slot. Turning the shadow stack off therefore turns statepoints off with it.Statepoints are an alternative lowering of the shadow stack's root-set analysis, not an independent mechanism. That has a consequence well beyond this knob: "delete the shadow stack and keep statepoints" is not currently expressible. Any plan that treats them as two interchangeable mechanisms — including the adoption plan in
docs/engine-plan.md— rests on a premise the code does not support.Asks
Found during the statepoint adoption soak.