FAILURE MAP
← Case archive

FA-89406 / Instruction set emulation / Open access

Stack pointer sticks at zero · case 01

Pushing past the bottom of the stack page overwrites the same byte repeatedly.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The decrement saturates instead of wrapping within the page.

THE FAILURE

The decrement saturates instead of wrapping within the page.

Unsuccessful approach: A 9-bit wrap leaves the stack page.

Case contract

Input [pc, sp, ops] for an 8-bit stack pointer addressing page 0x100. push stores at 0x100+sp then decrements sp (wrapping in 8 bits); pull increments sp (wrapping) then reads (unwritten bytes read 0). jsr t (3 bytes at pc) pushes (pc+2) high byte then low byte and jumps; rts pulls low then high and resumes at that address + 1 (16-bit wrap). pha v pushes v, pla pulls; both and nop advance pc by 1. Return [[pc, sp, pulled value or None] per op, sorted [address, byte] of written stack memory].

Why this case matters

Emulated call/return must reproduce the exact stack image because programs inspect and manipulate return addresses on the stack.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(*args):
    pc, sp, ops = args
    mem = {}
    trace = []
    def push(v):
        nonlocal sp
        mem[0x100 + sp] = v & 0xFF
        sp = max(sp - 1, 0)
    def pull():
        nonlocal sp
        sp = (sp + 1) & 0xFF
        return mem.get(0x100 + sp, 0)
    for op in ops:
        got = None
        if op[0] == 'jsr':
            ret = (pc + 2) & 0xFFFF
            push(ret >> 8)
            push(ret)
            pc = op[1]
        elif op[0] == 'rts':
            lo = pull()
            hi = pull()
            pc = ((hi << 8 | lo) + 1) & 0xFFFF
        elif op[0] == 'pha':
            push(op[1])
            pc += 1
        elif op[0] == 'pla':
            got = pull()
            pc += 1
        else:
            pc += 1
        trace.append([pc, sp, got])
    return [trace, [[k, mem[k]] for k in sorted(mem)]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 18], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 86], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2289, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 129, [['jsr', 4660], ['rts']]], [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 19], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 19]], [[510, 34], [511, 19]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 87], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 87]], [[256, 68], [257, 51], [511, 87]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2290, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2293, 255, None]], [[508, 2], [509, 9], [510, 244], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 130, [['jsr', 4660], ['rts']]], [[[4660, 128, None], [0, 130, None]], [[385, 255], [386, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 20], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 20]], [[510, 34], [511, 20]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 88], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 88]], [[256, 68], [257, 51], [511, 88]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2291, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2294, 255, None]], [[508, 2], [509, 9], [510, 245], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 131, [['jsr', 4660], ['rts']]], [[[4660, 129, None], [0, 131, None]], [[386, 255], [387, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 21], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 21]], [[510, 34], [511, 21]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 89], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 89]], [[256, 68], [257, 51], [511, 89]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2292, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2295, 255, None]], [[508, 2], [509, 9], [510, 246], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 132, [['jsr', 4660], ['rts']]], [[[4660, 130, None], [0, 132, None]], [[387, 255], [388, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 22], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 22]], [[510, 34], [511, 22]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 90], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 90]], [[256, 68], [257, 51], [511, 90]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2293, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2296, 255, None]], [[508, 2], [509, 9], [510, 247], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 133, [['jsr', 4660], ['rts']]], [[[4660, 131, None], [0, 133, None]], [[388, 255], [389, 255]]])]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
call and return[[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]][[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]Passed
push and pull[[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]][[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]Passed
stack pointer wraps below page start[[[769, 0, None], [770, 0, None], [771, 0, None], [772, 1, 51]], [[256, 86], [257, 51]]][[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]Failed
pull wraps above page end[[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []][[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]Passed
nested calls[[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]][[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]Passed
return address carries into high byte[[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]][[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]Passed
return from top of memory[[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]][[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]]Passed

SHA-256 / 08313e3fb3c9eca740d438e5e6b41bde83add68027cc28be1336fec09adc880d

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(*args):
    pc, sp, ops = args
    mem = {}
    trace = []
    def push(v):
        nonlocal sp
        mem[0x100 + sp] = v & 0xFF
        sp = (sp - 1) & 0x1FF
    def pull():
        nonlocal sp
        sp = (sp + 1) & 0xFF
        return mem.get(0x100 + sp, 0)
    for op in ops:
        got = None
        if op[0] == 'jsr':
            ret = (pc + 2) & 0xFFFF
            push(ret >> 8)
            push(ret)
            pc = op[1]
        elif op[0] == 'rts':
            lo = pull()
            hi = pull()
            pc = ((hi << 8 | lo) + 1) & 0xFFFF
        elif op[0] == 'pha':
            push(op[1])
            pc += 1
        elif op[0] == 'pla':
            got = pull()
            pc += 1
        else:
            pc += 1
        trace.append([pc, sp, got])
    return [trace, [[k, mem[k]] for k in sorted(mem)]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 18], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 86], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2289, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 129, [['jsr', 4660], ['rts']]], [[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 19], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 19]], [[510, 34], [511, 19]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 87], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 87]], [[256, 68], [257, 51], [511, 87]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2290, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2293, 255, None]], [[508, 2], [509, 9], [510, 244], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 130, [['jsr', 4660], ['rts']]], [[[4660, 128, None], [0, 130, None]], [[385, 255], [386, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 20], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 20]], [[510, 34], [511, 20]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 88], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 88]], [[256, 68], [257, 51], [511, 88]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2291, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2294, 255, None]], [[508, 2], [509, 9], [510, 245], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 131, [['jsr', 4660], ['rts']]], [[[4660, 129, None], [0, 131, None]], [[386, 255], [387, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 21], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 21]], [[510, 34], [511, 21]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 89], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 89]], [[256, 68], [257, 51], [511, 89]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2292, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2295, 255, None]], [[508, 2], [509, 9], [510, 246], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 132, [['jsr', 4660], ['rts']]], [[[4660, 130, None], [0, 132, None]], [[387, 255], [388, 255]]])], [('call and return', [1536, 253, [['jsr', 1792], ['nop'], ['rts']]], [[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]), ('push and pull', [512, 255, [['pha', 22], ['pha', 34], ['pla'], ['pla']]], [[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 22]], [[510, 34], [511, 22]]]), ('stack pointer wraps below page start', [768, 1, [['pha', 51], ['pha', 68], ['pha', 90], ['pla']]], [[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 90]], [[256, 68], [257, 51], [511, 90]]]), ('pull wraps above page end', [1024, 254, [['pla'], ['pla'], ['pla']]], [[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]), ('nested calls', [2293, 255, [['jsr', 2304], ['jsr', 2560], ['rts'], ['rts']]], [[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2296, 255, None]], [[508, 2], [509, 9], [510, 247], [511, 8]]]), ('return address carries into high byte', [4350, 240, [['jsr', 8192], ['rts']]], [[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]), ('return from top of memory', [65533, 133, [['jsr', 4660], ['rts']]], [[[4660, 131, None], [0, 133, None]], [[388, 255], [389, 255]]])]]
for label, args, expected in fixtures[N-1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
call and return[[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]][[[1792, 251, None], [1793, 251, None], [1539, 253, None]], [[508, 2], [509, 6]]]Passed
push and pull[[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]][[[513, 254, None], [514, 253, None], [515, 254, 34], [516, 255, 18]], [[510, 34], [511, 18]]]Passed
stack pointer wraps below page start[[[769, 0, None], [770, 511, None], [771, 510, None], [772, 255, 0]], [[256, 68], [257, 51], [767, 86]]][[[769, 0, None], [770, 255, None], [771, 254, None], [772, 255, 86]], [[256, 68], [257, 51], [511, 86]]]Failed
pull wraps above page end[[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []][[[1025, 255, 0], [1026, 0, 0], [1027, 1, 0]], []]Passed
nested calls[[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]][[[2304, 253, None], [2560, 251, None], [2307, 253, None], [2292, 255, None]], [[508, 2], [509, 9], [510, 243], [511, 8]]]Passed
return address carries into high byte[[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]][[[8192, 238, None], [4353, 240, None]], [[495, 0], [496, 17]]]Passed
return from top of memory[[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]][[[4660, 127, None], [0, 129, None]], [[384, 255], [385, 255]]]Passed

SHA-256 / 2df64d6a8045402f64f17807c1d30dcf6755052aed1750afc082542f16c6d440

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

Verification & scope

A deterministic bounded teaching model of one emulator rule; the instruction semantics are a stipulated contract inspired by common ISAs and are not a claim of cycle-exact or architectural conformance. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:51:17.242992+00:00.

Case digest / fc077379c140e74f830aebf4a46c29ca5b4ac5a1b42924270828d3db6f156bb6