Enum Mode

Source
#[repr(i8)]
pub enum Mode { Native = 0, NativeTlsId = 1, Gettid = 2, }
Expand description

Modes of operation for this module.

Variants§

§

Native = 0

Delegate back to ELF native thread local storage. This is the fastest option, and simplest with respect to our own code, but is unsound. We should probably ultimately disable or remove it.

In native thread local storage for ELF executables, an access to a thread-local variable (with C storage specifier __thread) from a dynamically shared object (like the Shadow shim) involves implicitly calling the libc function __tls_get_addr. That function is not guaranteed to be async-signal-safe (See signal-safety(7)), and can end up making system calls and doing memory allocation. This has caused problems with some versions of glibc (Can’t find the issue #…), and recently when running managed processed compiled with asan https://github.com/shadow/shadow/issues/2790.

SAFETY: __tls_get_addr in the linked version of libc must not make system calls or do anything async-signal unsafe. This basically can’t be ensured, but is often true in practice.

§

NativeTlsId = 1

This mode takes advantage of ELF native thread local storage, but only leverages it as a cheap-to-retrieve thread identifier. It does not call into libc or store anything directly in the native thread local storage.

In particular, based on 3.4.6 and 3.4.2 of [ELF-TLS], we know that we can retrieve the “thread pointer” by loading offset zero of the fs register; i.e. %fs:0.

The contents of the data pointed to by the thread pointer are an implementation detail of the compiler, linker, and libc, so we don’t depend on it. However it seems reasonable to assume that this address is unique to each live thread, and doesn’t change during the lifetime of a thread. Therefore we use the address as a thread-identifier, which we in turn use as key to our own allocated thread-local-storage.

This mode is nearly as fast as native, but:

  • Assumes that if the “thread pointer” in %fs:0 is non-NULL for a given thread, that it is stable and unique for the lifetime of that thread. This seems like a fairly reasonable assumption, and seems to hold so far, but isn’t guaranteed.
  • Requires that each thread using thread local storage from this module calls ThreadLocalStorage::unregister_current_thread before exiting, since the thread pointer may subsequently be used for another thread.

[ELF-TLS]: “ELF Handling For Thread-Local Storage”, by Ulrich Drepper. https://www.akkadia.org/drepper/tls.pdf

SAFETY: Requires that each thread using this thread local storage calls ThreadLocalStorage::unregister_current_thread before exiting.

§

Gettid = 2

This mode is similar to NativeTlsId, but instead of using the ELF thread pointer to identify each thread, it uses the system thread ID as retrieved by the gettid syscall.

Unlike NativeTlsId, this approach doesn’t rely on any assumptions about the implementation details of thread local storage in the managed process. It also usually still works without calling ThreadLocalStorage::unregister_current_thread, but technically still requires it to guarantee soundness, since thread

Unfortunately this mode is much slower than the others.

SAFETY: Each thread using this thread local storage must call ThreadLocalStorage::unregister_current_thread before exiting.

Trait Implementations§

Source§

impl Clone for Mode

Source§

fn clone(&self) -> Mode

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Mode

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl From<Mode> for i8

Source§

fn from(enum_value: Mode) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for Mode

Source§

fn eq(&self, other: &Mode) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl TryFrom<i8> for Mode

Source§

type Error = TryFromPrimitiveError<Mode>

The type returned in the event of a conversion error.
Source§

fn try_from(number: i8) -> Result<Self, TryFromPrimitiveError<Self>>

Performs the conversion.
Source§

impl TryFromPrimitive for Mode

Source§

impl Copy for Mode

Source§

impl Eq for Mode

Source§

impl StructuralPartialEq for Mode

Auto Trait Implementations§

§

impl Freeze for Mode

§

impl RefUnwindSafe for Mode

§

impl Send for Mode

§

impl Sync for Mode

§

impl Unpin for Mode

§

impl UnwindSafe for Mode

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> NoTypeInference for T

Source§

type This = T

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V