immunant / c2rust

Migrate C code to Rust
https://c2rust.com/
Other
3.81k stars 220 forks source link

analyze: "unlower_map has no origin" on `(*x).f += y` #985

Open spernsteiner opened 1 year ago

spernsteiner commented 1 year ago

Example:

struct S {
    x: i32,
}

unsafe fn plus_eq_1(s: *mut S) {
    let p = s;
    let q = s;
    (*p).x += 1;
    (*q).x += 1;
}

Relevant MIR:

    bb1[0]: ((*_2).0: i32) = move (_4.0: i32)
    bb1[1]: _5 = CheckedAdd(((*_3).0: i32), const 1_i32)
    bb1[2]: Terminator { source_info: SourceInfo { span: c2rust-analyze/tests/filecheck/unlower_plus_eq.rs:10:5: 10:16 (#0), scope: scope[2] }, kind: assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", ((*_3).0: i32), const 1_i32) -> [success: bb2, unwind: bb3] }
  block bb2:
    bb2[0]: ((*_3).0: i32) = move (_5.0: i32)

The aliased writes to *s causes s to gain the CELL flag, so the assignment at bb2[0] must be rewritten. But it has no unlowering info because we currently don't handle ExprKind::AssignOp in UnlowerVisitor::visit_expr_inner.

This seems tricky to deal with and may need special handling. *p.x appears only once in the input but must appear twice in the output (once in the receiver of Cell::get and again for Cell::set). We also don't yet support CELL rewrites when only a single field is modified, as in this case (maybe we should produce a better panic message for that).