mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Merge pull request #8649 from roc-lang/fix-double-decref
Fix double-decref
This commit is contained in:
commit
9cd58ee4ab
3 changed files with 36 additions and 13 deletions
|
|
@ -229,6 +229,16 @@ pub const io_spec_tests = [_]TestSpec{
|
|||
.io_spec = "1>ok",
|
||||
.description = "Regression test: List.first with function syntax",
|
||||
},
|
||||
.{
|
||||
.roc_file = "test/fx/stdin_while_uaf.roc",
|
||||
.io_spec = "0<123456789012345678901234|1>123456789012345678901234|0<|1>",
|
||||
.description = "Regression test: Stdin.line! in while loop with 24 char input (heap-allocated string)",
|
||||
},
|
||||
.{
|
||||
.roc_file = "test/fx/stdin_while_uaf.roc",
|
||||
.io_spec = "0<short|1>short|0<|1>",
|
||||
.description = "Regression test: Stdin.line! in while loop with short input (small string optimization)",
|
||||
},
|
||||
};
|
||||
|
||||
/// Get the total number of IO spec tests
|
||||
|
|
|
|||
|
|
@ -14217,11 +14217,9 @@ pub const Interpreter = struct {
|
|||
var args = [1]StackValue{operand};
|
||||
const result = try self.callLowLevelBuiltin(low_level.op, &args, roc_ops, null);
|
||||
|
||||
// Decref operand based on ownership semantics
|
||||
const arg_ownership = low_level.op.getArgOwnership();
|
||||
if (arg_ownership.len > 0 and arg_ownership[0] == .borrow) {
|
||||
operand.decref(&self.runtime_layout_store, roc_ops);
|
||||
}
|
||||
// Note: We do NOT decref the operand here.
|
||||
// The defer statement at the top of unary_op_apply already handles decrefing.
|
||||
// Decrefing here too would cause a double-free bug.
|
||||
|
||||
self.env = saved_env;
|
||||
try value_stack.push(result);
|
||||
|
|
@ -14578,14 +14576,11 @@ pub const Interpreter = struct {
|
|||
var args = [2]StackValue{ lhs, rhs };
|
||||
var result = try self.callLowLevelBuiltin(low_level.op, &args, roc_ops, null);
|
||||
|
||||
// Decref arguments based on ownership semantics
|
||||
const arg_ownership = low_level.op.getArgOwnership();
|
||||
for (args, 0..) |arg, arg_idx| {
|
||||
const ownership = if (arg_idx < arg_ownership.len) arg_ownership[arg_idx] else .borrow;
|
||||
if (ownership == .borrow) {
|
||||
arg.decref(&self.runtime_layout_store, roc_ops);
|
||||
}
|
||||
}
|
||||
// Note: We do NOT decref arguments here for borrow semantics.
|
||||
// The defer statements at the top of binop_apply already handle decrefing
|
||||
// lhs and rhs. Decrefing here too would cause a double-free bug.
|
||||
// For consume semantics, the low-level builtin takes ownership, so we
|
||||
// also don't decref - the builtin is responsible for the memory.
|
||||
|
||||
// Decref the method closure (for low-level, we handle it here)
|
||||
method_func.decref(&self.runtime_layout_store, roc_ops);
|
||||
|
|
|
|||
18
test/fx/stdin_while_uaf.roc
Normal file
18
test/fx/stdin_while_uaf.roc
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
app [main!] { pf: platform "./platform/main.roc" }
|
||||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
|
||||
main! = || {
|
||||
# Read lines until empty string
|
||||
var $count = 0
|
||||
var $continue = True
|
||||
while $continue {
|
||||
line = Stdin.line!()
|
||||
Stdout.line!(line)
|
||||
$count = $count + 1
|
||||
if line == "" {
|
||||
$continue = False
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue