Skip to content

Commit 8fc93ee

Browse files
authored
[unsafe] Wrap initialization of global variables in unsafe (#106)
The initializer of a global variable might use another global variable. We translate global variables as `static mut`. All usages of `static mut` are unsafe, hence the initializer of a global variable must also be wrapped in `unsafe`.
1 parent e98510e commit 8fc93ee

21 files changed

Lines changed: 257 additions & 157 deletions

cpp2rust/converter/converter.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,25 +437,40 @@ bool Converter::ConvertLambdaVarDecl(clang::VarDecl *decl) {
437437
return false;
438438
}
439439

440+
void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) {
441+
if (decl->hasInit()) {
442+
ConvertVarInit(decl->getType(), decl->getInit());
443+
} else if (!clang::isa<clang::ParmVarDecl>(decl)) {
444+
StrCat(ConvertVarDefaultInit(decl->getType()));
445+
}
446+
}
447+
440448
void Converter::ConvertVarDecl(clang::VarDecl *decl) {
441449
if (!ConvertVarDeclSkipInit(decl)) {
442450
// Skip global variables declared extern
443451
return;
444452
}
445-
auto qual_type = decl->getType();
446453
PushConstInitializer static_init(*this, decl->isFileVarDecl() ||
447454
decl->isStaticLocal());
448-
if (decl->hasInit()) {
449-
StrCat(token::kAssign);
450-
ConvertVarInit(qual_type, decl->getInit());
451-
} else if (!clang::isa<clang::ParmVarDecl>(decl)) {
452-
StrCat(token::kAssign, ConvertVarDefaultInit(qual_type));
453-
}
455+
StrCat(token::kAssign);
456+
ConvertVarDeclInitializer(decl);
454457
StrCat(token::kSemiColon);
455458
}
456459

457460
void Converter::ConvertGlobalVarDecl(clang::VarDecl *decl) {
458-
ConvertVarDecl(decl);
461+
if (!ConvertVarDeclSkipInit(decl)) {
462+
// Skip global variables declared extern
463+
return;
464+
}
465+
PushConstInitializer static_init(*this, decl->isFileVarDecl() ||
466+
decl->isStaticLocal());
467+
StrCat(token::kAssign);
468+
StrCat(keyword_unsafe_);
469+
{
470+
PushBrace push(*this);
471+
ConvertVarDeclInitializer(decl);
472+
}
473+
StrCat(token::kSemiColon);
459474
}
460475

461476
bool Converter::VisitVarDecl(clang::VarDecl *decl) {

cpp2rust/converter/converter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
8888

8989
void ConvertVarDecl(clang::VarDecl *decl);
9090

91+
void ConvertVarDeclInitializer(clang::VarDecl *decl);
92+
9193
virtual void ConvertGlobalVarDecl(clang::VarDecl *decl);
9294

9395
virtual void ConvertVaListVarDecl(clang::VarDecl *decl);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
3+
int first;
4+
int second = first + 1;
5+
6+
int main() {
7+
assert(first == 0);
8+
assert(second == first + 1);
9+
return 0;
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
thread_local!(
10+
pub static first: Value<i32> = <Value<i32>>::default();
11+
);
12+
thread_local!(
13+
pub static second: Value<i32> =
14+
Rc::new(RefCell::new(((*first.with(Value::clone).borrow()) + 1)));
15+
);
16+
pub fn main() {
17+
std::process::exit(main_0());
18+
}
19+
fn main_0() -> i32 {
20+
assert!(((*first.with(Value::clone).borrow()) == 0));
21+
assert!(((*second.with(Value::clone).borrow()) == ((*first.with(Value::clone).borrow()) + 1)));
22+
return 0;
23+
}

tests/unit/out/unsafe/addr_of_global.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,19 @@ pub struct Inner {
1616
pub struct Outer {
1717
pub p: *mut Inner,
1818
}
19-
pub static mut alpha: Inner = Inner { value: 1 };
20-
pub static mut beta: Inner = Inner { value: 2 };
21-
pub static mut shared: Inner = Inner { value: 42 };
22-
pub static mut items: [*mut Inner; 2] = [
23-
(&raw mut alpha as *mut Inner),
24-
(&raw mut beta as *mut Inner),
25-
];
26-
pub static mut obj: Outer = Outer {
27-
p: (&raw mut shared as *mut Inner),
19+
pub static mut alpha: Inner = unsafe { Inner { value: 1 } };
20+
pub static mut beta: Inner = unsafe { Inner { value: 2 } };
21+
pub static mut shared: Inner = unsafe { Inner { value: 42 } };
22+
pub static mut items: [*mut Inner; 2] = unsafe {
23+
[
24+
(&raw mut alpha as *mut Inner),
25+
(&raw mut beta as *mut Inner),
26+
]
27+
};
28+
pub static mut obj: Outer = unsafe {
29+
Outer {
30+
p: (&raw mut shared as *mut Inner),
31+
}
2832
};
2933
pub fn main() {
3034
unsafe {
@@ -35,10 +39,12 @@ unsafe fn main_0() -> i32 {
3539
assert!((((*items[(0) as usize]).value) == (1)));
3640
assert!((((*items[(1) as usize]).value) == (2)));
3741
assert!((((*obj.p).value) == (42)));
38-
static mut cache: [*mut Inner; 2] = [
39-
(&raw mut alpha as *mut Inner),
40-
(&raw mut beta as *mut Inner),
41-
];;
42+
static mut cache: [*mut Inner; 2] = unsafe {
43+
[
44+
(&raw mut alpha as *mut Inner),
45+
(&raw mut beta as *mut Inner),
46+
]
47+
};;
4248
assert!((((*cache[(0) as usize]).value) == (1)));
4349
assert!((((*cache[(1) as usize]).value) == (2)));
4450
return 0;

tests/unit/out/unsafe/bool_condition_logical.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl From<i32> for Code {
2323
}
2424
}
2525
}
26-
pub static mut side_effect: i32 = 0;
26+
pub static mut side_effect: i32 = unsafe { 0 };
2727
pub unsafe fn observe_0(mut v: i32) -> i32 {
2828
side_effect.prefix_inc();
2929
return v;

tests/unit/out/unsafe/bool_condition_logical_c.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl From<i32> for Code {
2323
}
2424
}
2525
}
26-
pub static mut side_effect: i32 = 0;
26+
pub static mut side_effect: i32 = unsafe { 0 };
2727
pub unsafe fn observe_0(mut v: i32) -> i32 {
2828
side_effect.prefix_inc();
2929
return v;

tests/unit/out/unsafe/default_in_statics.rs

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -58,49 +58,9 @@ impl Default for Foo {
5858
}
5959
}
6060
}
61-
pub static mut static_fn: Option<unsafe fn(i32) -> i32> = None;
62-
pub static mut static_outer: Outer = Outer {
63-
p1: std::ptr::null_mut(),
64-
p2: std::ptr::null(),
65-
arr: [std::ptr::null_mut(); 3],
66-
cp: std::ptr::null(),
67-
pp: std::ptr::null_mut(),
68-
inner: Inner {
69-
v: 0_i32,
70-
name: std::ptr::null(),
71-
},
72-
x: 0_i32,
73-
fn_: None,
74-
};
75-
pub static mut static_inner_array: [Inner; 2] = [Inner {
76-
v: 0_i32,
77-
name: std::ptr::null(),
78-
}; 2];
79-
pub static mut static_foo: Foo = Foo {
80-
s1: b"hello\0".as_ptr(),
81-
s2: std::ptr::null(),
82-
fn1: None,
83-
fn2: None,
84-
n: 42,
85-
};
86-
pub static mut static_foo_array: [Foo; 2] = [
87-
Foo {
88-
s1: b"first\0".as_ptr(),
89-
s2: std::ptr::null(),
90-
fn1: None,
91-
fn2: None,
92-
n: 1,
93-
},
94-
Foo {
95-
s1: b"second\0".as_ptr(),
96-
s2: std::ptr::null(),
97-
fn1: None,
98-
fn2: None,
99-
n: 2,
100-
},
101-
];
102-
pub unsafe fn check_local_static_0() {
103-
static mut local_outer: Outer = Outer {
61+
pub static mut static_fn: Option<unsafe fn(i32) -> i32> = unsafe { None };
62+
pub static mut static_outer: Outer = unsafe {
63+
Outer {
10464
p1: std::ptr::null_mut(),
10565
p2: std::ptr::null(),
10666
arr: [std::ptr::null_mut(); 3],
@@ -112,9 +72,59 @@ pub unsafe fn check_local_static_0() {
11272
},
11373
x: 0_i32,
11474
fn_: None,
75+
}
76+
};
77+
pub static mut static_inner_array: [Inner; 2] = unsafe {
78+
[Inner {
79+
v: 0_i32,
80+
name: std::ptr::null(),
81+
}; 2]
82+
};
83+
pub static mut static_foo: Foo = unsafe {
84+
Foo {
85+
s1: b"hello\0".as_ptr(),
86+
s2: std::ptr::null(),
87+
fn1: None,
88+
fn2: None,
89+
n: 42,
90+
}
91+
};
92+
pub static mut static_foo_array: [Foo; 2] = unsafe {
93+
[
94+
Foo {
95+
s1: b"first\0".as_ptr(),
96+
s2: std::ptr::null(),
97+
fn1: None,
98+
fn2: None,
99+
n: 1,
100+
},
101+
Foo {
102+
s1: b"second\0".as_ptr(),
103+
s2: std::ptr::null(),
104+
fn1: None,
105+
fn2: None,
106+
n: 2,
107+
},
108+
]
109+
};
110+
pub unsafe fn check_local_static_0() {
111+
static mut local_outer: Outer = unsafe {
112+
Outer {
113+
p1: std::ptr::null_mut(),
114+
p2: std::ptr::null(),
115+
arr: [std::ptr::null_mut(); 3],
116+
cp: std::ptr::null(),
117+
pp: std::ptr::null_mut(),
118+
inner: Inner {
119+
v: 0_i32,
120+
name: std::ptr::null(),
121+
},
122+
x: 0_i32,
123+
fn_: None,
124+
}
115125
};;
116-
static mut local_fn: Option<unsafe fn(i32) -> i32> = None;;
117-
static mut local_p: *mut i32 = std::ptr::null_mut();;
126+
static mut local_fn: Option<unsafe fn(i32) -> i32> = unsafe { None };;
127+
static mut local_p: *mut i32 = unsafe { std::ptr::null_mut() };;
118128
assert!((local_outer.p1).is_null());
119129
assert!((local_outer.fn_).is_none());
120130
assert!((local_fn).is_none());

tests/unit/out/unsafe/enum_int_interop.rs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,26 +66,28 @@ pub struct Entry {
6666
pub color: Color,
6767
pub opt: Option,
6868
}
69-
pub static mut global_color: Color = Color::GREEN;
70-
pub static mut global_opt: Option = Option::OPT_B;
71-
pub static mut global_tag: Tag = Tag::TAG_TWO;
72-
pub static mut entries: [Entry; 3] = [
73-
Entry {
74-
name: b"first\0".as_ptr(),
75-
color: Color::RED,
76-
opt: Option::OPT_NONE,
77-
},
78-
Entry {
79-
name: b"second\0".as_ptr(),
80-
color: Color::GREEN,
81-
opt: Option::OPT_A,
82-
},
83-
Entry {
84-
name: b"third\0".as_ptr(),
85-
color: Color::BLUE,
86-
opt: Option::OPT_C,
87-
},
88-
];
69+
pub static mut global_color: Color = unsafe { Color::GREEN };
70+
pub static mut global_opt: Option = unsafe { Option::OPT_B };
71+
pub static mut global_tag: Tag = unsafe { Tag::TAG_TWO };
72+
pub static mut entries: [Entry; 3] = unsafe {
73+
[
74+
Entry {
75+
name: b"first\0".as_ptr(),
76+
color: Color::RED,
77+
opt: Option::OPT_NONE,
78+
},
79+
Entry {
80+
name: b"second\0".as_ptr(),
81+
color: Color::GREEN,
82+
opt: Option::OPT_A,
83+
},
84+
Entry {
85+
name: b"third\0".as_ptr(),
86+
color: Color::BLUE,
87+
opt: Option::OPT_C,
88+
},
89+
]
90+
};
8991
pub unsafe fn as_int_0(mut c: Color) -> i32 {
9092
return (c as i32);
9193
}

tests/unit/out/unsafe/enum_int_interop_c.rs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,26 +66,28 @@ pub struct Entry {
6666
pub color: Color,
6767
pub opt: Option,
6868
}
69-
pub static mut global_color: Color = Color::GREEN;
70-
pub static mut global_opt: Option = Option::OPT_B;
71-
pub static mut global_tag: Tag = Tag::TAG_TWO;
72-
pub static mut entries: [Entry; 3] = [
73-
Entry {
74-
name: b"first\0".as_ptr().cast_mut().cast_const(),
75-
color: Color::RED,
76-
opt: Option::OPT_NONE,
77-
},
78-
Entry {
79-
name: b"second\0".as_ptr().cast_mut().cast_const(),
80-
color: Color::GREEN,
81-
opt: Option::OPT_A,
82-
},
83-
Entry {
84-
name: b"third\0".as_ptr().cast_mut().cast_const(),
85-
color: Color::BLUE,
86-
opt: Option::OPT_C,
87-
},
88-
];
69+
pub static mut global_color: Color = unsafe { Color::GREEN };
70+
pub static mut global_opt: Option = unsafe { Option::OPT_B };
71+
pub static mut global_tag: Tag = unsafe { Tag::TAG_TWO };
72+
pub static mut entries: [Entry; 3] = unsafe {
73+
[
74+
Entry {
75+
name: b"first\0".as_ptr().cast_mut().cast_const(),
76+
color: Color::RED,
77+
opt: Option::OPT_NONE,
78+
},
79+
Entry {
80+
name: b"second\0".as_ptr().cast_mut().cast_const(),
81+
color: Color::GREEN,
82+
opt: Option::OPT_A,
83+
},
84+
Entry {
85+
name: b"third\0".as_ptr().cast_mut().cast_const(),
86+
color: Color::BLUE,
87+
opt: Option::OPT_C,
88+
},
89+
]
90+
};
8991
pub unsafe fn as_int_0(mut c: Color) -> i32 {
9092
return (c as i32);
9193
}

0 commit comments

Comments
 (0)