Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit e2326a1

Browse files
Treat a NULL return from dlsym as an error on illumos
This works around behavior observed on illumos in rust-lang#74469, in which foreign code (libc according to the OP) was racing with rustc to check `dlerror`.
1 parent 766fcb0 commit e2326a1

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

src/librustc_metadata/dynamic_lib.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,26 @@ mod dl {
107107
handle: *mut u8,
108108
symbol: *const libc::c_char,
109109
) -> Result<*mut u8, String> {
110+
// HACK(#74469): On some platforms, users observed foreign code
111+
// (specifically libc) invoking `dlopen`/`dlsym` in parallel with the
112+
// functions in this module. This is problematic because, according to
113+
// the POSIX API documentation, `dlerror` must be called to determine
114+
// whether `dlsym` succeeded. Unlike `dlopen`, a NULL return value may
115+
// indicate a successfully resolved symbol with an address of zero.
116+
//
117+
// Because symbols with address zero shouldn't occur in practice, we
118+
// treat them as errors on platforms with misbehaving libc
119+
// implementations.
120+
const DLSYM_NULL_IS_ERROR: bool = cfg!(target_os = "illumos");
121+
110122
let mut dlerror = error::lock();
111123

112-
// Flush `dlerror` since we need to use it to determine whether the subsequent call to
113-
// `dlsym` is successful.
114-
dlerror.clear();
124+
// No need to flush `dlerror` if we aren't using it to determine whether
125+
// the subsequent call to `dlsym` succeeded. If an error occurs, any
126+
// stale value will be overwritten.
127+
if !DLSYM_NULL_IS_ERROR {
128+
dlerror.clear();
129+
}
115130

116131
let ret = libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8;
117132

@@ -121,7 +136,12 @@ mod dl {
121136
return Ok(ret);
122137
}
123138

124-
dlerror.get().map(|()| ret)
139+
match dlerror.get() {
140+
Ok(()) if DLSYM_NULL_IS_ERROR => Err("Unknown error".to_string()),
141+
Ok(()) => Ok(ret),
142+
143+
Err(msg) => Err(msg),
144+
}
125145
}
126146

127147
pub(super) unsafe fn close(handle: *mut u8) {

0 commit comments

Comments
 (0)