immunant / c2rust

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

analyze: missing `&p[0]` rewrite when dropping `OFFSET` permission #906

Open spernsteiner opened 1 year ago

spernsteiner commented 1 year ago

This test currently fails:

pub struct S {
    x: i32,
}

// CHECK-LABEL: fn offset_field_with_temp
pub unsafe extern "C" fn offset_field_with_temp(mut p: *const S) -> i32 {
    // CHECK: p = &(p)[((1) as usize) ..];
    p = p.offset(1);
    // CHECK: let q = &(p)[0];
    let q = p;
    // CHECK: (*q).x
    (*q).x
}

// CHECK-LABEL: fn offset_field_direct
pub unsafe extern "C" fn offset_field_direct(mut p: *const S) -> i32 {
    // CHECK: p = &(p)[((1) as usize) ..];
    p = p.offset(1);
    // CHECK: (*(&(p)[0])).x
    (*p).x
}

Both functions should perform an operation like &p[0] at some point to convert from &[S] (the rewritten type of p) to &S.

The MIR for offset_field_with_temp looks like this:

_1 = move _2;           // Store the result of p.offset(1) back into p (_1)
_4 = _1;                // Copy p into q
_0 = ((*_4).0: i32);    // (*q).x
return;

The type assignment for this function looks correct:

type assignment for "offset_field_with_temp":
_0 (6: i32): i32
_1 (6: mut p): &[S]
_2 (8: p.offset(1)): &[S]
_3 (8: p): &[S]
_4 (10: q): &S

However, it looks like mir_op::ExprRewriteVisitor::emit_cast is failing to generate the proper MIR rewrite somewhere, probably on the _4 = _1 line:

unsupported cast kind: READ | OFFSET_ADD | OFFSET_SUB (Imm, OffsetPtr) -> (Imm, Single)

This is a significant source of compilation errors in lighttpd (18 errors like this one).