Fix segfault by adding type annotations

This commit is contained in:
Richard Feldman 2025-12-08 09:08:55 -05:00
parent d6e802c50f
commit e2a60faa35
No known key found for this signature in database
3 changed files with 23 additions and 6 deletions

View file

@ -1166,22 +1166,26 @@ test "fx platform runtime stack overflow" {
defer allocator.free(run_result.stdout);
defer allocator.free(run_result.stderr);
// After stack overflow handling is implemented, we expect:
// 1. The process exits with code 134 (indicating stack overflow was caught)
// 2. Stderr contains a helpful message about stack overflow
// Stack overflow can be caught by either:
// 1. The Roc interpreter (exit code 1, "overflowed its stack memory" message) - most common
// 2. The SIGABRT signal handler (exit code 134) - if native stack overflow handling is used
switch (run_result.term) {
.Exited => |code| {
if (code == 134) {
// Stack overflow was caught and handled properly
// Stack overflow was caught by native signal handler
// Verify the helpful error message was printed
try testing.expect(std.mem.indexOf(u8, run_result.stderr, "overflowed its stack memory") != null);
} else if (code == 1) {
// Stack overflow was caught by the interpreter - this is the expected case
// The interpreter detects excessive work stack depth and reports the error
try testing.expect(std.mem.indexOf(u8, run_result.stderr, "overflowed its stack memory") != null);
} else if (code == 139) {
// Exit code 139 = 128 + 11 (SIGSEGV) - stack overflow was NOT handled
// The Roc program crashed with a segfault that wasn't caught
std.debug.print("\n", .{});
std.debug.print("Stack overflow handling NOT YET IMPLEMENTED for Roc programs.\n", .{});
std.debug.print("Process crashed with SIGSEGV (exit code 139).\n", .{});
std.debug.print("Expected: exit code 134 with stack overflow message\n", .{});
std.debug.print("Expected: exit code 1 or 134 with stack overflow message\n", .{});
return error.StackOverflowNotHandled;
} else {
std.debug.print("Unexpected exit code: {}\n", .{code});
@ -1194,7 +1198,7 @@ test "fx platform runtime stack overflow" {
std.debug.print("\n", .{});
std.debug.print("Stack overflow handling NOT YET IMPLEMENTED for Roc programs.\n", .{});
std.debug.print("Process was killed by signal: {}\n", .{sig});
std.debug.print("Expected: exit code 134 with stack overflow message\n", .{});
std.debug.print("Expected: exit code 1 or 134 with stack overflow message\n", .{});
return error.StackOverflowNotHandled;
},
else => {

View file

@ -9550,6 +9550,11 @@ pub const Interpreter = struct {
pub const WorkStack = struct {
items: std.array_list.AlignedManaged(WorkItem, null),
/// Maximum work stack size to prevent infinite recursion from hanging.
/// When exceeded, triggers a stack overflow error.
/// 10,000 items allows deep but not infinite recursion (~1MB memory).
pub const max_size: usize = 10_000;
pub fn init(allocator: std.mem.Allocator) !WorkStack {
return .{ .items = try std.array_list.AlignedManaged(WorkItem, null).initCapacity(allocator, 64) };
}
@ -9650,6 +9655,12 @@ pub const Interpreter = struct {
}
},
}
// Check for stack overflow (infinite recursion)
if (work_stack.items.items.len > WorkStack.max_size) {
self.triggerCrash("This Roc program overflowed its stack memory. This usually means there is infinite recursion somewhere in the code.", false, roc_ops);
return error.Crash;
}
}
// Should never reach here - return_result should have exited the loop

View file

@ -18,8 +18,10 @@ parse_range = |range_str| {
}
repeat : List(a), U64 -> List(a)
repeat = |list, n| repeat_helper([], list, n)
repeat_helper : List(a), List(a), U64 -> List(a)
repeat_helper = |acc, list, n| match n {
0 => acc
_ => repeat_helper(acc.concat(list), list, n - 1)