Do not encourage use of libloading for TLS

On MSVC Windows loading a TLS symbol will give an address to the
initializer (which when overwritten simply changes the default value new
threads gain for the variable).

On macOS thread locals are misimplemented entirely.

On Linux things "just work", but unknown to what extent, really.

Since the behaviour of using thread local variables as if they were
plain global variables is mostly undefined, lets just not make any
claims of this working.
This commit is contained in:
Simonas Kazlauskas
2020-08-22 20:09:10 +03:00
committed by Simonas Kazlauskas
parent bbc5028a88
commit f75a0d0606
6 changed files with 7 additions and 52 deletions
-6
View File
@@ -26,9 +26,6 @@ jobs:
profile: minimal
components: clippy
default: true
- name: Set LIBLOADING_TEST_NIGHTLY
run: echo "::set-env name=LIBLOADING_TEST_NIGHTLY::1"
if: ${{ matrix.rust_toolchain == 'nightly' }}
- name: Update
uses: actions-rs/cargo@v1
with:
@@ -73,9 +70,6 @@ jobs:
- i686-pc-windows-gnu
steps:
- uses: actions/checkout@v2
- name: Set LIBLOADING_TEST_NIGHTLY
run: echo "::set-env name=LIBLOADING_TEST_NIGHTLY::1"
if: ${{ matrix.rust_toolchain == 'nightly' }}
- name: Add MSYS2 to the PATH
run: echo "::add-path::c:/msys64/bin"
- name: Add 32-bit mingw-w64 to the PATH
-1
View File
@@ -67,5 +67,4 @@ fn main() {
"cargo:rustc-env=LIBLOADING_TEST_TARGET={}",
std::env::var("TARGET").expect("$TARGET is not set")
);
println!("cargo:rerun-if-env-changed=LIBLOADING_TEST_NIGHTLY");
}
+3 -3
View File
@@ -143,9 +143,9 @@ impl Library {
///
/// # Platform-specific behaviour
///
/// On Linux and Windows, a TLS variable acts just like any regular global variable. OS X uses
/// some sort of lazy initialization scheme, which makes loading TLS variables this way
/// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour.
/// Implementation of thread local variables is extremely platform specific and uses of these
/// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems or
/// Windows.
///
/// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
/// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call
+4 -4
View File
@@ -208,8 +208,8 @@ impl Library {
///
/// # Platform-specific behaviour
///
/// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables
/// impossible. Using a TLS variable loaded this way on OS X has no defined behaviour.
/// Implementation of thread local variables is extremely platform specific and uses of these
/// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems.
///
/// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such
/// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym`
@@ -244,8 +244,8 @@ impl Library {
///
/// # Platform-specific behaviour
///
/// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables
/// impossible. Using a TLS variable loaded this way on OS X has no defined behaviour.
/// Implementation of thread local variables is extremely platform specific and uses of these
/// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems.
#[inline(always)]
pub unsafe fn get_singlethreaded<T>(&self, symbol: &[u8]) -> Result<Symbol<T>, crate::Error> {
self.get_impl(symbol, || Ok(Symbol {
-12
View File
@@ -1,7 +1,6 @@
//! This is a separate file containing helpers for tests of this library. It is built into a
//! dynamic library by the build.rs script.
#![crate_type="cdylib"]
#![cfg_attr(thread_local, feature(thread_local))]
#[no_mangle]
pub static mut TEST_STATIC_U32: u32 = 0;
@@ -9,11 +8,6 @@ pub static mut TEST_STATIC_U32: u32 = 0;
#[no_mangle]
pub static mut TEST_STATIC_PTR: *mut () = 0 as *mut _;
#[cfg(thread_local)]
#[thread_local]
#[no_mangle]
pub static mut TEST_THREAD_LOCAL: u32 = 0;
#[no_mangle]
pub extern "C" fn test_identity_u32(x: u32) -> u32 {
x
@@ -41,9 +35,3 @@ pub unsafe extern "C" fn test_get_static_u32() -> u32 {
pub unsafe extern "C" fn test_check_static_ptr() -> bool {
TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _)
}
#[cfg(thread_local)]
#[no_mangle]
pub unsafe extern "C" fn test_get_thread_local() -> u32 {
TEST_THREAD_LOCAL
}
-26
View File
@@ -18,9 +18,6 @@ fn make_helpers() {
.arg("--target")
.arg(env!("LIBLOADING_TEST_TARGET"))
.arg("-O");
if std::env::var_os("LIBLOADING_TEST_NIGHTLY").is_some() {
cmd.arg("--cfg").arg("thread_local");
}
cmd
.output()
@@ -145,29 +142,6 @@ fn test_static_ptr() {
}
}
#[cfg(any(windows, target_os="linux"))]
#[test]
fn test_tls_static() {
make_helpers();
let lib = Library::new(LIBPATH).unwrap();
if std::env::var_os("LIBLOADING_TEST_NIGHTLY").is_some() {
unsafe {
let var: Symbol<*mut u32> = lib.get(b"TEST_THREAD_LOCAL\0").unwrap();
**var = 84;
let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_thread_local\0").unwrap();
assert_eq!(84, help());
}
::std::thread::spawn(move || unsafe {
let help: Symbol<unsafe extern fn() -> u32> = lib.get(b"test_get_thread_local\0").unwrap();
assert_eq!(0, help());
}).join().unwrap();
} else {
unsafe {
assert!(lib.get::<Symbol<*mut u32>>(b"TEST_THREAD_LOCAL\0").is_err());
}
}
}
#[cfg(unix)]
#[test]
fn library_this_get() {