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
5 changed files with 68 additions and 0 deletions
|
@ -464,6 +464,29 @@ impl fmt::Display for CannotReallocInPlace {
|
||||||
/// * if a layout `k` fits a memory block (denoted by `ptr`)
|
/// * if a layout `k` fits a memory block (denoted by `ptr`)
|
||||||
/// currently allocated via an allocator `a`, then it is legal to
|
/// currently allocated via an allocator `a`, then it is legal to
|
||||||
/// use that layout to deallocate it, i.e. `a.dealloc(ptr, k);`.
|
/// 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 {
|
pub unsafe trait Alloc {
|
||||||
|
|
||||||
// (Note: existing allocators have unspecified but well-defined
|
// (Note: existing allocators have unspecified but well-defined
|
||||||
|
|
|
@ -27,24 +27,32 @@ pub mod __core {
|
||||||
|
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
#[allocator]
|
#[allocator]
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
||||||
#[cold]
|
#[cold]
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_oom(err: *const u8) -> !;
|
fn __rust_oom(err: *const u8) -> !;
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
|
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_usable_size(layout: *const u8,
|
fn __rust_usable_size(layout: *const u8,
|
||||||
min: *mut usize,
|
min: *mut usize,
|
||||||
max: *mut usize);
|
max: *mut usize);
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_realloc(ptr: *mut u8,
|
fn __rust_realloc(ptr: *mut u8,
|
||||||
old_size: usize,
|
old_size: usize,
|
||||||
old_align: usize,
|
old_align: usize,
|
||||||
new_size: usize,
|
new_size: usize,
|
||||||
new_align: usize,
|
new_align: usize,
|
||||||
err: *mut u8) -> *mut u8;
|
err: *mut u8) -> *mut u8;
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_alloc_excess(size: usize,
|
fn __rust_alloc_excess(size: usize,
|
||||||
align: usize,
|
align: usize,
|
||||||
excess: *mut usize,
|
excess: *mut usize,
|
||||||
err: *mut u8) -> *mut u8;
|
err: *mut u8) -> *mut u8;
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_realloc_excess(ptr: *mut u8,
|
fn __rust_realloc_excess(ptr: *mut u8,
|
||||||
old_size: usize,
|
old_size: usize,
|
||||||
old_align: usize,
|
old_align: usize,
|
||||||
|
@ -52,11 +60,13 @@ extern "Rust" {
|
||||||
new_align: usize,
|
new_align: usize,
|
||||||
excess: *mut usize,
|
excess: *mut usize,
|
||||||
err: *mut u8) -> *mut u8;
|
err: *mut u8) -> *mut u8;
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_grow_in_place(ptr: *mut u8,
|
fn __rust_grow_in_place(ptr: *mut u8,
|
||||||
old_size: usize,
|
old_size: usize,
|
||||||
old_align: usize,
|
old_align: usize,
|
||||||
new_size: usize,
|
new_size: usize,
|
||||||
new_align: usize) -> u8;
|
new_align: usize) -> u8;
|
||||||
|
#[rustc_allocator_nounwind]
|
||||||
fn __rust_shrink_in_place(ptr: *mut u8,
|
fn __rust_shrink_in_place(ptr: *mut u8,
|
||||||
old_size: usize,
|
old_size: usize,
|
||||||
old_align: usize,
|
old_align: usize,
|
||||||
|
|
|
@ -107,6 +107,7 @@
|
||||||
#![feature(pattern)]
|
#![feature(pattern)]
|
||||||
#![feature(placement_in_syntax)]
|
#![feature(placement_in_syntax)]
|
||||||
#![feature(placement_new_protocol)]
|
#![feature(placement_new_protocol)]
|
||||||
|
#![feature(rustc_attrs)]
|
||||||
#![feature(shared)]
|
#![feature(shared)]
|
||||||
#![feature(slice_get_slice)]
|
#![feature(slice_get_slice)]
|
||||||
#![feature(slice_patterns)]
|
#![feature(slice_patterns)]
|
||||||
|
|
|
@ -119,6 +119,8 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
|
||||||
llvm::AttributePlace::ReturnValue(), llfn);
|
llvm::AttributePlace::ReturnValue(), llfn);
|
||||||
} else if attr.check_name("unwind") {
|
} else if attr.check_name("unwind") {
|
||||||
unwind(llfn, true);
|
unwind(llfn, true);
|
||||||
|
} else if attr.check_name("rustc_allocator_nounwind") {
|
||||||
|
unwind(llfn, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !target_features.is_empty() {
|
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…
Add table
Add a link
Reference in a new issue