fix(compiler): return of a Text interp of a place handed out the borrow
- emit_return's place test matched only bare Ident/Field/Index, so
`return "${p.content}"` (p a loop borrow) returned the part's own
string; the caller's eventual drop freed it under the container —
arena corruption surfacing two requests later (multipart slice)
- the return test now sees through Interp exactly as copy_place_text
does (is_borrowed_value_t, container reads excluded); bare
Ident/Field/Index behavior at return unchanged
- interp-borrowed-field fixture grows the return flavor (fn first),
50 iterations exact
- gates: oop-e2e 89/0 (ASan stage), woc-test green
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b5d862dcc5
commit
1995de5c28
3 changed files with 27 additions and 3 deletions
|
|
@ -140,8 +140,12 @@ so a Text-typed SINGLE-SEGMENT interpolation of a place
|
|||
register through a `let`/assignment boundary uncopied — the binding aliased
|
||||
the row's field and its overwrite freed it (release-build crash the arena
|
||||
hid from ASan). It now asks `is_borrowed_value_t && not is_container_read`,
|
||||
exactly `drop_fresh_text`'s place test. Pinned by
|
||||
`tests/corpus/run/interp-borrowed-field`.
|
||||
exactly `drop_fresh_text`'s place test. The RETURN boundary had the same
|
||||
hole (`return "${p.content}"` handed the caller the part's own string —
|
||||
the multipart slice's arena corruption, two requests removed from the
|
||||
crash): emit_return's place test now sees through `Interp` the same way,
|
||||
while bare Ident/Field/Index behavior there is unchanged. Both flavors
|
||||
pinned by `tests/corpus/run/interp-borrowed-field`.
|
||||
|
||||
Two rules the measurements imposed, both easy to get backwards:
|
||||
|
||||
|
|
|
|||
|
|
@ -3756,7 +3756,16 @@ and emit_return (p : pctx) (f : fstate) (v : views) (s : Ast.stmt) (opt : Ast.ex
|
|||
`return lv` inside `for lv in [...]` is WO-E304 and the workload's own
|
||||
level classifier cannot be written at all. *)
|
||||
let t =
|
||||
let is_place = match e.Ast.kind with Ast.Ident _ | Ast.Field _ | Ast.Index _ -> true | _ -> false in
|
||||
(* an interpolation is seen through exactly as copy_place_text sees
|
||||
it: `return "${p.content}"` (p a loop borrow) handed the caller the
|
||||
part's own string — the caller's drop then freed it under the
|
||||
container, the multipart-400 arena corruption *)
|
||||
let is_place =
|
||||
match e.Ast.kind with
|
||||
| Ast.Ident _ | Ast.Field _ | Ast.Index _ -> true
|
||||
| Ast.Interp _ -> is_borrowed_value_t p f e && not (is_container_read e)
|
||||
| _ -> false
|
||||
in
|
||||
let is_text = match ty_of_expr p f e with Some ty -> field_kind p ty = 3 | None -> false in
|
||||
if is_place && is_text then begin
|
||||
let w = alloc_temps p f e.pos 1 in
|
||||
|
|
|
|||
|
|
@ -16,6 +16,15 @@ class Tab {
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
-- the RETURN flavor: an interpolation of a borrowed field handed straight
|
||||
-- to the caller must be the caller's own copy, not the row's string
|
||||
fn first() -> Text {
|
||||
for r in self.rows {
|
||||
return "${r.method}";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Int {
|
||||
|
|
@ -26,6 +35,8 @@ fn main() -> Int {
|
|||
while i < 50 {
|
||||
let s = t.scan();
|
||||
if s != "GET, POST" { print("bad: ${s} at ${i}"); return 1; }
|
||||
let h = t.first();
|
||||
if h != "GET" { print("bad first: ${h} at ${i}"); return 1; }
|
||||
i = i + 1;
|
||||
}
|
||||
print("ok");
|
||||
|
|
|
|||
Loading…
Reference in a new issue