Skip to content

Commit 1b09d21

Browse files
committed
Use CStr as the type for symbol name
1 parent 6bdd37f commit 1b09d21

File tree

9 files changed

+58
-113
lines changed

9 files changed

+58
-113
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ description = "Bindings around the platform's dynamic library loading primitives
1313
keywords = ["dlopen", "load", "shared", "dylib"]
1414
categories = ["api-bindings"]
1515
rust-version = "1.56.0"
16-
edition = "2015"
16+
edition = "2021"
1717

1818
[target.'cfg(windows)'.dependencies.windows-targets]
1919
version = ">=0.48, <0.54"

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
//! fn call_dynamic() -> Result<u32, Box<dyn std::error::Error>> {
2828
//! unsafe {
2929
//! let lib = libloading::Library::new("/path/to/liblibrary.so")?;
30-
//! let func: libloading::Symbol<unsafe extern fn() -> u32> = lib.get(b"my_func")?;
30+
//! let func: libloading::Symbol<unsafe extern fn() -> u32> = lib.get(c"my_func")?;
3131
//! Ok(func())
3232
//! }
3333
//! }

src/os/unix/consts.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,7 @@ mod posix {
5454

5555
#[cfg(any(not(libloading_docs), unix))]
5656
mod posix {
57-
extern crate cfg_if;
58-
use self::cfg_if::cfg_if;
57+
use cfg_if::cfg_if;
5958
use super::c_int;
6059
cfg_if! {
6160
if #[cfg(target_os = "haiku")] {

src/os/unix/mod.rs

+27-13
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ mod unix_imports {
88
}
99

1010
pub use self::consts::*;
11+
use crate::error::Error;
12+
use crate::util::ensure_compatible_types;
1113
use self::unix_imports::*;
12-
use std::ffi::{CStr, OsStr};
14+
use std::borrow::Cow;
15+
use std::ffi::{CStr, CString, OsStr};
1316
use std::os::raw;
1417
use std::{fmt, marker, mem, ptr};
15-
use util::{cstr_cow_from_bytes, ensure_compatible_types};
1618

1719
mod consts;
1820

@@ -181,6 +183,25 @@ impl Library {
181183
where
182184
P: AsRef<OsStr>,
183185
{
186+
/// Checks for the last byte and avoids allocating if it is zero.
187+
///
188+
/// Non-last null bytes still result in an error.
189+
fn cstr_cow_from_bytes(slice: &[u8]) -> Result<Cow<'_, CStr>, Error> {
190+
Ok(match slice.last() {
191+
// Slice out of 0 elements
192+
None => Cow::Borrowed(c""),
193+
// Slice with trailing 0
194+
Some(&0) => Cow::Borrowed(
195+
CStr::from_bytes_with_nul(slice)
196+
.map_err(|source| Error::CreateCStringWithTrailing { source })?,
197+
),
198+
// Slice with no trailing 0
199+
Some(_) => {
200+
Cow::Owned(CString::new(slice).map_err(|source| Error::CreateCString { source })?)
201+
}
202+
})
203+
}
204+
184205
let filename = match filename {
185206
None => None,
186207
Some(ref f) => Some(cstr_cow_from_bytes(f.as_ref().as_bytes())?),
@@ -207,12 +228,12 @@ impl Library {
207228
.map_err(|e| e.unwrap_or(crate::Error::DlOpenUnknown))
208229
}
209230

210-
unsafe fn get_impl<T, F>(&self, symbol: &[u8], on_null: F) -> Result<Symbol<T>, crate::Error>
231+
unsafe fn get_impl<T, F>(&self, symbol: &CStr, on_null: F) -> Result<Symbol<T>, crate::Error>
211232
where
212233
F: FnOnce() -> Result<Symbol<T>, crate::Error>,
213234
{
214235
ensure_compatible_types::<T, *mut raw::c_void>()?;
215-
let symbol = cstr_cow_from_bytes(symbol)?;
236+
216237
// `dlsym` may return nullptr in two cases: when a symbol genuinely points to a null
217238
// pointer or the symbol cannot be found. In order to detect this case a double dlerror
218239
// pattern must be used, which is, sadly, a little bit racy.
@@ -243,9 +264,6 @@ impl Library {
243264

244265
/// Get a pointer to a function or static variable by symbol name.
245266
///
246-
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
247-
/// null terminated `symbol` may help to avoid an allocation.
248-
///
249267
/// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
250268
/// most likely invalid.
251269
///
@@ -265,8 +283,7 @@ impl Library {
265283
/// pointer without it being an error. If loading a null pointer is something you care about,
266284
/// consider using the [`Library::get_singlethreaded`] call.
267285
#[inline(always)]
268-
pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
269-
extern crate cfg_if;
286+
pub unsafe fn get<T>(&self, symbol: &CStr) -> Result<Symbol<T>, crate::Error> {
270287
cfg_if::cfg_if! {
271288
// These targets are known to have MT-safe `dlerror`.
272289
if #[cfg(any(
@@ -289,9 +306,6 @@ impl Library {
289306

290307
/// Get a pointer to function or static variable by symbol name.
291308
///
292-
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
293-
/// null terminated `symbol` may help to avoid an allocation.
294-
///
295309
/// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
296310
/// most likely invalid.
297311
///
@@ -308,7 +322,7 @@ impl Library {
308322
/// The implementation of thread-local variables is extremely platform specific and uses of such
309323
/// variables that work on e.g. Linux may have unintended behaviour on other targets.
310324
#[inline(always)]
311-
pub unsafe fn get_singlethreaded<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
325+
pub unsafe fn get_singlethreaded<T>(&self, symbol: &CStr) -> Result<Symbol<T>, crate::Error> {
312326
self.get_impl(symbol, || {
313327
Ok(Symbol {
314328
pointer: ptr::null_mut(),

src/os/windows/mod.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ mod windows_imports {
1515
windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(module: HMODULE, procname: *const u8) -> FARPROC);
1616
}
1717

18+
use crate::util::ensure_compatible_types;
1819
use self::windows_imports::*;
19-
use util::{ensure_compatible_types, cstr_cow_from_bytes};
20-
use std::ffi::{OsStr, OsString};
20+
use std::ffi::{CStr, OsStr, OsString};
2121
use std::{fmt, io, marker, mem, ptr};
2222
use std::os::raw;
2323

@@ -173,18 +173,15 @@ impl Library {
173173

174174
/// Get a pointer to a function or static variable by symbol name.
175175
///
176-
/// The `symbol` may not contain any null bytes, with the exception of the last byte. A null
177-
/// terminated `symbol` may avoid a string allocation in some cases.
178-
///
179176
/// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
180177
/// most likely invalid.
181178
///
182179
/// # Safety
183180
///
184181
/// Users of this API must specify the correct type of the function or variable loaded.
185-
pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
182+
pub unsafe fn get<T>(&self, symbol: &CStr) -> Result<Symbol<T>, crate::Error> {
186183
ensure_compatible_types::<T, FARPROC>()?;
187-
let symbol = cstr_cow_from_bytes(symbol)?;
184+
188185
with_get_last_error(|source| crate::Error::GetProcAddress { source }, || {
189186
let symbol = GetProcAddress(self.0, symbol.as_ptr().cast());
190187
if symbol.is_none() {

src/safe.rs

+7-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::os::unix as imp;
55
#[cfg(all(not(libloading_docs), windows))]
66
use super::os::windows as imp;
77
use super::Error;
8-
use std::ffi::OsStr;
8+
use std::ffi::{CStr, OsStr};
99
use std::fmt;
1010
use std::marker;
1111
use std::ops;
@@ -87,9 +87,6 @@ impl Library {
8787

8888
/// Get a pointer to a function or static variable by symbol name.
8989
///
90-
/// The `symbol` may not contain any null bytes, with the exception of the last byte. Providing a
91-
/// null-terminated `symbol` may help to avoid an allocation.
92-
///
9390
/// The symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are
9491
/// most likely invalid.
9592
///
@@ -130,7 +127,7 @@ impl Library {
130127
/// # };
131128
/// unsafe {
132129
/// let awesome_function: Symbol<unsafe extern fn(f64) -> f64> =
133-
/// lib.get(b"awesome_function\0").unwrap();
130+
/// lib.get(c"awesome_function").unwrap();
134131
/// awesome_function(0.42);
135132
/// }
136133
/// ```
@@ -141,11 +138,11 @@ impl Library {
141138
/// # use ::libloading::{Library, Symbol};
142139
/// # let lib = unsafe { Library::new("/path/to/awesome.module").unwrap() };
143140
/// unsafe {
144-
/// let awesome_variable: Symbol<*mut f64> = lib.get(b"awesome_variable\0").unwrap();
141+
/// let awesome_variable: Symbol<*mut f64> = lib.get(c"awesome_variable").unwrap();
145142
/// **awesome_variable = 42.0;
146143
/// };
147144
/// ```
148-
pub unsafe fn get<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, Error> {
145+
pub unsafe fn get<T>(&self, symbol: &CStr) -> Result<Symbol<T>, Error> {
149146
self.0.get(symbol).map(|from| Symbol::from_raw(from, self))
150147
}
151148

@@ -215,7 +212,7 @@ impl<'lib, T> Symbol<'lib, T> {
215212
/// # use ::libloading::{Library, Symbol};
216213
/// unsafe {
217214
/// let lib = Library::new("/path/to/awesome.module").unwrap();
218-
/// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
215+
/// let symbol: Symbol<*mut u32> = lib.get(c"symbol").unwrap();
219216
/// let symbol = symbol.into_raw();
220217
/// }
221218
/// ```
@@ -238,7 +235,7 @@ impl<'lib, T> Symbol<'lib, T> {
238235
/// # use ::libloading::{Library, Symbol};
239236
/// unsafe {
240237
/// let lib = Library::new("/path/to/awesome.module").unwrap();
241-
/// let symbol: Symbol<*mut u32> = lib.get(b"symbol\0").unwrap();
238+
/// let symbol: Symbol<*mut u32> = lib.get(c"symbol").unwrap();
242239
/// let symbol = symbol.into_raw();
243240
/// let symbol = Symbol::from_raw(symbol, &lib);
244241
/// }
@@ -280,7 +277,7 @@ impl<'lib, T> Symbol<'lib, Option<T>> {
280277
/// # use ::libloading::{Library, Symbol};
281278
/// unsafe {
282279
/// let lib = Library::new("/path/to/awesome.module").unwrap();
283-
/// let symbol: Symbol<Option<*mut u32>> = lib.get(b"symbol\0").unwrap();
280+
/// let symbol: Symbol<Option<*mut u32>> = lib.get(c"symbol").unwrap();
284281
/// let symbol: Symbol<*mut u32> = symbol.lift_option().expect("static is not null");
285282
/// }
286283
/// ```

src/test_helpers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ pub unsafe extern "C" fn test_get_static_u32() -> u32 {
3333

3434
#[no_mangle]
3535
pub unsafe extern "C" fn test_check_static_ptr() -> bool {
36-
TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _)
36+
TEST_STATIC_PTR == (&raw mut TEST_STATIC_PTR as *mut *mut _ as *mut _)
3737
}

src/util.rs

-24
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,5 @@
1-
use std::borrow::Cow;
2-
use std::ffi::{CStr, CString};
3-
use std::os::raw;
4-
51
use crate::Error;
62

7-
/// Checks for the last byte and avoids allocating if it is zero.
8-
///
9-
/// Non-last null bytes still result in an error.
10-
pub(crate) fn cstr_cow_from_bytes(slice: &[u8]) -> Result<Cow<'_, CStr>, Error> {
11-
static ZERO: raw::c_char = 0;
12-
Ok(match slice.last() {
13-
// Slice out of 0 elements
14-
None => unsafe { Cow::Borrowed(CStr::from_ptr(&ZERO)) },
15-
// Slice with trailing 0
16-
Some(&0) => Cow::Borrowed(
17-
CStr::from_bytes_with_nul(slice)
18-
.map_err(|source| Error::CreateCStringWithTrailing { source })?,
19-
),
20-
// Slice with no trailing 0
21-
Some(_) => {
22-
Cow::Owned(CString::new(slice).map_err(|source| Error::CreateCString { source })?)
23-
}
24-
})
25-
}
26-
273
#[inline]
284
pub(crate) fn ensure_compatible_types<T, E>() -> Result<(), Error> {
295
if ::std::mem::size_of::<T>() != ::std::mem::size_of::<E>() {

0 commit comments

Comments
 (0)