- copy_place_text matched only bare Ident/Field/Index, so a Text-typed
single-segment interpolation ("${r.method}", r a loop borrow) passed
the place's own register through a binding/assignment boundary — the
local aliased the row's field and its overwrite freed it
- release-build crash; invisible to ASan (in-arena free, no redzones)
- now asks is_borrowed_value_t && not is_container_read — exactly
drop_fresh_text's place test; Int segments (fresh int_to_text) and
container reads (already copies) stay uncopied as before
- pinned by tests/corpus/run/interp-borrowed-field (crashed both
runtimes before the fix, 50 iterations now exact)
- gates: woc-test 540/0, oop-e2e 89/0 (ASan stage included)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
33 lines
738 B
Text
33 lines
738 B
Text
-- probe: Text interpolation of a borrowed field inside a loop.
|
|
-- If the interpolation segment drops the field it only borrows, repeated
|
|
-- calls corrupt the arena and the third-ish call crashes in release.
|
|
|
|
class Row {
|
|
method: Text
|
|
}
|
|
|
|
class Tab {
|
|
rows: multi Row
|
|
|
|
fn scan() -> Text {
|
|
let out = "";
|
|
for r in self.rows {
|
|
if out == "" { out = "${r.method}"; } else { out = "${out}, ${r.method}"; }
|
|
}
|
|
return out;
|
|
}
|
|
}
|
|
|
|
fn main() -> Int {
|
|
let t = Tab { rows: [] };
|
|
push(t.rows, Row { method: "GET" });
|
|
push(t.rows, Row { method: "POST" });
|
|
let i = 0;
|
|
while i < 50 {
|
|
let s = t.scan();
|
|
if s != "GET, POST" { print("bad: ${s} at ${i}"); return 1; }
|
|
i = i + 1;
|
|
}
|
|
print("ok");
|
|
return 0;
|
|
}
|