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:
Alex Crichton 2017-08-22 14:36:49 -07:00
parent a24e0f25d7
commit b6f554b6dc
5 changed files with 68 additions and 0 deletions

View File

@ -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

View File

@ -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,

View File

@ -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)]

View File

@ -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() {

View 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);
}