From 1ccd9b42764b4da98666628dfa933b62d5c79592 Mon Sep 17 00:00:00 2001 From: Torste Aikio Date: Mon, 9 Dec 2019 20:10:08 +0200 Subject: [PATCH] C API wrapper (#14) * std based C API * Build and test C API with Travis * Use full lto for release profile * Add CI for GitHub Actions * Move demangle crate to a `crates` directory * Run rustfmt * Use a `match` instead of `unwrap` * Run rustfmt --- .github/workflows/main.yml | 3 +- Cargo.toml | 6 + crates/capi/Cargo.toml | 11 ++ crates/capi/include/rustc_demangle.h | 18 +++ crates/capi/src/lib.rs | 160 +++++++++++++++++++++++++++ 5 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 crates/capi/Cargo.toml create mode 100644 crates/capi/include/rustc_demangle.h create mode 100644 crates/capi/src/lib.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c242c5b..61465ce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,8 @@ jobs: - uses: actions/checkout@master - name: Install Rust run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} - - run: cargo test + - run: cargo build --all + - run: cargo test --all rustfmt: name: Rustfmt diff --git a/Cargo.toml b/Cargo.toml index 5b5a4e9..0701278 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,15 @@ description = """ Rust compiler symbol demangling. """ +[workspace] +members = ["crates/capi"] + [dependencies] core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } compiler_builtins = { version = '0.1.2', optional = true } [features] rustc-dep-of-std = ['core', 'compiler_builtins'] + +[profile.release] +lto = true diff --git a/crates/capi/Cargo.toml b/crates/capi/Cargo.toml new file mode 100644 index 0000000..0f1fb07 --- /dev/null +++ b/crates/capi/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rustc-demangle-capi" +version = "0.1.0" +authors = ["Torste Aikio "] + +[lib] +name = "rustc_demangle" +crate-type = ["staticlib", "cdylib"] + +[dependencies] +rustc-demangle = { version = "0.1.16", path = "../.." } diff --git a/crates/capi/include/rustc_demangle.h b/crates/capi/include/rustc_demangle.h new file mode 100644 index 0000000..61c4aa1 --- /dev/null +++ b/crates/capi/include/rustc_demangle.h @@ -0,0 +1,18 @@ +#ifndef RUST_DEMANGLE_H_ +#define RUST_DEMANGLE_H_ + +#ifdef __cplusplus +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); + +#ifdef __cplusplus +} +#endif + +#endif // RUSTC_DEMANGLE_H_ diff --git a/crates/capi/src/lib.rs b/crates/capi/src/lib.rs new file mode 100644 index 0000000..51e3103 --- /dev/null +++ b/crates/capi/src/lib.rs @@ -0,0 +1,160 @@ +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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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); + } +}