Skip to content

static mut translation adds UB, but could be safe #782

@Dante-Broggi

Description

@Dante-Broggi

Thread locals are currently translated as static mut which is unsafe, but more importantly are accessed by &mut which adds UB compared to C.

As a minimal example this:

static __thread int x = 0;
void bar(int *y) {
    int *z = &x;
    *z = *y;
}
void foo() { bar(&x); }

Currently translates on the website (https://c2rust.com) as:

#[thread_local]
static mut x: libc::c_int = 0 as libc::c_int;
#[no_mangle]
pub unsafe extern "C" fn bar(mut y: *mut libc::c_int) {
    let mut z: *mut libc::c_int = &mut x;
    *z = *y;
}
#[no_mangle]
pub unsafe extern "C" fn foo() {
    bar(&mut x);
}

Which creates 2 &mut x references and uses the first after the construction of the second, leading to UB absent in the original C code.
But it could use translate as:

use core::cell::Cell;
#[thread_local]
static x: Cell<libc::c_int> = Cell::new(0 as libc::c_int);
#[no_mangle]
pub unsafe extern "C" fn bar(mut y: *mut libc::c_int) {
    let mut z: *mut libc::c_int = x.as_ptr();
    *z = *y;
}
#[no_mangle]
pub unsafe extern "C" fn foo() {
    bar(x.as_ptr());
}

This translation would prevent the UB from creating multiple &mut to the same static, and moreover makes the definition of x itself completely safe. It would even work with pointer typed static __thread variables because unlike normal statics, #[thread_local] static does not need to be Sync.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions