rustc: Implement the #[global_allocator] attribute

This PR is an implementation of [RFC 1974] which specifies a new method of
defining a global allocator for a program. This obsoletes the old
`#![allocator]` attribute and also removes support for it.

[RFC 1974]: https://github.com/rust-lang/rfcs/pull/197

The new `#[global_allocator]` attribute solves many issues encountered with the
`#![allocator]` attribute such as composition and restrictions on the crate
graph itself. The compiler now has much more control over the ABI of the
allocator and how it's implemented, allowing much more freedom in terms of how
this feature is implemented.

cc #27389
This commit is contained in:
Alex Crichton 2017-06-03 14:54:08 -07:00
parent 4c225c4d17
commit 695dee063b
115 changed files with 2860 additions and 1201 deletions

View file

@ -11,7 +11,7 @@
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
#![feature(allocator)]
#![feature(custom_attribute)]
pub struct S {
_field: [i64; 4],

View file

@ -1,21 +0,0 @@
// Copyright 2015 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.
// error-pattern: `allocator3` cannot depend on a crate that needs an allocator
// aux-build:needs_allocator.rs
// aux-build:allocator3.rs
// The needs_allocator crate is a dependency of the allocator crate allocator3,
// which is not allowed
extern crate allocator3;
fn main() {
}

View file

@ -1,41 +0,0 @@
// Copyright 2015 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.
// ignore-musl no dylibs
// aux-build:allocator-dylib.rs
// aux-build:allocator1.rs
// no-prefer-dynamic
// error-pattern: cannot link together two allocators
// Verify that the allocator for statically linked dynamic libraries is the
// system allocator. Do this by linking in jemalloc and making sure that we get
// an error.
// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
#![feature(alloc_jemalloc)]
extern crate allocator_dylib;
// The main purpose of this test is to ensure that `alloc_jemalloc` **fails**
// here (specifically the jemalloc allocator), but currently jemalloc is
// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure
// that this just passes on those platforms we link in some other allocator to
// ensure we get the same error.
//
// So long as we CI linux/macOS we should be good.
#[cfg(any(target_os = "linux", target_os = "macos"))]
extern crate alloc_jemalloc;
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
extern crate allocator1;
fn main() {
allocator_dylib::foo();
}

View file

@ -1,41 +0,0 @@
// Copyright 2015 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.
// ignore-musl no dylibs
// aux-build:allocator-dylib2.rs
// aux-build:allocator1.rs
// error-pattern: cannot link together two allocators
// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
// by linking in the system allocator here and ensuring that we get a complaint.
// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
#![feature(alloc_system)]
extern crate allocator_dylib2;
// The main purpose of this test is to ensure that `alloc_system` **fails**
// here (specifically the system allocator), but currently system is
// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure
// that this just passes on those platforms we link in some other allocator to
// ensure we get the same error.
//
// So long as we CI linux/macOS we should be good.
#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
target_os = "macos"))]
extern crate alloc_system;
#[cfg(not(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
target_os = "macos")))]
extern crate allocator1;
fn main() {
allocator_dylib2::foo();
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -10,10 +10,10 @@
// no-prefer-dynamic
#![feature(allocator)]
#![no_std]
#![allocator]
#![feature(global_allocator, allocator_api)]
#![crate_type = "rlib"]
extern crate needs_allocator;
use std::heap::System;
#[global_allocator]
static A: System = System;

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -10,7 +10,10 @@
// no-prefer-dynamic
#![feature(allocator)]
#![allocator]
#![feature(global_allocator, allocator_api)]
#![crate_type = "rlib"]
#![no_std]
use std::heap::System;
#[global_allocator]
static A: System = System;

View file

@ -0,0 +1,16 @@
// Copyright 2016 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.
#![feature(global_allocator)]
#[global_allocator]
fn foo() {} //~ ERROR: allocators must be statics
fn main() {}

View file

@ -0,0 +1,26 @@
// Copyright 2016 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.
#![feature(global_allocator, heap_api)]
#[global_allocator]
static A: usize = 0;
//~^ the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
//~| the trait bound `&usize:
fn main() {}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,12 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern: cannot link together two allocators
#![feature(global_allocator, allocator_api)]
// aux-build:allocator1.rs
// aux-build:allocator2.rs
use std::heap::System;
extern crate allocator1;
extern crate allocator2;
#[global_allocator]
static A: System = System;
#[global_allocator]
static B: System = System;
//~^ ERROR: cannot define more than one #[global_allocator]
fn main() {}

View file

@ -0,0 +1,25 @@
// Copyright 2016 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.
// aux-build:system-allocator.rs
// no-prefer-dynamic
// error-pattern: the #[global_allocator] in
#![feature(global_allocator, allocator_api)]
extern crate system_allocator;
use std::heap::System;
#[global_allocator]
static A: System = System;
fn main() {}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,12 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:system-allocator.rs
// aux-build:system-allocator2.rs
// no-prefer-dynamic
// error-pattern: the #[global_allocator] in
#![feature(alloc_system)]
#![feature(global_allocator)]
extern crate alloc_system;
extern crate system_allocator;
extern crate system_allocator2;
fn main() {
println!("{:?}", Box::new(3));
}
fn main() {}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![default_lib_allocator] //~ ERROR: attribute is an experimental feature
#![crate_type = "dylib"]
fn main() {}
pub fn foo() {}

View file

@ -0,0 +1,14 @@
// Copyright 2016 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.
#[global_allocator] //~ ERROR: attribute is an experimental feature
static A: usize = 0;
fn main() {}

View file

@ -1,21 +0,0 @@
// Copyright 2015 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.
// error-pattern: cannot link together two allocators: allocator1 and allocator2
// aux-build:allocator1.rs
// aux-build:allocator2.rs
// Make sure we can't link together two explicit allocators.
extern crate allocator1;
extern crate allocator2;
fn main() {}

View file

@ -1,23 +0,0 @@
// Copyright 2015 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.
// aux-build:allocator1.rs
// error-pattern: cannot link together two allocators
// ignore-musl no dylibs on musl yet
// ignore-emscripten
// We're linking std dynamically (via -C prefer-dynamic for this test) which
// has an allocator and then we're also linking in a new allocator (allocator1)
// and this should be an error
extern crate allocator1;
fn main() {
}

View file

@ -4,9 +4,7 @@ ifdef IS_MSVC
# FIXME(#27979)
all:
else
all:
$(RUSTC) foo.rs
$(RUSTC) bar.rs
all: $(call STATICLIB,foo) $(call STATICLIB,bar)
$(RUSTC) main.rs
$(call RUN,main)
endif

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allocator] //~ ERROR: experimental feature
extern void foo();
fn main() {}
void bar() {
foo();
}

View file

@ -1,25 +0,0 @@
// Copyright 2014 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.
#![feature(lang_items, alloc_system, compiler_builtins_lib)]
#![crate_type = "dylib"]
#![no_std]
extern crate alloc_system;
extern crate compiler_builtins;
#[no_mangle]
pub extern fn bar() {}
#[lang = "eh_personality"] fn eh_personality() {}
#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -8,5 +8,4 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub fn foo() {}
void foo() {}

View file

@ -1,25 +0,0 @@
// Copyright 2014 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.
#![feature(lang_items, alloc_system, compiler_builtins_lib)]
#![no_std]
#![crate_type = "dylib"]
extern crate alloc_system;
extern crate compiler_builtins;
#[no_mangle]
pub extern fn foo() {}
#[lang = "eh_personality"] fn eh_personality() {}
#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}

View file

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#[link(name = "foo")]
#[link(name = "bar")]
#[link(name = "foo")]
#[link(name = "foo")] // linker should drop this library, no symbols used
#[link(name = "bar")] // symbol comes from this library
#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it
extern {
fn bar();
}

View file

@ -8,20 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(alloc, allocator_api, heap_api, unique)]
#![feature(allocator_api, unique)]
extern crate alloc;
use alloc::heap::HeapAlloc;
use alloc::allocator::Alloc;
use std::heap::{Heap, Alloc};
fn main() {
unsafe {
let ptr = HeapAlloc.alloc_one::<i32>().unwrap_or_else(|e| {
HeapAlloc.oom(e)
let ptr = Heap.alloc_one::<i32>().unwrap_or_else(|e| {
Heap.oom(e)
});
*ptr.as_ptr() = 4;
assert_eq!(*ptr.as_ptr(), 4);
HeapAlloc.dealloc_one(ptr);
Heap.dealloc_one(ptr);
}
}

View file

@ -1,19 +0,0 @@
// Copyright 2015 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.
#![feature(alloc_jemalloc)]
#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
target_os = "macos"))]
extern crate alloc_jemalloc;
fn main() {
println!("{:?}", Box::new(3));
}

View file

@ -1,29 +0,0 @@
// Copyright 2015 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-prefer-dynamic
// aux-build:allocator-dummy.rs
// ignore-emscripten
#![feature(test)]
extern crate allocator_dummy;
extern crate test;
fn main() {
unsafe {
let before = allocator_dummy::HITS;
let mut b = Box::new(3);
test::black_box(&mut b); // Make sure the allocation is not optimized away
assert_eq!(allocator_dummy::HITS - before, 1);
drop(b);
assert_eq!(allocator_dummy::HITS - before, 2);
}
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -10,7 +10,18 @@
// no-prefer-dynamic
#![feature(needs_allocator)]
#![no_std]
#![needs_allocator]
#![feature(global_allocator)]
#![crate_type = "rlib"]
extern crate custom;
use std::sync::atomic::{ATOMIC_USIZE_INIT, Ordering};
use custom::A;
#[global_allocator]
static ALLOCATOR: A = A(ATOMIC_USIZE_INIT);
pub fn get() -> usize {
ALLOCATOR.0.load(Ordering::SeqCst)
}

View file

@ -0,0 +1,31 @@
// 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-prefer-dynamic
#![feature(heap_api, allocator_api)]
#![crate_type = "rlib"]
use std::heap::{Alloc, System, AllocErr, Layout};
use std::sync::atomic::{AtomicUsize, Ordering};
pub struct A(pub AtomicUsize);
unsafe impl<'a> Alloc for &'a A {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
self.0.fetch_add(1, Ordering::SeqCst);
System.alloc(layout)
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
self.0.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout)
}
}

View file

@ -1,4 +1,4 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// 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.
//
@ -10,7 +10,10 @@
// no-prefer-dynamic
#![feature(allocator)]
#![allocator]
#![crate_type = "rlib"]
#![no_std]
use std::fmt;
pub fn work_with(p: &fmt::Debug) {
drop(p);
}

View file

@ -0,0 +1,68 @@
// 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.
// aux-build:helper.rs
// no-prefer-dynamic
#![feature(global_allocator, heap_api, allocator_api)]
extern crate helper;
use std::env;
use std::heap::{Heap, Alloc, System, Layout, AllocErr};
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
struct A;
unsafe impl<'a> Alloc for &'a A {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
HITS.fetch_add(1, Ordering::SeqCst);
System.alloc(layout)
}
unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
HITS.fetch_add(1, Ordering::SeqCst);
System.dealloc(ptr, layout)
}
}
#[global_allocator]
static GLOBAL: A = A;
fn main() {
env::set_var("FOO", "bar");
drop(env::var("FOO"));
let n = HITS.load(Ordering::SeqCst);
assert!(n > 0);
unsafe {
let layout = Layout::from_size_align(4, 2).unwrap();
let ptr = Heap.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
Heap.dealloc(ptr, layout.clone());
assert_eq!(HITS.load(Ordering::SeqCst), n + 2);
let s = String::with_capacity(10);
helper::work_with(&s);
assert_eq!(HITS.load(Ordering::SeqCst), n + 3);
drop(s);
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
let ptr = System.alloc(layout.clone()).unwrap();
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
helper::work_with(&ptr);
System.dealloc(ptr, layout);
assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
}
}

View file

@ -0,0 +1,44 @@
// 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.
// aux-build:custom.rs
// aux-build:helper.rs
// no-prefer-dynamic
#![feature(global_allocator, heap_api, allocator_api)]
extern crate custom;
extern crate helper;
use std::env;
use std::heap::{Heap, Alloc, System, Layout};
use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
#[global_allocator]
static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
fn main() {
unsafe {
let n = GLOBAL.0.load(Ordering::SeqCst);
let layout = Layout::from_size_align(4, 2).unwrap();
let ptr = Heap.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
Heap.dealloc(ptr, layout.clone());
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
let ptr = System.alloc(layout.clone()).unwrap();
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
helper::work_with(&ptr);
System.dealloc(ptr, layout);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
}
}

View file

@ -0,0 +1,57 @@
// 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.
// aux-build:custom.rs
// aux-build:custom-as-global.rs
// aux-build:helper.rs
// no-prefer-dynamic
#![feature(heap_api, allocator_api)]
extern crate custom;
extern crate custom_as_global;
extern crate helper;
use std::env;
use std::heap::{Heap, Alloc, System, Layout};
use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
fn main() {
unsafe {
let n = custom_as_global::get();
let layout = Layout::from_size_align(4, 2).unwrap();
// Global allocator routes to the `custom_as_global` global
let ptr = Heap.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 1);
Heap.dealloc(ptr, layout.clone());
assert_eq!(custom_as_global::get(), n + 2);
// Usage of the system allocator avoids all globals
let ptr = System.alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 2);
System.dealloc(ptr, layout.clone());
assert_eq!(custom_as_global::get(), n + 2);
// Usage of our personal allocator doesn't affect other instances
let ptr = (&GLOBAL).alloc(layout.clone()).unwrap();
helper::work_with(&ptr);
assert_eq!(custom_as_global::get(), n + 2);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1);
(&GLOBAL).dealloc(ptr, layout);
assert_eq!(custom_as_global::get(), n + 2);
assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2);
}
}

View file

@ -8,16 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:clibrary.rs
// compile-flags: -lclibrary
// compile-flags: -lrust_test_helpers
#[link(name = "clibrary", kind = "static")]
#[link(name = "rust_test_helpers", kind = "static")]
extern "C" {
pub fn foo(x:i32) -> i32;
pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
}
fn main() {
unsafe {
foo(42);
rust_dbg_extern_identity_u32(42);
}
}

View file

@ -13,11 +13,9 @@
// Ideally this would be revised to use no_std, but for now it serves
// well enough to reproduce (and illustrate) the bug from #16687.
#![feature(heap_api, alloc, oom)]
#![feature(heap_api, allocator_api)]
extern crate alloc;
use alloc::heap;
use std::heap::{Heap, Alloc, Layout};
use std::ptr;
fn main() {
@ -47,38 +45,39 @@ unsafe fn test_triangle() -> bool {
static PRINT : bool = false;
unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if PRINT { println!("allocate(size={} align={})", size, align); }
unsafe fn allocate(layout: Layout) -> *mut u8 {
if PRINT {
println!("allocate({:?})", layout);
}
let ret = heap::allocate(size, align);
if ret.is_null() { alloc::oom() }
let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e));
if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}",
size, align, ret as usize);
if PRINT {
println!("allocate({:?}) = {:?}", layout, ret);
}
ret
}
unsafe fn deallocate(ptr: *mut u8, size: usize, align: usize) {
if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})",
ptr as usize, size, align);
unsafe fn deallocate(ptr: *mut u8, layout: Layout) {
if PRINT {
println!("deallocate({:?}, {:?}", ptr, layout);
}
heap::deallocate(ptr, size, align);
Heap.dealloc(ptr, layout);
}
unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
if PRINT {
println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})",
ptr as usize, old_size, size, align);
println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
}
let ret = heap::reallocate(ptr, old_size, size, align);
if ret.is_null() { alloc::oom() }
let ret = Heap.realloc(ptr, old.clone(), new.clone())
.unwrap_or_else(|e| Heap.oom(e));
if PRINT {
println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \
ret: 0x{:010x}",
ptr as usize, old_size, size, align, ret as usize);
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
ptr, old, new, ret);
}
ret
}
@ -91,8 +90,8 @@ unsafe fn test_triangle() -> bool {
// way.)
for i in 0..COUNT / 2 {
let size = idx_to_size(i);
ascend[2*i] = allocate(size, ALIGN);
ascend[2*i+1] = allocate(size, ALIGN);
ascend[2*i] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
ascend[2*i+1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
}
// Initialize each pair of rows to distinct value.
@ -112,8 +111,8 @@ unsafe fn test_triangle() -> bool {
for i in 0..COUNT / 2 {
let size = idx_to_size(i);
deallocate(ascend[2*i], size, ALIGN);
deallocate(ascend[2*i+1], size, ALIGN);
deallocate(ascend[2*i], Layout::from_size_align(size, ALIGN).unwrap());
deallocate(ascend[2*i+1], Layout::from_size_align(size, ALIGN).unwrap());
}
return true;
@ -124,14 +123,16 @@ unsafe fn test_triangle() -> bool {
// rows as we go.
unsafe fn test_1(ascend: &mut [*mut u8]) {
let new_size = idx_to_size(COUNT-1);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
for i in 0..COUNT / 2 {
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
assert!(old_size < new_size);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
}
}
@ -139,14 +140,16 @@ unsafe fn test_triangle() -> bool {
// Test 2: turn the square back into a triangle, top to bottom.
unsafe fn test_2(ascend: &mut [*mut u8]) {
let old_size = idx_to_size(COUNT-1);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
for i in 0..COUNT / 2 {
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
assert!(new_size < old_size);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
}
}
@ -154,14 +157,16 @@ unsafe fn test_triangle() -> bool {
// Test 3: turn triangle into a square, bottom to top.
unsafe fn test_3(ascend: &mut [*mut u8]) {
let new_size = idx_to_size(COUNT-1);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
for i in (0..COUNT / 2).rev() {
let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
assert!(old_size < new_size);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
}
}
@ -169,14 +174,16 @@ unsafe fn test_triangle() -> bool {
// Test 4: turn the square back into a triangle, bottom to top.
unsafe fn test_4(ascend: &mut [*mut u8]) {
let old_size = idx_to_size(COUNT-1);
let old = Layout::from_size_align(old_size, ALIGN).unwrap();
for i in (0..COUNT / 2).rev() {
let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
assert!(new_size < old_size);
let new = Layout::from_size_align(new_size, ALIGN).unwrap();
ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
sanity_check(&*ascend);
ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
ascend[2*i] = reallocate(p0, old.clone(), new.clone());
sanity_check(&*ascend);
}
}

View file

@ -8,16 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:clibrary.rs
// compile-flags: -lstatic=wronglibrary:clibrary
// compile-flags: -lstatic=wronglibrary:rust_test_helpers
#[link(name = "wronglibrary", kind = "dylib")]
extern "C" {
pub fn foo(x:i32) -> i32;
pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
}
fn main() {
unsafe {
foo(42);
rust_dbg_extern_identity_u32(42);
}
}

View file

@ -10,32 +10,32 @@
// Smallest "hello world" with a libc runtime
// pretty-expanded FIXME #23616
// ignore-windows
// ignore-android
#![feature(intrinsics, lang_items, start, no_core, alloc_system)]
#![no_core]
#![feature(global_allocator, allocator_api)]
#![no_std]
extern crate alloc_system;
extern { fn puts(s: *const u8); }
extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }
use alloc_system::System;
#[lang = "eh_personality"] extern fn eh_personality() {}
#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
#[global_allocator]
static A: System = System;
extern {
fn puts(s: *const u8);
}
#[no_mangle]
#[lang = "eh_personality"] pub extern fn rust_eh_personality() {}
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
#[start]
fn main(_: isize, _: *const *const u8) -> isize {
unsafe {
let (ptr, _): (*const u8, usize) = transmute("Hello!\0");
puts(ptr);
puts("Hello!\0".as_ptr() as *const u8);
}
return 0;
return 0
}
#[cfg(target_os = "android")]
#[link(name="gcc")]
extern { }