Skip to content

Commit a04a2fa

Browse files
Deny unsafe ops in unsafe fns in std::sys_common
1 parent b4bdc07 commit a04a2fa

12 files changed

+151
-82
lines changed

library/std/src/sys_common/alloc.rs

+16-5
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,25 @@ pub unsafe fn realloc_fallback(
3333
old_layout: Layout,
3434
new_size: usize,
3535
) -> *mut u8 {
36-
// Docs for GlobalAlloc::realloc require this to be valid:
37-
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
36+
// SAFETY: as stated in docs for GlobalAlloc::realloc, the caller
37+
// must guarantee that `new_size` is valid for a `Layout`.
38+
// The `old_layout.align()` is guaranteed to be valid as it comes
39+
// from a `Layout`.
40+
let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, old_layout.align()) };
3841

39-
let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
42+
// SAFETY: as stated in docs for GlobalAlloc::realloc, the caller
43+
// must guarantee that `new_size` is greater than zero.
44+
let new_ptr = unsafe { GlobalAlloc::alloc(alloc, new_layout) };
4045
if !new_ptr.is_null() {
4146
let size = cmp::min(old_layout.size(), new_size);
42-
ptr::copy_nonoverlapping(ptr, new_ptr, size);
43-
GlobalAlloc::dealloc(alloc, ptr, old_layout);
47+
// SAFETY: the newly allocated memory cannot overlap the previously
48+
// allocated memory. Also, the call to `dealloc` is safe since
49+
// the caller must guarantee that `ptr` is allocated via this allocator
50+
// and layout is the same layout that was used to allocate `ptr`.
51+
unsafe {
52+
ptr::copy_nonoverlapping(ptr, new_ptr, size);
53+
GlobalAlloc::dealloc(alloc, ptr, old_layout);
54+
}
4455
}
4556
new_ptr
4657
}

library/std/src/sys_common/at_exit_imp.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ const DONE: *mut Queue = 1_usize as *mut _;
2626
const ITERS: usize = 10;
2727

2828
unsafe fn init() -> bool {
29-
if QUEUE.is_null() {
29+
// SAFETY: the caller must ensure that `QUEUE` is not in use anywhere else,
30+
// which `push` below does by locking `LOCK`.
31+
if unsafe { QUEUE.is_null() } {
3032
let state: Box<Queue> = box Vec::new();
31-
QUEUE = Box::into_raw(state);
32-
} else if QUEUE == DONE {
33+
unsafe {
34+
QUEUE = Box::into_raw(state);
35+
}
36+
} else if unsafe { QUEUE == DONE } {
3337
// can't re-init after a cleanup
3438
return false;
3539
}

library/std/src/sys_common/backtrace.rs

+33-31
Original file line numberDiff line numberDiff line change
@@ -76,44 +76,46 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
7676
let mut res = Ok(());
7777
// Start immediately if we're not using a short backtrace.
7878
let mut start = print_fmt != PrintFmt::Short;
79-
backtrace_rs::trace_unsynchronized(|frame| {
80-
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
81-
return false;
82-
}
79+
unsafe {
80+
backtrace_rs::trace_unsynchronized(|frame| {
81+
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
82+
return false;
83+
}
8384

84-
let mut hit = false;
85-
let mut stop = false;
86-
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
87-
hit = true;
88-
if print_fmt == PrintFmt::Short {
89-
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
90-
if sym.contains("__rust_begin_short_backtrace") {
91-
stop = true;
92-
return;
93-
}
94-
if sym.contains("__rust_end_short_backtrace") {
95-
start = true;
96-
return;
85+
let mut hit = false;
86+
let mut stop = false;
87+
backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
88+
hit = true;
89+
if print_fmt == PrintFmt::Short {
90+
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
91+
if sym.contains("__rust_begin_short_backtrace") {
92+
stop = true;
93+
return;
94+
}
95+
if sym.contains("__rust_end_short_backtrace") {
96+
start = true;
97+
return;
98+
}
9799
}
98100
}
99-
}
100101

101-
if start {
102-
res = bt_fmt.frame().symbol(frame, symbol);
102+
if start {
103+
res = bt_fmt.frame().symbol(frame, symbol);
104+
}
105+
});
106+
if stop {
107+
return false;
103108
}
104-
});
105-
if stop {
106-
return false;
107-
}
108-
if !hit {
109-
if start {
110-
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
109+
if !hit {
110+
if start {
111+
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
112+
}
111113
}
112-
}
113114

114-
idx += 1;
115-
res.is_ok()
116-
});
115+
idx += 1;
116+
res.is_ok()
117+
});
118+
}
117119
res?;
118120
bt_fmt.finish()?;
119121
if print_fmt == PrintFmt::Short {

library/std/src/sys_common/condvar.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,22 @@ impl Condvar {
2525
/// address.
2626
#[inline]
2727
pub unsafe fn init(&mut self) {
28-
self.0.init()
28+
// SAFETY: the caller must uphold the safety contract for `init`.
29+
unsafe { self.0.init() }
2930
}
3031

3132
/// Signals one waiter on this condition variable to wake up.
3233
#[inline]
3334
pub unsafe fn notify_one(&self) {
34-
self.0.notify_one()
35+
// SAFETY: the caller must uphold the safety contract for `notify_one`.
36+
unsafe { self.0.notify_one() }
3537
}
3638

3739
/// Awakens all current waiters on this condition variable.
3840
#[inline]
3941
pub unsafe fn notify_all(&self) {
40-
self.0.notify_all()
42+
// SAFETY: the caller must uphold the safety contract for `notify_all`.
43+
unsafe { self.0.notify_all() }
4144
}
4245

4346
/// Waits for a signal on the specified mutex.
@@ -47,7 +50,8 @@ impl Condvar {
4750
/// on this condition variable.
4851
#[inline]
4952
pub unsafe fn wait(&self, mutex: &Mutex) {
50-
self.0.wait(mutex::raw(mutex))
53+
// SAFETY: the caller must uphold the safety contract for `wait`.
54+
unsafe { self.0.wait(mutex::raw(mutex)) }
5155
}
5256

5357
/// Waits for a signal on the specified mutex with a timeout duration
@@ -58,7 +62,8 @@ impl Condvar {
5862
/// on this condition variable.
5963
#[inline]
6064
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
61-
self.0.wait_timeout(mutex::raw(mutex), dur)
65+
// SAFETY: the caller must uphold the safety contract for `wait_timeout`.
66+
unsafe { self.0.wait_timeout(mutex::raw(mutex), dur) }
6267
}
6368

6469
/// Deallocates all resources associated with this condition variable.
@@ -67,6 +72,7 @@ impl Condvar {
6772
/// this condition variable.
6873
#[inline]
6974
pub unsafe fn destroy(&self) {
70-
self.0.destroy()
75+
// SAFETY: the caller must uphold the safety contract for `destroy`.
76+
unsafe { self.0.destroy() }
7177
}
7278
}

library/std/src/sys_common/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
1515
#![allow(missing_docs)]
1616
#![allow(missing_debug_implementations)]
17+
#![deny(unsafe_op_in_unsafe_fn)]
1718

1819
#[cfg(test)]
1920
mod tests;

library/std/src/sys_common/mutex.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ impl Mutex {
3030
/// `init()`) is undefined behavior.
3131
#[inline]
3232
pub unsafe fn init(&mut self) {
33-
self.0.init()
33+
// SAFETY: the caller must uphold the safety contract for `init`.
34+
unsafe { self.0.init() }
3435
}
3536

3637
/// Locks the mutex blocking the current thread until it is available.
@@ -39,14 +40,18 @@ impl Mutex {
3940
/// previous function call.
4041
#[inline]
4142
pub unsafe fn raw_lock(&self) {
42-
self.0.lock()
43+
// SAFETY: the caller must uphold the safety contract for `lock`.
44+
unsafe { self.0.lock() }
4345
}
4446

4547
/// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
4648
/// will be unlocked.
4749
#[inline]
4850
pub unsafe fn lock(&self) -> MutexGuard<'_> {
49-
self.raw_lock();
51+
// SAFETY: the caller must uphold the safety contract for `raw_lock`.
52+
unsafe {
53+
self.raw_lock();
54+
}
5055
MutexGuard(&self.0)
5156
}
5257

@@ -57,7 +62,8 @@ impl Mutex {
5762
/// previous function call.
5863
#[inline]
5964
pub unsafe fn try_lock(&self) -> bool {
60-
self.0.try_lock()
65+
// SAFETY: the caller must uphold the safety contract for `try_lock`.
66+
unsafe { self.0.try_lock() }
6167
}
6268

6369
/// Unlocks the mutex.
@@ -69,7 +75,8 @@ impl Mutex {
6975
/// lock() whenever possible.
7076
#[inline]
7177
pub unsafe fn raw_unlock(&self) {
72-
self.0.unlock()
78+
// SAFETY: the caller must uphold the safety contract for `unlock`.
79+
unsafe { self.0.unlock() }
7380
}
7481

7582
/// Deallocates all resources associated with this mutex.
@@ -78,7 +85,8 @@ impl Mutex {
7885
/// this mutex.
7986
#[inline]
8087
pub unsafe fn destroy(&self) {
81-
self.0.destroy()
88+
// SAFETY: the caller must uphold the safety contract for `destroy`.
89+
unsafe { self.0.destroy() }
8290
}
8391
}
8492

library/std/src/sys_common/remutex.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ impl<T> ReentrantMutex<T> {
5353
/// once this mutex is in its final resting place, and only then are the
5454
/// lock/unlock methods safe.
5555
pub const unsafe fn new(t: T) -> ReentrantMutex<T> {
56-
ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
56+
// `ReentrantMutex::uninitialized()` is not unsafe on all platforms
57+
#[allow(unused_unsafe)]
58+
// SAFETY: the caller must guarantee that `init` is called.
59+
unsafe {
60+
ReentrantMutex { inner: sys::ReentrantMutex::uninitialized(), data: t }
61+
}
5762
}
5863

5964
/// Initializes this mutex so it's ready for use.
@@ -63,7 +68,8 @@ impl<T> ReentrantMutex<T> {
6368
/// Unsafe to call more than once, and must be called after this will no
6469
/// longer move in memory.
6570
pub unsafe fn init(&self) {
66-
self.inner.init();
71+
// SAFETY: the caller must uphold the safety contract for `init`.
72+
unsafe { self.inner.init() };
6773
}
6874

6975
/// Acquires a mutex, blocking the current thread until it is able to do so.
@@ -79,6 +85,7 @@ impl<T> ReentrantMutex<T> {
7985
/// this call will return failure if the mutex would otherwise be
8086
/// acquired.
8187
pub fn lock(&self) -> ReentrantMutexGuard<'_, T> {
88+
// SAFETY: the caller must uphold the safety contract for `lock`.
8289
unsafe { self.inner.lock() }
8390
ReentrantMutexGuard::new(&self)
8491
}

library/std/src/sys_common/rwlock.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ impl RWLock {
2323
/// previous method call.
2424
#[inline]
2525
pub unsafe fn read(&self) {
26-
self.0.read()
26+
// SAFETY: the caller must uphold the safety contract for `read`.
27+
unsafe { self.0.read() }
2728
}
2829

2930
/// Attempts to acquire shared access to this lock, returning whether it
@@ -35,7 +36,8 @@ impl RWLock {
3536
/// previous method call.
3637
#[inline]
3738
pub unsafe fn try_read(&self) -> bool {
38-
self.0.try_read()
39+
// SAFETY: the caller must uphold the safety contract for `try_read`.
40+
unsafe { self.0.try_read() }
3941
}
4042

4143
/// Acquires write access to the underlying lock, blocking the current thread
@@ -45,7 +47,8 @@ impl RWLock {
4547
/// previous method call.
4648
#[inline]
4749
pub unsafe fn write(&self) {
48-
self.0.write()
50+
// SAFETY: the caller must uphold the safety contract for `write`.
51+
unsafe { self.0.write() }
4952
}
5053

5154
/// Attempts to acquire exclusive access to this lock, returning whether it
@@ -57,15 +60,17 @@ impl RWLock {
5760
/// previous method call.
5861
#[inline]
5962
pub unsafe fn try_write(&self) -> bool {
60-
self.0.try_write()
63+
// SAFETY: the caller must uphold the safety contract for `try_write`.
64+
unsafe { self.0.try_write() }
6165
}
6266

6367
/// Unlocks previously acquired shared access to this lock.
6468
///
6569
/// Behavior is undefined if the current thread does not have shared access.
6670
#[inline]
6771
pub unsafe fn read_unlock(&self) {
68-
self.0.read_unlock()
72+
// SAFETY: the caller must uphold the safety contract for `read_unlock`.
73+
unsafe { self.0.read_unlock() }
6974
}
7075

7176
/// Unlocks previously acquired exclusive access to this lock.
@@ -74,7 +79,8 @@ impl RWLock {
7479
/// exclusive access.
7580
#[inline]
7681
pub unsafe fn write_unlock(&self) {
77-
self.0.write_unlock()
82+
// SAFETY: the caller must uphold the safety contract for `write_unlock`.
83+
unsafe { self.0.write_unlock() }
7884
}
7985

8086
/// Destroys OS-related resources with this RWLock.
@@ -83,6 +89,7 @@ impl RWLock {
8389
/// lock.
8490
#[inline]
8591
pub unsafe fn destroy(&self) {
86-
self.0.destroy()
92+
// SAFETY: the caller must uphold the safety contract for `destroy`.
93+
unsafe { self.0.destroy() }
8794
}
8895
}

library/std/src/sys_common/thread_info.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
1+
// stack_guard isn't used right now on all platforms
2+
#![allow(dead_code)]
3+
// FIXME: this should be removed once `thread_local!` denies unsafe ops in unsafe
4+
// fns. This cannot be done yet because the macro is also used in libproc_macro.
5+
#![allow(unsafe_op_in_unsafe_fn)]
26

37
use crate::cell::RefCell;
48
use crate::sys::thread::guard::Guard;

library/std/src/sys_common/thread_local_dtor.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,25 @@ pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut
2929

3030
static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
3131
type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
32-
if DTORS.get().is_null() {
32+
if unsafe { DTORS.get().is_null() } {
3333
let v: Box<List> = box Vec::new();
34-
DTORS.set(Box::into_raw(v) as *mut u8);
34+
unsafe { DTORS.set(Box::into_raw(v) as *mut u8) }
3535
}
36-
let list: &mut List = &mut *(DTORS.get() as *mut List);
36+
let list: &mut List = unsafe { &mut *(DTORS.get() as *mut List) };
3737
list.push((t, dtor));
3838

3939
unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
4040
while !ptr.is_null() {
41-
let list: Box<List> = Box::from_raw(ptr as *mut List);
41+
let list: Box<List> = unsafe { Box::from_raw(ptr as *mut List) };
4242
for (ptr, dtor) in list.into_iter() {
43-
dtor(ptr);
43+
unsafe {
44+
dtor(ptr);
45+
}
46+
}
47+
unsafe {
48+
ptr = DTORS.get();
49+
DTORS.set(ptr::null_mut());
4450
}
45-
ptr = DTORS.get();
46-
DTORS.set(ptr::null_mut());
4751
}
4852
}
4953
}

0 commit comments

Comments
 (0)