Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C API wrapper #14

Merged
merged 9 commits into from
Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}