1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #![cfg_attr(feature = "oom_with_hook", feature(alloc_error_hook))]
7 use arrayvec::{Array, ArrayString};
10 use std::os::raw::c_char;
11 use std::os::raw::c_int;
14 #[link(name = "wrappers")]
16 // We can't use MOZ_Crash directly because it may be weakly linked
17 // and rust can't handle that.
18 fn RustMozCrash(filename: *const c_char, line: c_int, reason: *const c_char) -> !;
21 /// Truncate a string at the closest unicode character boundary
23 /// assert_eq!(str_truncate_valid("éà", 3), "é");
24 /// assert_eq!(str_truncate_valid("éà", 4), "éè");
26 fn str_truncate_valid(s: &str, mut mid: usize) -> &str {
28 if let Some(res) = s.get(..mid) {
35 /// Similar to ArrayString, but with terminating nul character.
36 #[derive(Debug, PartialEq)]
37 struct ArrayCString<A: Array<Item = u8> + Copy> {
38 inner: ArrayString<A>,
41 impl<S: AsRef<str>, A: Array<Item = u8> + Copy> From<S> for ArrayCString<A> {
42 /// Contrary to ArrayString::from, truncates at the closest unicode
43 /// character boundary.
45 /// assert_eq!(ArrayCString::<[_; 4]>::from("éà"),
46 /// ArrayCString::<[_; 4]>::from("é"));
47 /// assert_eq!(&*ArrayCString::<[_; 4]>::from("éà"), "é\0");
49 fn from(s: S) -> Self {
51 let len = cmp::min(s.len(), A::CAPACITY - 1);
52 let mut result = Self {
53 inner: ArrayString::from(str_truncate_valid(s, len)).unwrap(),
55 result.inner.push('\0');
60 impl<A: Array<Item = u8> + Copy> Deref for ArrayCString<A> {
63 fn deref(&self) -> &str {
68 fn panic_hook(info: &panic::PanicInfo) {
69 // Try to handle &str/String payloads, which should handle 99% of cases.
70 let payload = info.payload();
71 let message = if let Some(s) = payload.downcast_ref::<&str>() {
73 } else if let Some(s) = payload.downcast_ref::<String>() {
76 // Not the most helpful thing, but seems unlikely to happen
78 "Unhandled rust panic payload!"
80 let (filename, line) = if let Some(loc) = info.location() {
81 (loc.file(), loc.line())
85 // Copy the message and filename to the stack in order to safely add
86 // a terminating nul character (since rust strings don't come with one
87 // and RustMozCrash wants one).
88 let message = ArrayCString::<[_; 512]>::from(message);
89 let filename = ArrayCString::<[_; 512]>::from(filename);
92 filename.as_ptr() as *const c_char,
94 message.as_ptr() as *const c_char,
99 /// Configure a panic hook to redirect rust panics to MFBT's MOZ_Crash.
101 pub extern "C" fn install_rust_panic_hook() {
102 panic::set_hook(Box::new(panic_hook));
105 #[cfg(feature = "oom_with_hook")]
107 use std::alloc::{set_alloc_error_hook, Layout};
110 fn RustHandleOOM(size: usize) -> !;
113 pub fn hook(layout: Layout) {
115 RustHandleOOM(layout.size());
120 set_alloc_error_hook(hook);
125 pub extern "C" fn install_rust_oom_hook() {
126 #[cfg(feature = "oom_with_hook")]
130 #[cfg(feature = "moz_memory")]
132 use std::alloc::{GlobalAlloc, Layout};
133 use std::os::raw::c_void;
136 fn malloc(size: usize) -> *mut c_void;
138 fn free(ptr: *mut c_void);
140 fn calloc(nmemb: usize, size: usize) -> *mut c_void;
142 fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
145 fn _aligned_malloc(size: usize, align: usize) -> *mut c_void;
148 fn memalign(align: usize, size: usize) -> *mut c_void;
152 unsafe fn memalign(align: usize, size: usize) -> *mut c_void {
153 _aligned_malloc(size, align)
156 pub struct GeckoAlloc;
159 fn need_memalign(layout: Layout) -> bool {
160 // mozjemalloc guarantees a minimum alignment of 16 for all sizes, except
161 // for size classes below 16 (4 and 8).
162 layout.align() > layout.size() || layout.align() > 16
165 unsafe impl GlobalAlloc for GeckoAlloc {
166 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
167 if need_memalign(layout) {
168 memalign(layout.align(), layout.size()) as *mut u8
170 malloc(layout.size()) as *mut u8
174 unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
175 free(ptr as *mut c_void)
178 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
179 if need_memalign(layout) {
180 let ptr = self.alloc(layout);
182 std::ptr::write_bytes(ptr, 0, layout.size());
186 calloc(1, layout.size()) as *mut u8
190 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
191 let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
192 if need_memalign(new_layout) {
193 let new_ptr = self.alloc(new_layout);
194 if !new_ptr.is_null() {
195 let size = std::cmp::min(layout.size(), new_size);
196 std::ptr::copy_nonoverlapping(ptr, new_ptr, size);
197 self.dealloc(ptr, layout);
201 realloc(ptr as *mut c_void, new_size) as *mut u8
207 #[cfg(feature = "moz_memory")]
209 static A: moz_memory::GeckoAlloc = moz_memory::GeckoAlloc;