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
This commit is contained in:
parent
a24e0f25d7
commit
b6f554b6dc
@ -464,6 +464,29 @@ impl fmt::Display for CannotReallocInPlace {
|
||||
/// * if a layout `k` fits a memory block (denoted by `ptr`)
|
||||
/// currently allocated via an allocator `a`, then it is legal to
|
||||
/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// The `Alloc` trait is an `unsafe` trait for a number of reasons, and
|
||||
/// implementors must ensure that they adhere to these contracts:
|
||||
///
|
||||
/// * Pointers returned from allocation functions must point to valid memory and
|
||||
/// retain their validity until at least the instance of `Alloc` is dropped
|
||||
/// itself.
|
||||
///
|
||||
/// * It's undefined behavior if global allocators unwind. This restriction may
|
||||
/// be lifted in the future, but currently a panic from any of these
|
||||
/// functions may lead to memory unsafety. Note that as of the time of this
|
||||
/// writing allocators *not* intending to be global allocators can still panic
|
||||
/// in their implementation without violating memory safety.
|
||||
///
|
||||
/// * `Layout` queries and calculations in general must be correct. Callers of
|
||||
/// this trait are allowed to rely on the contracts defined on each method,
|
||||
/// and implementors must ensure such contracts remain true.
|
||||
///
|
||||
/// Note that this list may get tweaked over time as clarifications are made in
|
||||
/// the future. Additionally global allocators may gain unique requirements for
|
||||
/// how to safely implement one in the future as well.
|
||||
pub unsafe trait Alloc {
|
||||
|
||||
// (Note: existing allocators have unspecified but well-defined
|
||||
|
@ -27,24 +27,32 @@ pub mod __core {
|
||||
|
||||
extern "Rust" {
|
||||
#[allocator]
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
||||
#[cold]
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_oom(err: *const u8) -> !;
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_usable_size(layout: *const u8,
|
||||
min: *mut usize,
|
||||
max: *mut usize);
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_realloc(ptr: *mut u8,
|
||||
old_size: usize,
|
||||
old_align: usize,
|
||||
new_size: usize,
|
||||
new_align: usize,
|
||||
err: *mut u8) -> *mut u8;
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_alloc_excess(size: usize,
|
||||
align: usize,
|
||||
excess: *mut usize,
|
||||
err: *mut u8) -> *mut u8;
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_realloc_excess(ptr: *mut u8,
|
||||
old_size: usize,
|
||||
old_align: usize,
|
||||
@ -52,11 +60,13 @@ extern "Rust" {
|
||||
new_align: usize,
|
||||
excess: *mut usize,
|
||||
err: *mut u8) -> *mut u8;
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_grow_in_place(ptr: *mut u8,
|
||||
old_size: usize,
|
||||
old_align: usize,
|
||||
new_size: usize,
|
||||
new_align: usize) -> u8;
|
||||
#[rustc_allocator_nounwind]
|
||||
fn __rust_shrink_in_place(ptr: *mut u8,
|
||||
old_size: usize,
|
||||
old_align: usize,
|
||||
|
@ -107,6 +107,7 @@
|
||||
#![feature(pattern)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(placement_new_protocol)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(shared)]
|
||||
#![feature(slice_get_slice)]
|
||||
#![feature(slice_patterns)]
|
||||
|
@ -119,6 +119,8 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
|
||||
llvm::AttributePlace::ReturnValue(), llfn);
|
||||
} else if attr.check_name("unwind") {
|
||||
unwind(llfn, true);
|
||||
} else if attr.check_name("rustc_allocator_nounwind") {
|
||||
unwind(llfn, false);
|
||||
}
|
||||
}
|
||||
if !target_features.is_empty() {
|
||||
|
32
src/test/codegen/dealloc-no-unwind.rs
Normal file
32
src/test/codegen/dealloc-no-unwind.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// no-system-llvm
|
||||
// compile-flags: -O
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
struct A;
|
||||
|
||||
impl Drop for A {
|
||||
fn drop(&mut self) {
|
||||
extern { fn foo(); }
|
||||
unsafe { foo(); }
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn a(a: Box<i32>) {
|
||||
// CHECK-LABEL: define void @a
|
||||
// CHECK: call void @__rust_dealloc
|
||||
// CHECK-NEXT: call void @foo
|
||||
let _a = A;
|
||||
drop(a);
|
||||
}
|
Loading…
Reference in New Issue
Block a user