summaryrefslogtreecommitdiffstats
path: root/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
blob: 851da231a73441708317aabc4c681f92e967f2dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// run-pass
// ignore-android no libc
// ignore-emscripten no libc
// ignore-sgx no libc
// ignore-wasm32 no libc
// only-linux
// compile-flags:-C panic=abort
// aux-build:helper.rs

#![feature(start, rustc_private, new_uninit, panic_info_message, lang_items)]
#![feature(alloc_error_handler)]
#![no_std]

extern crate alloc;
extern crate libc;

// ARM targets need these symbols
#[no_mangle]
pub fn __aeabi_unwind_cpp_pr0() {}

#[no_mangle]
pub fn __aeabi_unwind_cpp_pr1() {}

use core::ptr::null_mut;
use core::alloc::{GlobalAlloc, Layout};
use alloc::boxed::Box;

extern crate helper;

struct MyAllocator;

#[alloc_error_handler]
fn my_oom(layout: Layout) -> !
{
    use alloc::fmt::write;
    unsafe {
        let size = layout.size();
        let mut s = alloc::string::String::new();
        write(&mut s, format_args!("My OOM: failed to allocate {} bytes!\n", size)).unwrap();
        let s = s.as_str();
        libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
        libc::exit(0)
    }
}

unsafe impl GlobalAlloc for MyAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        if layout.size() < 4096 {
            libc::malloc(layout.size()) as _
        } else {
            null_mut()
        }
    }
    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}

#[global_allocator]
static A: MyAllocator = MyAllocator;

#[panic_handler]
fn panic(panic_info: &core::panic::PanicInfo) -> ! {
    unsafe {
        if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
            const PSTR: &str = "panic occurred: ";
            const CR: &str = "\n";
            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
        }
        if let Some(args) = panic_info.message() {
            let mut s = alloc::string::String::new();
            alloc::fmt::write(&mut s, *args).unwrap();
            let s = s.as_str();
            const PSTR: &str = "panic occurred: ";
            const CR: &str = "\n";
            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
            libc::write(libc::STDERR_FILENO, s as *const _ as _, s.len());
            libc::write(libc::STDERR_FILENO, CR as *const _ as _, CR.len());
        } else {
            const PSTR: &str = "panic occurred\n";
            libc::write(libc::STDERR_FILENO, PSTR as *const _ as _, PSTR.len());
        }
        libc::exit(1)
    }
}

// Because we are compiling this code with `-C panic=abort`, this wouldn't normally be needed.
// However, `core` and `alloc` are both compiled with `-C panic=unwind`, which means that functions
// in these libraries will refer to `rust_eh_personality` if LLVM can not *prove* the contents won't
// unwind. So, for this test case we will define the symbol.
#[lang = "eh_personality"]
extern fn rust_eh_personality() {}

#[derive(Debug)]
struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);

#[start]
pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
    let zero = Box::<Page>::new_zeroed();
    let zero = unsafe { zero.assume_init() };
    helper::work_with(&zero);
    1
}