extern crate rustc_demangle;
use std::io::Write;
use std::os::raw::{c_char, c_int};
/// C-style interface for demangling.
/// Demangles symbol given in `mangled` argument into `out` buffer
///
/// 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
#[no_mangle]
pub unsafe extern "C" fn rustc_demangle(
mangled: *const c_char,
out: *mut c_char,
out_size: usize,
) -> c_int {
let mangled_str = match std::ffi::CStr::from_ptr(mangled).to_str() {
Ok(s) => s,
Err(_) => return 0,
};
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,
}
}
Err(_) => return 0,
}
}
#[cfg(test)]
mod tests {
use std;
use std::os::raw::c_char;
#[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();
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();
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, "*****");
}
#[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, "********");
}
#[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);
}
#[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);
}
#[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);
}
}