phantom stack entries #169
Labels
No labels
bug
dependencies
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
refactor
rust
technical-debt
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-seq#169
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
when in the repl, no error is thrown when the repl has 2 stack entries and rot is called.
if the stack has (3 4) and rot is called a 0 is infered and the stack is now (4 0).
if rot is called again the stack becomes (0 3).
if rot is called again the stack becomes (3 4) again.
Is this correct behavior?
is the repl show / display processing correct? the stack deptth of 2 never changed despite rot operates on 3 depth and the display shows the program knew about the stack values that dropped off the stack... that the stack seems to be keeping values that are not displayed. This behavior feels like a bug machine. Lets discuss before implementing any changes.
@claude fyi
Claude finished @navicore's task in 3m 57s —— View job
Analysis of phantom stack entries
I've thoroughly analyzed this issue and identified two distinct bugs that work together to create the phantom stack behavior.
The Bugs
Bug #1: Type Checker Allows Insufficient Stack Depth ❌
Expected behavior: The type checker should reject
rotwhen there are fewer than 3 values on the stack.What's happening:
rothas signature( a T U V -- a U V T )incrates/compiler/src/builtins.rs:364(3 4), the type checker should fail during unificationEmpty ← Int ← Int(2 values)a ← T ← U ← V(row variable + 3 values)crates/compiler/src/unification.rs:238-293should detect this mismatch and reject itThe type checker is failing to catch this error, allowing code to compile that will access invalid stack positions.
Bug #2: Runtime Accesses Uninitialized Stack Memory 💣
The "phantom stack entries" are actually undefined behavior from reading uninitialized memory.
Looking at
crates/runtime/src/stack.rs:653-671:There are NO bounds checks. When you call
rotwith only 2 stack items:ptr_apoints to uninitialized stack memory below the logical stack base*ptr_areads whatever garbage value happens to be thereWhy you see a 0: The stack buffer is likely zero-initialized when allocated, so uninitialized positions contain
StackValue { slot0: 0, slot1: 0, ... }which representsInt(0).The cycling behavior: Each
rotoperation rotates 3 positions, including the garbage value:(3 4)+ garbage 0 at position -3rot: garbage rotates to position -2 →(4 0)rot: the 3 rotates from position -3 →(0 3)rot: back to(3 4)at positions -2 and -1Answers to Your Questions
No. This is undefined behavior caused by insufficient type checking and lack of runtime bounds validation. The program should be rejected at compile time.
Yes, the display is correct. It shows exactly what exists on the logical stack (2 values). The "phantom" values you observe during rotation are uninitialized memory being illegally accessed by
rot. The stack depth never actually changes - you're seeing the same 2 positions being rotated with garbage data from below the stack base.Recommendations
This is definitely a bug. Here's what should happen:
Primary Fix: Improve Type Checking (Compile-Time Safety)
The type checker should reject operations that access more stack positions than available:
( a T U V -- a U V T ), extract minimum required depth (3 values)Location:
crates/compiler/src/typechecker.rsin theapply_effectmethod around line 1029.Optional: Runtime Bounds Checking (Defense-in-Depth)
Add runtime assertions for debugging/safety:
get_stack_base())patch_seq_rot, verifystack - 3 >= basebefore accessingThis has performance implications but would catch bugs that slip through type checking.
Next Steps
Before implementing fixes:
Would you like me to:
Let me know how you'd like to proceed!
https://github.com/navicore/patch-seq/pull/170