Skip to content

Commit 76a1144

Browse files
committed
std: Mark allocation functions as nounwind
This commit flags all allocation-related functions in liballoc as "this can't unwind" which should largely resolve the size-related issues found on #42808. The documentation on the trait was updated with such a restriction (they can't panic) as well as some other words about the relative instability about implementing a bullet-proof allocator. Closes #42808
1 parent 4b6a821 commit 76a1144

File tree

4 files changed

+66
-0
lines changed

4 files changed

+66
-0
lines changed

src/liballoc/allocator.rs

+21
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,27 @@ impl fmt::Display for CannotReallocInPlace {
452452
/// * if a layout `k` fits a memory block (denoted by `ptr`)
453453
/// currently allocated via an allocator `a`, then it is legal to
454454
/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`.
455+
///
456+
/// # Unsafety
457+
///
458+
/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and
459+
/// implementors must ensure that they adhere to these contracts:
460+
///
461+
/// * Pointers returned from allocation functions must point to valid memory and
462+
/// retain their validity until at least the instance of `Alloc` is dropped
463+
/// itself.
464+
///
465+
/// * Implementations of `Alloc` are not currently memory safe if they unwind.
466+
/// This restriction may be lifted in the future, but currently an panic from
467+
/// any of these functions may lead to memory unsafety.
468+
///
469+
/// * `Layout` queries and calculations in general must be correct. Callers of
470+
/// this trait are allowed to rely on the contracts defined on each method,
471+
/// and implementors must ensure such contracts remain true.
472+
///
473+
/// Note that this list may get tweaked over time as clarifications are made in
474+
/// the future. Additionally global allocators may gain unique requirements for
475+
/// how to safely implement one in the future as well.
455476
pub unsafe trait Alloc {
456477

457478
// (Note: existing allocators have unspecified but well-defined

src/liballoc/heap.rs

+11
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,46 @@ pub mod __core {
2727

2828
extern "Rust" {
2929
#[allocator]
30+
#[allocator_nounwind]
3031
fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
32+
#[cold]
33+
#[allocator_nounwind]
3134
fn __rust_oom(err: *const u8) -> !;
35+
#[allocator_nounwind]
3236
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
37+
#[allocator_nounwind]
3338
fn __rust_usable_size(layout: *const u8,
3439
min: *mut usize,
3540
max: *mut usize);
41+
#[allocator_nounwind]
3642
fn __rust_realloc(ptr: *mut u8,
3743
old_size: usize,
3844
old_align: usize,
3945
new_size: usize,
4046
new_align: usize,
4147
err: *mut u8) -> *mut u8;
48+
#[allocator_nounwind]
4249
fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
50+
#[allocator_nounwind]
4351
fn __rust_alloc_excess(size: usize,
4452
align: usize,
4553
excess: *mut usize,
4654
err: *mut u8) -> *mut u8;
55+
#[allocator_nounwind]
4756
fn __rust_realloc_excess(ptr: *mut u8,
4857
old_size: usize,
4958
old_align: usize,
5059
new_size: usize,
5160
new_align: usize,
5261
excess: *mut usize,
5362
err: *mut u8) -> *mut u8;
63+
#[allocator_nounwind]
5464
fn __rust_grow_in_place(ptr: *mut u8,
5565
old_size: usize,
5666
old_align: usize,
5767
new_size: usize,
5868
new_align: usize) -> u8;
69+
#[allocator_nounwind]
5970
fn __rust_shrink_in_place(ptr: *mut u8,
6071
old_size: usize,
6172
old_align: usize,

src/librustc_trans/attributes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
119119
llvm::AttributePlace::ReturnValue(), llfn);
120120
} else if attr.check_name("unwind") {
121121
unwind(llfn, true);
122+
} else if attr.check_name("allocator_nounwind") {
123+
unwind(llfn, false);
122124
}
123125
}
124126
if !target_features.is_empty() {

src/test/codegen/dealloc-no-unwind.rs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
//
11+
// no-system-llvm
12+
// compile-flags: -O
13+
14+
#![crate_type="lib"]
15+
16+
struct A;
17+
18+
impl Drop for A {
19+
fn drop(&mut self) {
20+
extern { fn foo(); }
21+
unsafe { foo(); }
22+
}
23+
}
24+
25+
#[no_mangle]
26+
pub fn a(a: Box<i32>) {
27+
// CHECK-LABEL: define void @a
28+
// CHECK: call void @__rust_dealloc
29+
// CHECK-NEXT: call void @foo
30+
let _a = A;
31+
drop(a);
32+
}

0 commit comments

Comments
 (0)