diff options
author | Matthew Maurer <mmaurer@google.com> | 2021-08-23 20:18:23 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-08-23 20:18:23 +0000 |
commit | 8d48c68380f84270eb7c37e2fa3eb6f5b99d2bd1 (patch) | |
tree | 2ba28e2710f7e840a8a69f53bd763176ec14098c | |
parent | cbc2c275ac9e5b05fe3cc29d4dce5383b37782a3 (diff) | |
parent | b9b539ba98973bda29819769b6cfba795a818cf6 (diff) | |
download | rustc-demangle-capi-8d48c68380f84270eb7c37e2fa3eb6f5b99d2bd1.tar.gz |
Adjust API to match __cxa_demangle am: 3984194dfe am: b29f75761b am: b9b539ba98
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/rustc-demangle-capi/+/1798343
Change-Id: I7622b22d61d075bb10f3550a81d6407074307e53
-rw-r--r-- | include/rustc_demangle.h | 9 | ||||
-rw-r--r-- | patches/0002-Adjust-API-to-match-__cxa_demangle.patch | 435 | ||||
-rw-r--r-- | src/lib.rs | 339 |
3 files changed, 673 insertions, 110 deletions
diff --git a/include/rustc_demangle.h b/include/rustc_demangle.h index 61c4aa1..e7ee2ca 100644 --- a/include/rustc_demangle.h +++ b/include/rustc_demangle.h @@ -5,11 +5,10 @@ extern "C" { #endif -// Demangles symbol given in `mangled` argument into `out` buffer -// -// Returns 0 if `mangled` is not Rust symbol or if `out` buffer is too small -// Returns 1 otherwise -int rustc_demangle(const char *mangled, char *out, size_t out_size); +// For size_t +#include <stddef.h> + +char *rustc_demangle(const char *mangled, char *out, size_t *len, int *status); #ifdef __cplusplus } diff --git a/patches/0002-Adjust-API-to-match-__cxa_demangle.patch b/patches/0002-Adjust-API-to-match-__cxa_demangle.patch new file mode 100644 index 0000000..b54d49a --- /dev/null +++ b/patches/0002-Adjust-API-to-match-__cxa_demangle.patch @@ -0,0 +1,435 @@ +From 290b3379f60c0578174861c6ac8fb93f1ce83a3f Mon Sep 17 00:00:00 2001 +From: Matthew Maurer <mmaurer@google.com> +Date: Tue, 17 Aug 2021 10:50:56 -0700 +Subject: [PATCH] Adjust API to match __cxa_demangle + +Bug: 178565008 +Test: cargo test + generate tombstone +Change-Id: Iaf76af67a7f3a6323e926075a8ecd08b1d381db0 +--- + include/rustc_demangle.h | 9 +- + src/lib.rs | 339 +++++++++++++++++++++++++++------------ + 2 files changed, 238 insertions(+), 110 deletions(-) + +diff --git a/include/rustc_demangle.h b/include/rustc_demangle.h +index 61c4aa1..e7ee2ca 100644 +--- a/include/rustc_demangle.h ++++ b/include/rustc_demangle.h +@@ -5,11 +5,10 @@ + extern "C" { + #endif + +-// Demangles symbol given in `mangled` argument into `out` buffer +-// +-// Returns 0 if `mangled` is not Rust symbol or if `out` buffer is too small +-// Returns 1 otherwise +-int rustc_demangle(const char *mangled, char *out, size_t out_size); ++// For size_t ++#include <stddef.h> ++ ++char *rustc_demangle(const char *mangled, char *out, size_t *len, int *status); + + #ifdef __cplusplus + } +diff --git a/src/lib.rs b/src/lib.rs +index 51e3103..7610145 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -1,160 +1,289 @@ + extern crate rustc_demangle; + ++use std::alloc::{GlobalAlloc, Layout, System}; + use std::io::Write; + use std::os::raw::{c_char, c_int}; ++use std::ptr; ++use std::result; ++ ++type Result<T> = result::Result<T, Status>; ++ ++/// Convenience function to set return status if a location was provided. ++unsafe fn set_status(status: *mut c_int, val: c_int) { ++ if !status.is_null() { ++ *status = val; ++ } ++} ++ ++/// Region from the system allocator for demangler output. We use the ++/// system allocator because the intended client is C/C++ code which ++/// may not be using the Rust allocator. ++struct SystemBuffer { ++ buf: *mut u8, ++ size: usize, ++ size_out: *mut usize, ++} ++ ++impl SystemBuffer { ++ const DEFAULT_BUFFER_SIZE: usize = 1024; ++ fn new(size: usize) -> Result<Self> { ++ let buf = unsafe { System.alloc_zeroed(Layout::from_size_align_unchecked(size, 1)) }; ++ if buf.is_null() { ++ Err(Status::AllocFailure) ++ } else { ++ Ok(Self { ++ buf, ++ size, ++ size_out: ptr::null_mut(), ++ }) ++ } ++ } ++ /// Safety: If buf is non-null, size must be non-null and point to the ++ /// non-zero size of the buffer provided in buf. ++ /// Takes ownership of the buffer passed in (and may reallocate it). ++ /// size must outlive the resulting buffer if non-null. ++ unsafe fn from_raw(buf: *mut c_char, size: *mut usize) -> Result<Self> { ++ if buf.is_null() { ++ if !size.is_null() { ++ *size = Self::DEFAULT_BUFFER_SIZE; ++ } ++ let fresh = Self::new(Self::DEFAULT_BUFFER_SIZE)?; ++ Ok(Self { ++ size_out: size, ++ ..fresh ++ }) ++ } else { ++ Ok(Self { ++ buf: buf as *mut u8, ++ size: *size, ++ size_out: size, ++ }) ++ } ++ } ++ fn as_mut_slice(&mut self) -> &mut [u8] { ++ unsafe { std::slice::from_raw_parts_mut(self.buf, self.size) } ++ } ++ fn resize(&mut self) -> Result<()> { ++ let new_size = self.size * 2; ++ let new_buf = unsafe { ++ System.realloc( ++ self.buf, ++ Layout::from_size_align_unchecked(self.size, 1), ++ new_size, ++ ) ++ }; ++ if new_buf.is_null() { ++ Err(Status::AllocFailure) ++ } else { ++ self.buf = new_buf; ++ self.size = new_size; ++ if !self.size_out.is_null() { ++ unsafe { ++ *self.size_out = new_size; ++ } ++ } ++ Ok(()) ++ } ++ } ++} + + /// C-style interface for demangling. +-/// Demangles symbol given in `mangled` argument into `out` buffer ++/// Demangles symbol given in `mangled` argument into `out` buffer. ++/// ++/// This interface is a drop-in replacement for `__cxa_demangle`, but for ++/// Rust demangling. ++/// ++/// If `out` is null, a buffer will be allocated using the system allocator ++/// to contain the results. ++/// If `out` is non-null, `out_size` must be a pointer to the current size ++/// of the buffer, and `out` must come from the system allocator. ++/// If `out_size` is non-null, the size of the output buffer will be written ++/// to it. ++/// ++/// If `status` is non-null, it will be set to one of the following values: ++/// * 0: Demangling succeeded ++/// * -1: Allocation failure ++/// * -2: Name did not demangle ++/// * -3: Invalid arguments ++/// ++/// Returns null if `mangled` is not Rust symbol or demangling failed. ++/// Returns the buffer containing the demangled symbol name otherwise. + /// + /// Unsafe as it handles buffers by raw pointers. + /// +-/// Returns 0 if `mangled` is not Rust symbol or if `out` buffer is too small +-/// Returns 1 otherwise ++/// For non-null `out`, `out_size` represents a slight deviation from the ++/// `__cxa_demangle` behavior. For `__cxa_demangle`, the buffer must be at ++/// *least* the provided size. For `rustc_demangle`, it must be the exact ++/// buffer size because it is used in the reconstruction of the `Layout` ++/// for use with `::realloc`. + #[no_mangle] + pub unsafe extern "C" fn rustc_demangle( + mangled: *const c_char, + out: *mut c_char, +- out_size: usize, +-) -> c_int { ++ out_size: *mut usize, ++ status: *mut c_int, ++) -> *mut c_char { ++ match rustc_demangle_native(mangled, out, out_size) { ++ Ok(demangled) => { ++ set_status(status, 0); ++ demangled ++ } ++ Err(e) => { ++ set_status(status, e as c_int); ++ ptr::null_mut() ++ } ++ } ++} ++ ++enum Status { ++ AllocFailure = -1, ++ DemangleFailure = -2, ++ InvalidArgs = -3, ++} ++ ++unsafe fn rustc_demangle_native( ++ mangled: *const c_char, ++ out: *mut c_char, ++ out_size: *mut usize, ++) -> Result<*mut c_char> { ++ if mangled.is_null() { ++ return Err(Status::InvalidArgs); ++ } + let mangled_str = match std::ffi::CStr::from_ptr(mangled).to_str() { + Ok(s) => s, +- Err(_) => return 0, ++ Err(_) => return Err(Status::InvalidArgs), + }; ++ ++ if !out.is_null() { ++ if out_size.is_null() { ++ return Err(Status::InvalidArgs); ++ } ++ if *out_size == 0 { ++ return Err(Status::InvalidArgs); ++ } ++ } ++ ++ let mut out_buf = SystemBuffer::from_raw(out, out_size)?; ++ + match rustc_demangle::try_demangle(mangled_str) { + Ok(demangle) => { +- let mut out_slice = std::slice::from_raw_parts_mut(out as *mut u8, out_size); +- match write!(out_slice, "{:#}\0", demangle) { +- Ok(_) => return 1, +- Err(_) => return 0, ++ while write!(out_buf.as_mut_slice(), "{:#}\0", demangle).is_err() { ++ out_buf.resize()?; + } ++ Ok(out_buf.as_mut_slice().as_mut_ptr() as *mut c_char) + } +- Err(_) => return 0, ++ Err(_) => Err(Status::DemangleFailure), + } + } + + #[cfg(test)] + mod tests { +- use std; +- use std::os::raw::c_char; ++ use std::alloc::{GlobalAlloc, Layout, System}; ++ use std::os::raw::{c_char, c_int}; ++ use std::ptr; ++ ++ struct DemangleResult { ++ out_buf: *mut u8, ++ out_size: usize, ++ status: c_int, ++ } ++ ++ impl Drop for DemangleResult { ++ fn drop(&mut self) { ++ if !self.out_buf.is_null() { ++ unsafe { ++ System.dealloc( ++ self.out_buf, ++ Layout::from_size_align_unchecked(self.out_size, 1), ++ ); ++ } ++ } ++ } ++ } ++ ++ impl DemangleResult { ++ fn as_slice(&self) -> &[u8] { ++ unsafe { std::slice::from_raw_parts(self.out_buf, self.out_size) } ++ } ++ } ++ ++ fn demangle(mangled: &str, alloc_size: usize) -> DemangleResult { ++ unsafe { raw_demangle(mangled.as_ptr() as *const c_char, alloc_size) } ++ } ++ ++ unsafe fn raw_demangle(mangled: *const c_char, alloc_size: usize) -> DemangleResult { ++ let mut out_size: usize = alloc_size; ++ let mut status: c_int = 0; ++ let out_buf: *mut c_char = if out_size != 0 { ++ System.alloc(Layout::from_size_align_unchecked(out_size, 1)) as *mut c_char ++ } else { ++ ptr::null_mut() ++ }; ++ ptr::write_bytes(out_buf, '*' as u8, out_size); ++ ++ let res = super::rustc_demangle(mangled, out_buf, &mut out_size, &mut status); ++ DemangleResult { ++ out_buf: res as *mut u8, ++ out_size, ++ status, ++ } ++ } ++ + #[test] + fn demangle_c_str_large() { +- let mangled = "_ZN4testE\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 8, +- ) +- }; +- assert_eq!(res, 1); +- let out_str = std::str::from_utf8(&out_buf[..5]).unwrap(); ++ let res = demangle("_ZN4testE\0", 8); ++ assert_eq!(res.status, 0); ++ let out_str = core::str::from_utf8(&res.as_slice()[..5]).unwrap(); + assert_eq!(out_str, "test\0"); + } + + #[test] + fn demangle_c_str_exact() { +- let mangled = "_ZN4testE\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 5, +- ) +- }; +- assert_eq!(res, 1); +- let out_str = std::str::from_utf8(&out_buf).unwrap(); ++ let res = demangle("_ZN4testE\0", 8); ++ assert_eq!(res.status, 0); ++ // No reallocation necessary, so our * fill should be present ++ let out_str = core::str::from_utf8(res.as_slice()).unwrap(); + assert_eq!(out_str, "test\0***"); + } + + #[test] + fn demangle_c_str_small() { +- let mangled = "_ZN4testE\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 4, +- ) +- }; +- assert_eq!(res, 0); +- let out_str = std::str::from_utf8(&out_buf[4..]).unwrap(); +- assert_eq!(out_str, "****"); +- } +- +- #[test] +- fn demangle_c_str_smaller() { +- let mangled = "_ZN4testE\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 3, +- ) +- }; +- assert_eq!(res, 0); +- let out_str = std::str::from_utf8(&out_buf[3..]).unwrap(); +- assert_eq!(out_str, "*****"); ++ let res = demangle("_ZN4testE\0", 4); ++ assert_eq!(res.status, 0); ++ // demangle should have realloced ++ assert_ne!(res.out_size, 4); ++ // Only check the start, since the reallocation means our * fill may ++ // be absent. ++ let out_str = core::str::from_utf8(&res.as_slice()[..5]).unwrap(); ++ assert_eq!(out_str, "test\0"); + } + + #[test] +- fn demangle_c_str_zero() { +- let mangled = "_ZN4testE\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 0, +- ) +- }; +- assert_eq!(res, 0); +- let out_str = std::str::from_utf8(&out_buf).unwrap(); +- assert_eq!(out_str, "********"); ++ fn demangle_c_str_alloc() { ++ let res = demangle("_ZN4testE\0", 0); ++ assert_eq!(res.status, 0); ++ // demangle should have allocated ++ assert_ne!(res.out_size, 0); ++ let out_str = core::str::from_utf8(&res.as_slice()[..5]).unwrap(); ++ assert_eq!(out_str, "test\0"); + } + + #[test] + fn demangle_c_str_not_rust_symbol() { +- let mangled = "la la la\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 8, +- ) +- }; +- assert_eq!(res, 0); ++ let res = demangle("la la la\0", 8); ++ assert_eq!(res.status, -2); + } + + #[test] + fn demangle_c_str_null() { +- let mangled = "\0"; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 8, +- ) +- }; +- assert_eq!(res, 0); ++ let res = demangle("\0", 8); ++ assert_eq!(res.status, -2); + } + + #[test] + fn demangle_c_str_invalid_utf8() { + let mangled = [116, 101, 115, 116, 165, 0]; +- let mut out_buf: Vec<u8> = vec![42; 8]; +- let res = unsafe { +- super::rustc_demangle( +- mangled.as_ptr() as *const c_char, +- out_buf.as_mut_ptr() as *mut c_char, +- 8, +- ) +- }; +- assert_eq!(res, 0); ++ let res = unsafe { raw_demangle(mangled.as_ptr() as *const c_char, 8) }; ++ assert_eq!(res.status, -2); + } + } +-- +2.33.0.rc1.237.g0d66db33f3-goog + @@ -1,160 +1,289 @@ extern crate rustc_demangle; +use std::alloc::{GlobalAlloc, Layout, System}; use std::io::Write; use std::os::raw::{c_char, c_int}; +use std::ptr; +use std::result; + +type Result<T> = result::Result<T, Status>; + +/// Convenience function to set return status if a location was provided. +unsafe fn set_status(status: *mut c_int, val: c_int) { + if !status.is_null() { + *status = val; + } +} + +/// Region from the system allocator for demangler output. We use the +/// system allocator because the intended client is C/C++ code which +/// may not be using the Rust allocator. +struct SystemBuffer { + buf: *mut u8, + size: usize, + size_out: *mut usize, +} + +impl SystemBuffer { + const DEFAULT_BUFFER_SIZE: usize = 1024; + fn new(size: usize) -> Result<Self> { + let buf = unsafe { System.alloc_zeroed(Layout::from_size_align_unchecked(size, 1)) }; + if buf.is_null() { + Err(Status::AllocFailure) + } else { + Ok(Self { + buf, + size, + size_out: ptr::null_mut(), + }) + } + } + /// Safety: If buf is non-null, size must be non-null and point to the + /// non-zero size of the buffer provided in buf. + /// Takes ownership of the buffer passed in (and may reallocate it). + /// size must outlive the resulting buffer if non-null. + unsafe fn from_raw(buf: *mut c_char, size: *mut usize) -> Result<Self> { + if buf.is_null() { + if !size.is_null() { + *size = Self::DEFAULT_BUFFER_SIZE; + } + let fresh = Self::new(Self::DEFAULT_BUFFER_SIZE)?; + Ok(Self { + size_out: size, + ..fresh + }) + } else { + Ok(Self { + buf: buf as *mut u8, + size: *size, + size_out: size, + }) + } + } + fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { std::slice::from_raw_parts_mut(self.buf, self.size) } + } + fn resize(&mut self) -> Result<()> { + let new_size = self.size * 2; + let new_buf = unsafe { + System.realloc( + self.buf, + Layout::from_size_align_unchecked(self.size, 1), + new_size, + ) + }; + if new_buf.is_null() { + Err(Status::AllocFailure) + } else { + self.buf = new_buf; + self.size = new_size; + if !self.size_out.is_null() { + unsafe { + *self.size_out = new_size; + } + } + Ok(()) + } + } +} /// C-style interface for demangling. -/// Demangles symbol given in `mangled` argument into `out` buffer +/// Demangles symbol given in `mangled` argument into `out` buffer. +/// +/// This interface is a drop-in replacement for `__cxa_demangle`, but for +/// Rust demangling. +/// +/// If `out` is null, a buffer will be allocated using the system allocator +/// to contain the results. +/// If `out` is non-null, `out_size` must be a pointer to the current size +/// of the buffer, and `out` must come from the system allocator. +/// If `out_size` is non-null, the size of the output buffer will be written +/// to it. +/// +/// If `status` is non-null, it will be set to one of the following values: +/// * 0: Demangling succeeded +/// * -1: Allocation failure +/// * -2: Name did not demangle +/// * -3: Invalid arguments +/// +/// Returns null if `mangled` is not Rust symbol or demangling failed. +/// Returns the buffer containing the demangled symbol name otherwise. /// /// Unsafe as it handles buffers by raw pointers. /// -/// Returns 0 if `mangled` is not Rust symbol or if `out` buffer is too small -/// Returns 1 otherwise +/// For non-null `out`, `out_size` represents a slight deviation from the +/// `__cxa_demangle` behavior. For `__cxa_demangle`, the buffer must be at +/// *least* the provided size. For `rustc_demangle`, it must be the exact +/// buffer size because it is used in the reconstruction of the `Layout` +/// for use with `::realloc`. #[no_mangle] pub unsafe extern "C" fn rustc_demangle( mangled: *const c_char, out: *mut c_char, - out_size: usize, -) -> c_int { + out_size: *mut usize, + status: *mut c_int, +) -> *mut c_char { + match rustc_demangle_native(mangled, out, out_size) { + Ok(demangled) => { + set_status(status, 0); + demangled + } + Err(e) => { + set_status(status, e as c_int); + ptr::null_mut() + } + } +} + +enum Status { + AllocFailure = -1, + DemangleFailure = -2, + InvalidArgs = -3, +} + +unsafe fn rustc_demangle_native( + mangled: *const c_char, + out: *mut c_char, + out_size: *mut usize, +) -> Result<*mut c_char> { + if mangled.is_null() { + return Err(Status::InvalidArgs); + } let mangled_str = match std::ffi::CStr::from_ptr(mangled).to_str() { Ok(s) => s, - Err(_) => return 0, + Err(_) => return Err(Status::InvalidArgs), }; + + if !out.is_null() { + if out_size.is_null() { + return Err(Status::InvalidArgs); + } + if *out_size == 0 { + return Err(Status::InvalidArgs); + } + } + + let mut out_buf = SystemBuffer::from_raw(out, out_size)?; + match rustc_demangle::try_demangle(mangled_str) { Ok(demangle) => { - let mut out_slice = std::slice::from_raw_parts_mut(out as *mut u8, out_size); - match write!(out_slice, "{:#}\0", demangle) { - Ok(_) => return 1, - Err(_) => return 0, + while write!(out_buf.as_mut_slice(), "{:#}\0", demangle).is_err() { + out_buf.resize()?; } + Ok(out_buf.as_mut_slice().as_mut_ptr() as *mut c_char) } - Err(_) => return 0, + Err(_) => Err(Status::DemangleFailure), } } #[cfg(test)] mod tests { - use std; - use std::os::raw::c_char; + use std::alloc::{GlobalAlloc, Layout, System}; + use std::os::raw::{c_char, c_int}; + use std::ptr; + + struct DemangleResult { + out_buf: *mut u8, + out_size: usize, + status: c_int, + } + + impl Drop for DemangleResult { + fn drop(&mut self) { + if !self.out_buf.is_null() { + unsafe { + System.dealloc( + self.out_buf, + Layout::from_size_align_unchecked(self.out_size, 1), + ); + } + } + } + } + + impl DemangleResult { + fn as_slice(&self) -> &[u8] { + unsafe { std::slice::from_raw_parts(self.out_buf, self.out_size) } + } + } + + fn demangle(mangled: &str, alloc_size: usize) -> DemangleResult { + unsafe { raw_demangle(mangled.as_ptr() as *const c_char, alloc_size) } + } + + unsafe fn raw_demangle(mangled: *const c_char, alloc_size: usize) -> DemangleResult { + let mut out_size: usize = alloc_size; + let mut status: c_int = 0; + let out_buf: *mut c_char = if out_size != 0 { + System.alloc(Layout::from_size_align_unchecked(out_size, 1)) as *mut c_char + } else { + ptr::null_mut() + }; + ptr::write_bytes(out_buf, '*' as u8, out_size); + + let res = super::rustc_demangle(mangled, out_buf, &mut out_size, &mut status); + DemangleResult { + out_buf: res as *mut u8, + out_size, + status, + } + } + #[test] fn demangle_c_str_large() { - let mangled = "_ZN4testE\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 8, - ) - }; - assert_eq!(res, 1); - let out_str = std::str::from_utf8(&out_buf[..5]).unwrap(); + let res = demangle("_ZN4testE\0", 8); + assert_eq!(res.status, 0); + let out_str = core::str::from_utf8(&res.as_slice()[..5]).unwrap(); assert_eq!(out_str, "test\0"); } #[test] fn demangle_c_str_exact() { - let mangled = "_ZN4testE\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 5, - ) - }; - assert_eq!(res, 1); - let out_str = std::str::from_utf8(&out_buf).unwrap(); + let res = demangle("_ZN4testE\0", 8); + assert_eq!(res.status, 0); + // No reallocation necessary, so our * fill should be present + let out_str = core::str::from_utf8(res.as_slice()).unwrap(); assert_eq!(out_str, "test\0***"); } #[test] fn demangle_c_str_small() { - let mangled = "_ZN4testE\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 4, - ) - }; - assert_eq!(res, 0); - let out_str = std::str::from_utf8(&out_buf[4..]).unwrap(); - assert_eq!(out_str, "****"); - } - - #[test] - fn demangle_c_str_smaller() { - let mangled = "_ZN4testE\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 3, - ) - }; - assert_eq!(res, 0); - let out_str = std::str::from_utf8(&out_buf[3..]).unwrap(); - assert_eq!(out_str, "*****"); + let res = demangle("_ZN4testE\0", 4); + assert_eq!(res.status, 0); + // demangle should have realloced + assert_ne!(res.out_size, 4); + // Only check the start, since the reallocation means our * fill may + // be absent. + let out_str = core::str::from_utf8(&res.as_slice()[..5]).unwrap(); + assert_eq!(out_str, "test\0"); } #[test] - fn demangle_c_str_zero() { - let mangled = "_ZN4testE\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 0, - ) - }; - assert_eq!(res, 0); - let out_str = std::str::from_utf8(&out_buf).unwrap(); - assert_eq!(out_str, "********"); + fn demangle_c_str_alloc() { + let res = demangle("_ZN4testE\0", 0); + assert_eq!(res.status, 0); + // demangle should have allocated + assert_ne!(res.out_size, 0); + let out_str = core::str::from_utf8(&res.as_slice()[..5]).unwrap(); + assert_eq!(out_str, "test\0"); } #[test] fn demangle_c_str_not_rust_symbol() { - let mangled = "la la la\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 8, - ) - }; - assert_eq!(res, 0); + let res = demangle("la la la\0", 8); + assert_eq!(res.status, -2); } #[test] fn demangle_c_str_null() { - let mangled = "\0"; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 8, - ) - }; - assert_eq!(res, 0); + let res = demangle("\0", 8); + assert_eq!(res.status, -2); } #[test] fn demangle_c_str_invalid_utf8() { let mangled = [116, 101, 115, 116, 165, 0]; - let mut out_buf: Vec<u8> = vec![42; 8]; - let res = unsafe { - super::rustc_demangle( - mangled.as_ptr() as *const c_char, - out_buf.as_mut_ptr() as *mut c_char, - 8, - ) - }; - assert_eq!(res, 0); + let res = unsafe { raw_demangle(mangled.as_ptr() as *const c_char, 8) }; + assert_eq!(res.status, -2); } } |