I’ve got another panic with long stdin input. Using the same oneline.txt stdin as in #bugs > ✔ Panic use-after-free with long Stdin + List.append
This time, the minimal bug happens with a while loop.
main! = |_args| {
while True {
if Stdin.line!() == "" {
return Ok({})
}
}
Ok({})
}
I opened an issue https://github.com/roc-lang/roc/issues/8642
https://github.com/roc-lang/roc/pull/8649 should fix this
Richard Feldman said:
https://github.com/roc-lang/roc/pull/8649 should fix this
Hello, I've tested some code with a similar error on your fix branch, and I still got the following use-after-free error :
The spaghetti-flavored, not minimal repro-ified code below :
the_menagerie_with_cumulative_parts =
["fly", "spider", "bird", "cat", "dog", "goat", "cow", "horse"]
.fold(
{list: [], acc_str: ""},
|state, animal| {
dbg state
if animal == "horse" {
return {
list: state.list.append(
(animal, ""),
),
acc_str: "",
}
}
new_part = [add_line(animal), state.acc_str]->Str.join_with("\n")
{
list: state.list.append(
(animal, new_part),
),
acc_str: new_part,
}
},
)
add_line = |animal|
match animal {
"fly" =>
\\I don't know why she swallowed a fly.
\\Perhaps she'll die.
"spider" =>
"She swallowed the spider to catch the fly."
"bird" =>
"She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her."
"cat" =>
"She swallowed the cat to catch the bird."
"dog" =>
"She swallowed the dog to catch the cat."
"goat" =>
"She swallowed the goat to catch the dog."
}
The check output :
[dbg] { acc_str: "", list: [] }
[dbg] { acc_str: "I don't know why she swallowed a fly.
Perhaps she'll die.
", list: [("fly", "I don't know why she swallowed a fly.
Perhaps she'll die.
")] }
thread 68798 panic: Use-after-free: decref on already-freed memory
/home/astating/roc/src/builtins/utils.zig:525:13: 0x4ffea36 in decref (mod.zig)
@panic("Use-after-free: decref on already-freed memory");
^
/home/astating/roc/src/builtins/str.zig:267:40: 0x4ce0606 in decref (mod.zig)
@import("utils.zig").decref(self.getAllocationPtr(), self.capacity_or_alloc_ptr, RocStr.alignment, false, roc_ops);
^
/home/astating/roc/src/eval/StackValue.zig:114:23: 0x4ce0c34 in decrefLayoutPtr (mod.zig)
roc_str.decref(ops);
^
/home/astating/roc/src/eval/StackValue.zig:210:28: 0x4ce21b0 in decrefLayoutPtr (mod.zig)
decrefLayoutPtr(elem_layout, elem_ptr, layout_cache, ops);
^
/home/astating/roc/src/eval/StackValue.zig:133:36: 0x4ce11f9 in decrefLayoutPtr (mod.zig)
decrefLayoutPtr(elem_layout, @ptrCast(elem_ptr), layout_cache, ops);
^
/home/astating/roc/src/eval/StackValue.zig:192:28: 0x4ce1d07 in decrefLayoutPtr (mod.zig)
decrefLayoutPtr(field_layout, field_ptr, layout_cache, ops);
^
/home/astating/roc/src/eval/StackValue.zig:1730:28: 0x4a38b40 in decref (mod.zig)
decrefLayoutPtr(self.layout, self.ptr, layout_cache, ops);
^
/home/astating/roc/src/eval/interpreter.zig:15802:60: 0x4da4664 in applyContinuation (mod.zig)
self.bindings.items[j].value.decref(&self.runtime_layout_store, roc_ops);
^
/home/astating/roc/src/eval/interpreter.zig:9852:71: 0x4a72680 in evalWithExpectedType (mod.zig)
const should_continue = try self.applyContinuation(&work_stack, &value_stack, cont, roc_ops);
^
/home/astating/roc/src/eval/interpreter.zig:558:45: 0x4a379cf in eval (mod.zig)
return try self.evalWithExpectedType(expr_idx, roc_ops, null);
^
/home/astating/roc/src/eval/comptime_evaluator.zig:291:45: 0x47fd32b in evalDecl (mod.zig)
const result = self.interpreter.eval(expr_idx, ops) catch |err| {
^
/home/astating/roc/src/eval/comptime_evaluator.zig:1494:50: 0x47ff101 in evalAll (mod.zig)
const eval_result = self.evalDecl(def_idx) catch |err| {
^
/home/astating/roc/src/compile/compile_package.zig:1065:43: 0x49c0984 in typeCheckModule (mod.zig)
_ = try comptime_evaluator.evalAll();
^
/home/astating/roc/src/compile/compile_package.zig:1118:42: 0x49c1c38 in doTypeCheck (mod.zig)
var checker = try typeCheckModule(self.gpa, env, self.builtin_modules.builtin_module.env, imported_envs.items);
^
/home/astating/roc/src/compile/compile_package.zig:593:37: 0x49c48fc in process (mod.zig)
try self.doTypeCheck(task.module_id);
^
/home/astating/roc/src/compile/compile_package.zig:365:33: 0x49c59d2 in runSingleThread (mod.zig)
try self.process(task);
^
/home/astating/roc/src/compile/compile_package.zig:349:65: 0x49c7846 in buildRoot (mod.zig)
.single_threaded => try self.runSingleThread(),
^
/home/astating/roc/src/compile/compile_build.zig:569:35: 0x49ce37d in build (mod.zig)
try root_sched.*.buildRoot(pkg_root_file);
^
/home/astating/roc/src/cli/main.zig:4411:20: 0x49d3e12 in checkFileWithBuildEnv (main.zig)
build_env.build(filepath) catch {
^
/home/astating/roc/src/cli/main.zig:4508:45: 0x45e5e6e in rocCheck (main.zig)
var check_result = checkFileWithBuildEnv(
^
/home/astating/roc/src/cli/main.zig:741:40: 0x486ff28 in mainArgs (main.zig)
.check => |check_args| rocCheck(allocs, check_args),
^
/home/astating/roc/src/cli/main.zig:678:13: 0x48724c8 in main (main.zig)
mainArgs(&allocs, args) catch {
^
/home/astating/zig-x86_64-linux-0.15.2/lib/std/start.zig:627:37: 0x4872a81 in main (std.zig)
const result = root.main() catch |err| {
^
/home/astating/zig-x86_64-linux-0.15.2/lib/libc/musl/src/env/__libc_start_main.c:95:7: 0x9621e9f in libc_start_main_stage2 (/home/astating/zig-x86_64-linux-0.15.2/lib/libc/musl/src/env/__libc_start_main.c)
exit(main(argc, argv, envp));
^
???:?:?: 0x957af09 in ??? (???)
Unwind error at address `exe:0x957af09` (error.MissingFDE), trace may be incomplete
Aborted
run output :
dbg: { acc_str: "", list: [] }
Roc crashed: e_closure(expr=125): failed to resolve capture 'the_menagerie_with_cumulative_parts' (pattern_idx=0) in module 'food_chain.roc', bindings.len=9
Should I create a separate issue ?
Hi @Astating,
Can you try again with roc yourfile.roc --no-cache to make sure it is using the latest stuff?
Anton said:
Hi Astating,
Can you try again withroc yourfile.roc --no-cacheto make sure it is using the latest stuff?
Done, same outputs.
With a little bit reduced example with smaller strings, it does not fail on the same iteration but a bit later :
the_menagerie_with_cumulative_parts =
["fly", "spider", "bird", "cat", "dog", "goat", "cow", "horse"]
.fold(
{list: [], acc_str: ""},
|state, animal| {
dbg state
new_part = [animal, state.acc_str]->Str.join_with("\n")
{
list: state.list.append(
(animal, new_part),
),
acc_str: new_part,
}
},
)
[dbg] { acc_str: "", list: [] }
[dbg] { acc_str: "fly
", list: [("fly", "fly
")] }
[dbg] { acc_str: "spider
fly
", list: [("fly", "fly
"), ("spider", "spider
fly
")] }
[dbg] { acc_str: "bird
spider
fly
", list: [("fly", "fly
"), ("spider", "spider
fly
"), ("bird", "bird
spider
fly
")] }
[dbg] { acc_str: "cat
bird
spider
fly
", list: [("fly", "fly
"), ("spider", "spider
fly
"), ("bird", "bird
spider
fly
"), ("cat", "cat
bird
spider
fly
")] }
[dbg] { acc_str: "dog
cat
bird
spider
fly
", list: [("fly", "fly
"), ("spider", "spider
fly
"), ("bird", "bird
spider
fly
"), ("cat", "cat
bird
spider
fly
"), ("dog", "dog
cat
bird
spider
fly
")] }
thread 70700 panic: Use-after-free: decref on already-freed memory
Should I create a separate issue ?
Yes, please
Last updated: Dec 21 2025 at 12:15 UTC