Skip to content

Commit

Permalink
C API wrapper (#14)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
zokier authored and alexcrichton committed Dec 9, 2019
1 parent b2f44f8 commit 1ccd9b4
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 1 deletion.
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 11 additions & 0 deletions crates/capi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "rustc-demangle-capi"
version = "0.1.0"
authors = ["Torste Aikio <zokier@gmail.com>"]

[lib]
name = "rustc_demangle"
crate-type = ["staticlib", "cdylib"]

[dependencies]
rustc-demangle = { version = "0.1.16", path = "../.." }
18 changes: 18 additions & 0 deletions crates/capi/include/rustc_demangle.h
Original file line number Diff line number Diff line change
@@ -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_
160 changes: 160 additions & 0 deletions crates/capi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<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);
}
}

0 comments on commit 1ccd9b4

Please sign in to comment.