From 4e22f464387725a5a282f3d72e11cfb694a31a5a Mon Sep 17 00:00:00 2001 From: _ov4 Date: Sat, 17 Oct 2026 05:33:33 +0000 Subject: feat(memory): add checked REALLOC with failure preservation Co-Authored-By: Claude Fable 5.1 --- tests/i/memory-reallocation/case.json | 1 + tests/i/memory-reallocation/expected.txt | 17 +++++++ tests/i/memory-reallocation/notes.md | 5 ++ tests/i/memory-reallocation/program.cps | 81 ++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 tests/i/memory-reallocation/case.json create mode 100644 tests/i/memory-reallocation/expected.txt create mode 100644 tests/i/memory-reallocation/notes.md create mode 100644 tests/i/memory-reallocation/program.cps (limited to 'tests/i/memory-reallocation') diff --git a/tests/i/memory-reallocation/case.json b/tests/i/memory-reallocation/case.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/i/memory-reallocation/case.json @@ -0,0 +1 @@ +{} diff --git a/tests/i/memory-reallocation/expected.txt b/tests/i/memory-reallocation/expected.txt new file mode 100644 index 0000000..9e9ccc9 --- /dev/null +++ b/tests/i/memory-reallocation/expected.txt @@ -0,0 +1,17 @@ +TRUE +12:34 +12 +[Fatal] line 28: Memory allocation failed +preserved:12 +56 +TRUE +[Fatal] line 40: Invalid memory address (not an active allocation) +released address caught +[Fatal] line 47: Invalid memory address (not an active allocation) +invalid zero resize caught +71 +[Fatal] line 63: Invalid memory address (not an active allocation) +[Fatal] line 69: Invalid memory address (not an active allocation) +nested catch +[Fatal] line 77: Invalid memory address (not an active allocation) +internal buffer caught diff --git a/tests/i/memory-reallocation/notes.md b/tests/i/memory-reallocation/notes.md new file mode 100644 index 0000000..46560f5 --- /dev/null +++ b/tests/i/memory-reallocation/notes.md @@ -0,0 +1,5 @@ +# Trace notes + +Human review: pending. + +This case exercises explicit memory extensions. REALLOC(null, 0) returns null; REALLOC(null, 16) allocates. The record's 12 and 34 survive growth, and 12 survives shrinking to one INTEGER. A SIZE_MAX request fails without changing the pointer or its stored 12; a subsequent write of 56 survives resizing. A zero resize frees the block and returns null. Resizing its released address throws; a stack pointer throws even at zero size. C int 71 survives reallocation after an allocation returned from a function. Invalid resizing inside a function unwinds to its caller; another invalid free is caught inside that catch. A STRING literal is rejected as untracked storage. The final nested allocation/resize/free has no output. diff --git a/tests/i/memory-reallocation/program.cps b/tests/i/memory-reallocation/program.cps new file mode 100644 index 0000000..d119256 --- /dev/null +++ b/tests/i/memory-reallocation/program.cps @@ -0,0 +1,81 @@ +TYPE Raw = C_TYPE("void*") +TYPE NativePointer = C_TYPE("int*") +TYPE Pair + DECLARE First : INTEGER + DECLARE Second : INTEGER +ENDTYPE +TYPE PairPointer = ^Pair +TYPE IntPointer = ^INTEGER +DECLARE Empty : Raw +DECLARE P : Raw +DECLARE Q : Raw +DECLARE Number : INTEGER +DECLARE Pointer : IntPointer +DECLARE PairAddress : PairPointer +DECLARE Native : NativePointer +OUTPUT REALLOC(Empty, 0) = Empty +P <- REALLOC(Empty, 16) +PairAddress <- (PairPointer)P +PairAddress^.First <- 12 +PairAddress^.Second <- 34 +P <- REALLOC(P, 32) +PairAddress <- (PairPointer)P +OUTPUT PairAddress^.First, ":", PairAddress^.Second +P <- REALLOC(P, (C_INT)8) +Pointer <- (IntPointer)P +OUTPUT Pointer^ +TRY + P <- REALLOC(P, -1) +CATCH + Pointer <- (IntPointer)P + OUTPUT "preserved:", Pointer^ +ENDTRY +Pointer^ <- 56 +P <- REALLOC(P, 16) +Pointer <- (IntPointer)P +OUTPUT Pointer^ +Q <- P +OUTPUT REALLOC(P, 0) = Empty +TRY + REALLOC(Q, 8) +CATCH + OUTPUT "released address caught" +ENDTRY +Pointer <- ^Number +Q <- (Raw)Pointer +TRY + REALLOC(Q, 0) +CATCH + OUTPUT "invalid zero resize caught" +ENDTRY +FUNCTION AllocateNative() RETURNS Raw + RETURN MALLOC(16) +ENDFUNCTION +P <- AllocateNative() +Native <- (NativePointer)P +Native^ <- (C_INT)71 +P <- REALLOC(P, 32) +Native <- (NativePointer)P +OUTPUT Native^ +FREE(P) +// A runtime failure raised from a function propagates to the caller. +FUNCTION InvalidResize(Value : Raw) RETURNS Raw + RETURN REALLOC(Value, 8) +ENDFUNCTION +TRY + InvalidResize(Q) +CATCH + TRY + FREE(Q) + CATCH + OUTPUT "nested catch" + ENDTRY +ENDTRY +// STRING storage is deliberately outside the explicit allocation list. +Q <- (Raw)(C_STRING)"internal" +TRY + REALLOC(Q, 16) +CATCH + OUTPUT "internal buffer caught" +ENDTRY +FREE(REALLOC(Empty, (C_INT)8)) -- cgit v1.3.1-4-g156e