Skip to content

Commit 3a3272a

Browse files
authored
Always translate global objects as static mut (#67)
This is a continuation of #65: > This is incomplete, it only solves part of the problem. > > In Rust, `static` global variables require `Sync` so that multiple threads can take an immutable reference to the `static` storage, `static mut` global variables don't require `Sync` because it's by itself unsafe to access the `static mut` storage. > > This PR solved the problem for `static` global struct objects that contained raw pointers. Raw pointers are not `Sync` in Rust so any struct containing them needs to implement the `Sync` trait. What this PR does not solve is global arrays containing pointers in `static` storage, for example `[*const T; N]`. > > One solution would be to translate the const global variables as `const` instead of `static`. However `const` global variables don't have a stable address in the final binary. Other solution would be to wrap the array in a newtype, but this makes later usages of the array harder in the codegen. > > None of the two above solution is complete. For the moment we can translate all global variables as `static mut` instead of `static` so that we don't have to implement `Sync` for them. By construction, the generated code is guaranteed not to modify the global variable, even if it's declared as `static mut` instead of `static`. > > This only touches the unsafe model.
1 parent a8625eb commit 3a3272a

6 files changed

Lines changed: 144 additions & 10 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -385,16 +385,11 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) {
385385
!globals_.insert(name).second) {
386386
return false;
387387
}
388-
StrCat(AccessSpecifierAsString(decl->getAccess()), keyword::kStatic);
389-
if (!qual_type.isConstQualified()) {
390-
StrCat(keyword_mut_);
391-
}
388+
StrCat(AccessSpecifierAsString(decl->getAccess()), keyword::kStatic,
389+
keyword_mut_);
392390
ENSURE(decl_ids_.insert(GetID(decl)).second);
393391
} else if (decl->isStaticLocal()) {
394-
StrCat(keyword::kStatic);
395-
if (!qual_type.isConstQualified()) {
396-
StrCat(keyword_mut_);
397-
}
392+
StrCat(keyword::kStatic, keyword_mut_);
398393
} else if (decl->isLocalVarDecl()) {
399394
StrCat(keyword::kLet);
400395
}

tests/unit/global_pointers.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <cassert>
2+
#include <cstddef>
3+
4+
struct Entry {
5+
const char *name;
6+
int *p;
7+
};
8+
9+
static const Entry single_entry = {"alone", nullptr};
10+
11+
static const Entry entries[2] = {
12+
{"first", nullptr},
13+
{"second", nullptr},
14+
};
15+
16+
char *arr_of_pointers[3] = {};
17+
18+
int main() {
19+
assert(single_entry.p == nullptr);
20+
for (int i = 0; i < 2; ++i) {
21+
assert(entries[i].p == nullptr);
22+
assert(arr_of_pointers[i] == nullptr);
23+
}
24+
return 0;
25+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
#[derive(Default)]
10+
pub struct Entry {
11+
pub name: Value<Ptr<u8>>,
12+
pub p: Value<Ptr<i32>>,
13+
}
14+
impl Clone for Entry {
15+
fn clone(&self) -> Self {
16+
let mut this = Self {
17+
name: Rc::new(RefCell::new((*self.name.borrow()).clone())),
18+
p: Rc::new(RefCell::new((*self.p.borrow()).clone())),
19+
};
20+
this
21+
}
22+
}
23+
impl ByteRepr for Entry {}
24+
thread_local!(
25+
pub static single_entry: Value<Entry> = Rc::new(RefCell::new(Entry {
26+
name: Rc::new(RefCell::new(Ptr::from_string_literal("alone"))),
27+
p: Rc::new(RefCell::new(Default::default())),
28+
}));
29+
);
30+
thread_local!(
31+
pub static entries: Value<Box<[Entry]>> = Rc::new(RefCell::new(Box::new([
32+
Entry {
33+
name: Rc::new(RefCell::new(Ptr::from_string_literal("first"))),
34+
p: Rc::new(RefCell::new(Default::default())),
35+
},
36+
Entry {
37+
name: Rc::new(RefCell::new(Ptr::from_string_literal("second"))),
38+
p: Rc::new(RefCell::new(Default::default())),
39+
},
40+
])));
41+
);
42+
thread_local!(
43+
pub static arr_of_pointers: Value<Box<[Ptr<u8>]>> = Rc::new(RefCell::new(Box::new([
44+
Ptr::<u8>::null(),
45+
Ptr::<u8>::null(),
46+
Ptr::<u8>::null(),
47+
])));
48+
);
49+
pub fn main() {
50+
std::process::exit(main_0());
51+
}
52+
fn main_0() -> i32 {
53+
assert!((*(*single_entry.with(Value::clone).borrow()).p.borrow()).is_null());
54+
let i: Value<i32> = Rc::new(RefCell::new(0));
55+
'loop_: while ((*i.borrow()) < 2) {
56+
assert!(
57+
(*(*entries.with(Value::clone).borrow())[(*i.borrow()) as usize]
58+
.p
59+
.borrow())
60+
.is_null()
61+
);
62+
assert!(((*arr_of_pointers.with(Value::clone).borrow())[(*i.borrow()) as usize]).is_null());
63+
(*i.borrow_mut()).prefix_inc();
64+
}
65+
return 0;
66+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
extern crate libc;
2+
use libc::*;
3+
extern crate libcc2rs;
4+
use libcc2rs::*;
5+
use std::collections::BTreeMap;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
8+
use std::rc::Rc;
9+
#[repr(C)]
10+
#[derive(Copy, Clone, Default)]
11+
pub struct Entry {
12+
pub name: *const u8,
13+
pub p: *mut i32,
14+
}
15+
pub static mut single_entry: Entry = Entry {
16+
name: b"alone\0".as_ptr(),
17+
p: std::ptr::null_mut(),
18+
};
19+
pub static mut entries: [Entry; 2] = [
20+
Entry {
21+
name: b"first\0".as_ptr(),
22+
p: std::ptr::null_mut(),
23+
},
24+
Entry {
25+
name: b"second\0".as_ptr(),
26+
p: std::ptr::null_mut(),
27+
},
28+
];
29+
pub static mut arr_of_pointers: [*mut u8; 3] = [
30+
std::ptr::null_mut(),
31+
std::ptr::null_mut(),
32+
std::ptr::null_mut(),
33+
];
34+
pub fn main() {
35+
unsafe {
36+
std::process::exit(main_0() as i32);
37+
}
38+
}
39+
unsafe fn main_0() -> i32 {
40+
assert!((single_entry.p).is_null());
41+
let mut i: i32 = 0;
42+
'loop_: while ((i) < (2)) {
43+
assert!((entries[(i) as usize].p).is_null());
44+
assert!((arr_of_pointers[(i) as usize]).is_null());
45+
i.prefix_inc();
46+
}
47+
return 0;
48+
}

tests/unit/out/unsafe/static_local.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ pub unsafe fn foo_0() -> i32 {
1111
static mut static_f: f32 = 0.0_f32;;
1212
static mut static_b: bool = false;;
1313
static mut kX1: i32 = 1;;
14-
static kX2: i32 = 2;;
14+
static mut kX2: i32 = 2;;
1515
kX1 += 1;
1616
return (((kX1) + (kX2)) + (static_i));
1717
}

tests/unit/out/unsafe/string_escape.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn main() {
1414
unsafe fn main_0() -> i32 {
1515
let mut special: *const u8 =
1616
b"\x07\x08\t\n\x0b\x0c\r !\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~\0".as_ptr();
17-
static expected: [u8; 40] = [
17+
static mut expected: [u8; 40] = [
1818
7_u8, 8_u8, 9_u8, 10_u8, 11_u8, 12_u8, 13_u8, 32_u8, 33_u8, 34_u8, 35_u8, 36_u8, 37_u8,
1919
38_u8, 39_u8, 40_u8, 41_u8, 42_u8, 43_u8, 44_u8, 45_u8, 46_u8, 47_u8, 58_u8, 59_u8, 60_u8,
2020
61_u8, 62_u8, 63_u8, 64_u8, 91_u8, 92_u8, 93_u8, 94_u8, 95_u8, 96_u8, 123_u8, 124_u8,

0 commit comments

Comments
 (0)