Skip to content

Commit 1ccd9b4

Browse files
zokieralexcrichton
authored andcommitted
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
1 parent b2f44f8 commit 1ccd9b4

File tree

5 files changed

+197
-1
lines changed

5 files changed

+197
-1
lines changed

.github/workflows/main.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ jobs:
1212
- uses: actions/checkout@master
1313
- name: Install Rust
1414
run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
15-
- run: cargo test
15+
- run: cargo build --all
16+
- run: cargo test --all
1617

1718
rustfmt:
1819
name: Rustfmt

Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@ description = """
1111
Rust compiler symbol demangling.
1212
"""
1313

14+
[workspace]
15+
members = ["crates/capi"]
16+
1417
[dependencies]
1518
core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' }
1619
compiler_builtins = { version = '0.1.2', optional = true }
1720

1821
[features]
1922
rustc-dep-of-std = ['core', 'compiler_builtins']
23+
24+
[profile.release]
25+
lto = true

crates/capi/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "rustc-demangle-capi"
3+
version = "0.1.0"
4+
authors = ["Torste Aikio <[email protected]>"]
5+
6+
[lib]
7+
name = "rustc_demangle"
8+
crate-type = ["staticlib", "cdylib"]
9+
10+
[dependencies]
11+
rustc-demangle = { version = "0.1.16", path = "../.." }

crates/capi/include/rustc_demangle.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef RUST_DEMANGLE_H_
2+
#define RUST_DEMANGLE_H_
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
// Demangles symbol given in `mangled` argument into `out` buffer
9+
//
10+
// Returns 0 if `mangled` is not Rust symbol or if `out` buffer is too small
11+
// Returns 1 otherwise
12+
int rustc_demangle(const char *mangled, char *out, size_t out_size);
13+
14+
#ifdef __cplusplus
15+
}
16+
#endif
17+
18+
#endif // RUSTC_DEMANGLE_H_

crates/capi/src/lib.rs

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
extern crate rustc_demangle;
2+
3+
use std::io::Write;
4+
use std::os::raw::{c_char, c_int};
5+
6+
/// C-style interface for demangling.
7+
/// Demangles symbol given in `mangled` argument into `out` buffer
8+
///
9+
/// Unsafe as it handles buffers by raw pointers.
10+
///
11+
/// Returns 0 if `mangled` is not Rust symbol or if `out` buffer is too small
12+
/// Returns 1 otherwise
13+
#[no_mangle]
14+
pub unsafe extern "C" fn rustc_demangle(
15+
mangled: *const c_char,
16+
out: *mut c_char,
17+
out_size: usize,
18+
) -> c_int {
19+
let mangled_str = match std::ffi::CStr::from_ptr(mangled).to_str() {
20+
Ok(s) => s,
21+
Err(_) => return 0,
22+
};
23+
match rustc_demangle::try_demangle(mangled_str) {
24+
Ok(demangle) => {
25+
let mut out_slice = std::slice::from_raw_parts_mut(out as *mut u8, out_size);
26+
match write!(out_slice, "{:#}\0", demangle) {
27+
Ok(_) => return 1,
28+
Err(_) => return 0,
29+
}
30+
}
31+
Err(_) => return 0,
32+
}
33+
}
34+
35+
#[cfg(test)]
36+
mod tests {
37+
use std;
38+
use std::os::raw::c_char;
39+
#[test]
40+
fn demangle_c_str_large() {
41+
let mangled = "_ZN4testE\0";
42+
let mut out_buf: Vec<u8> = vec![42; 8];
43+
let res = unsafe {
44+
super::rustc_demangle(
45+
mangled.as_ptr() as *const c_char,
46+
out_buf.as_mut_ptr() as *mut c_char,
47+
8,
48+
)
49+
};
50+
assert_eq!(res, 1);
51+
let out_str = std::str::from_utf8(&out_buf[..5]).unwrap();
52+
assert_eq!(out_str, "test\0");
53+
}
54+
55+
#[test]
56+
fn demangle_c_str_exact() {
57+
let mangled = "_ZN4testE\0";
58+
let mut out_buf: Vec<u8> = vec![42; 8];
59+
let res = unsafe {
60+
super::rustc_demangle(
61+
mangled.as_ptr() as *const c_char,
62+
out_buf.as_mut_ptr() as *mut c_char,
63+
5,
64+
)
65+
};
66+
assert_eq!(res, 1);
67+
let out_str = std::str::from_utf8(&out_buf).unwrap();
68+
assert_eq!(out_str, "test\0***");
69+
}
70+
71+
#[test]
72+
fn demangle_c_str_small() {
73+
let mangled = "_ZN4testE\0";
74+
let mut out_buf: Vec<u8> = vec![42; 8];
75+
let res = unsafe {
76+
super::rustc_demangle(
77+
mangled.as_ptr() as *const c_char,
78+
out_buf.as_mut_ptr() as *mut c_char,
79+
4,
80+
)
81+
};
82+
assert_eq!(res, 0);
83+
let out_str = std::str::from_utf8(&out_buf[4..]).unwrap();
84+
assert_eq!(out_str, "****");
85+
}
86+
87+
#[test]
88+
fn demangle_c_str_smaller() {
89+
let mangled = "_ZN4testE\0";
90+
let mut out_buf: Vec<u8> = vec![42; 8];
91+
let res = unsafe {
92+
super::rustc_demangle(
93+
mangled.as_ptr() as *const c_char,
94+
out_buf.as_mut_ptr() as *mut c_char,
95+
3,
96+
)
97+
};
98+
assert_eq!(res, 0);
99+
let out_str = std::str::from_utf8(&out_buf[3..]).unwrap();
100+
assert_eq!(out_str, "*****");
101+
}
102+
103+
#[test]
104+
fn demangle_c_str_zero() {
105+
let mangled = "_ZN4testE\0";
106+
let mut out_buf: Vec<u8> = vec![42; 8];
107+
let res = unsafe {
108+
super::rustc_demangle(
109+
mangled.as_ptr() as *const c_char,
110+
out_buf.as_mut_ptr() as *mut c_char,
111+
0,
112+
)
113+
};
114+
assert_eq!(res, 0);
115+
let out_str = std::str::from_utf8(&out_buf).unwrap();
116+
assert_eq!(out_str, "********");
117+
}
118+
119+
#[test]
120+
fn demangle_c_str_not_rust_symbol() {
121+
let mangled = "la la la\0";
122+
let mut out_buf: Vec<u8> = vec![42; 8];
123+
let res = unsafe {
124+
super::rustc_demangle(
125+
mangled.as_ptr() as *const c_char,
126+
out_buf.as_mut_ptr() as *mut c_char,
127+
8,
128+
)
129+
};
130+
assert_eq!(res, 0);
131+
}
132+
133+
#[test]
134+
fn demangle_c_str_null() {
135+
let mangled = "\0";
136+
let mut out_buf: Vec<u8> = vec![42; 8];
137+
let res = unsafe {
138+
super::rustc_demangle(
139+
mangled.as_ptr() as *const c_char,
140+
out_buf.as_mut_ptr() as *mut c_char,
141+
8,
142+
)
143+
};
144+
assert_eq!(res, 0);
145+
}
146+
147+
#[test]
148+
fn demangle_c_str_invalid_utf8() {
149+
let mangled = [116, 101, 115, 116, 165, 0];
150+
let mut out_buf: Vec<u8> = vec![42; 8];
151+
let res = unsafe {
152+
super::rustc_demangle(
153+
mangled.as_ptr() as *const c_char,
154+
out_buf.as_mut_ptr() as *mut c_char,
155+
8,
156+
)
157+
};
158+
assert_eq!(res, 0);
159+
}
160+
}

0 commit comments

Comments
 (0)