Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect translation of post-modification of bitfield #758

Open
hvdijk opened this issue Dec 10, 2022 · 0 comments
Open

Incorrect translation of post-modification of bitfield #758

hvdijk opened this issue Dec 10, 2022 · 0 comments
Labels
bug Something isn't working

Comments

@hvdijk
Copy link

hvdijk commented Dec 10, 2022

Tested using c2rust 0.16.0

struct S {
  int i : 4;
} s;

int main(void) {
  int x = s.i++;
  int y = --s.i;
  return x + y;
}

This program returns zero. It is translated to a Rust program that returns -1.

The generated Rust code is

#![allow(dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, non_upper_case_globals, unused_assignments, unused_mut)]
#![register_tool(c2rust)]
#![feature(register_tool)]
#[macro_use]
extern crate c2rust_bitfields;
use ::c2rust_out::*;
#[derive(Copy, Clone, BitfieldStruct)]
#[repr(C)]
pub struct S {
    #[bitfield(name = "i", ty = "libc::c_int", bits = "0..=3")]
    pub i: [u8; 1],
    #[bitfield(padding)]
    pub c2rust_padding: [u8; 3],
}
#[no_mangle]
pub static mut s: S = S {
    i: [0; 1],
    c2rust_padding: [0; 3],
};
unsafe fn main_0() -> libc::c_int {
    let ref mut fresh0 = s.i();
    let fresh1 = *fresh0;
    *fresh0 = *fresh0 + 1;
    let mut x: libc::c_int = fresh1;
    s.set_i(s.i() - 1);
    let mut y: libc::c_int = s.i();
    return x + y;
}
pub fn main() {
    unsafe { ::std::process::exit(main_0() as i32) }
}

Note here the *fresh0 = *fresh0 + 1;. This does not have the desired effect of modifying s.i. Instead, it modifies the temporary returned by s.i(), a temporary which is never again used after being assigned to.

The pre-decrement, on the other hand, is correctly translated into a call to s.set_i.

One possible corrected translation would be

unsafe fn main_0() -> libc::c_int {
    let fresh0 = s.i();
    s.set_i(fresh0 + 1);
    let mut x: libc::c_int = fresh0;
    s.set_i(s.i() - 1);
    let mut y: libc::c_int = s.i();
    return x + y;
}
@kkysen kkysen added the bug Something isn't working label Dec 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants