Auto merge of #126606 - zachs18:patch-2, r=joboet · model-checking/verify-rust-std@206678c (original) (raw)

``

1

`+

cfg_if::cfg_if! {

`

``

2

`+

if #[cfg(target_os = "linux")] {

`

``

3

`+

/// pthread_t is a pointer on some platforms,

`

``

4

`+

/// so we wrap it in this to impl Send + Sync.

`

``

5

`+

#[derive(Clone, Copy)]

`

``

6

`+

#[repr(transparent)]

`

``

7

`+

struct PThread(libc::pthread_t);

`

``

8

`+

// Safety: pthread_t is safe to send between threads

`

``

9

`+

unsafe impl Send for PThread {}

`

``

10

`+

// Safety: pthread_t is safe to share between threads

`

``

11

`+

unsafe impl Sync for PThread {}

`

``

12

`+

/// Mitigation for https://github.com/rust-lang/rust/issues/126600

`

``

13

`+

///

`

``

14

`` +

/// On glibc, libc::exit has been observed to not always be thread-safe.

``

``

15

`+

/// It is currently unclear whether that is a glibc bug or allowed by the standard.

`

``

16

`+

/// To mitigate this problem, we ensure that only one

`

``

17

`` +

/// Rust thread calls libc::exit (or returns from main) by calling this function before

``

``

18

`` +

/// calling libc::exit (or returning from main).

``

``

19

`+

///

`

``

20

`+

/// Technically, this is not enough to ensure soundness, since other code directly calling

`

``

21

`` +

/// libc::exit will still race with this.

``

``

22

`+

///

`

``

23

`` +

/// This function does not itself call libc::exit. This is so it can also be used

``

``

24

`` +

/// to guard returning from main.

``

``

25

`+

///

`

``

26

`+

/// This function will return only the first time it is called in a process.

`

``

27

`+

///

`

``

28

`+

/// * If it is called again on the same thread as the first call, it will abort.

`

``

29

`+

/// * If it is called again on a different thread, it will wait in a loop

`

``

30

`+

/// (waiting for the process to exit).

`

``

31

`+

#[cfg_attr(any(test, doctest), allow(dead_code))]

`

``

32

`+

pub(crate) fn unique_thread_exit() {

`

``

33

`+

let this_thread_id = unsafe { libc::pthread_self() };

`

``

34

`+

use crate::sync::{Mutex, PoisonError};

`

``

35

`+

static EXITING_THREAD_ID: Mutex<Option> = Mutex::new(None);

`

``

36

`+

let mut exiting_thread_id =

`

``

37

`+

EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner);

`

``

38

`+

match *exiting_thread_id {

`

``

39

`+

None => {

`

``

40

`` +

// This is the first thread to call unique_thread_exit,

``

``

41

`+

// and this is the first time it is called.

`

``

42

`+

// Set EXITING_THREAD_ID to this thread's ID and return.

`

``

43

`+

*exiting_thread_id = Some(PThread(this_thread_id));

`

``

44

`+

},

`

``

45

`+

Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => {

`

``

46

`` +

// This is the first thread to call unique_thread_exit,

``

``

47

`+

// but this is the second time it is called.

`

``

48

`+

// Abort the process.

`

``

49

`+

core::panicking::panic_nounwind("std::process::exit called re-entrantly")

`

``

50

`+

}

`

``

51

`+

Some(_) => {

`

``

52

`` +

// This is not the first thread to call unique_thread_exit.

``

``

53

`+

// Pause until the process exits.

`

``

54

`+

drop(exiting_thread_id);

`

``

55

`+

loop {

`

``

56

`+

// Safety: libc::pause is safe to call.

`

``

57

`+

unsafe { libc::pause(); }

`

``

58

`+

}

`

``

59

`+

}

`

``

60

`+

}

`

``

61

`+

}

`

``

62

`+

} else {

`

``

63

`+

/// Mitigation for https://github.com/rust-lang/rust/issues/126600

`

``

64

`+

///

`

``

65

`+

/// Mitigation is NOT implemented on this platform, either because this platform

`

``

66

`+

/// is not affected, or because mitigation is not yet implemented for this platform.

`

``

67

`+

#[cfg_attr(any(test, doctest), allow(dead_code))]

`

``

68

`+

pub(crate) fn unique_thread_exit() {

`

``

69

`` +

// Mitigation not required on platforms where exit is thread-safe.

``

``

70

`+

}

`

``

71

`+

}

`

``

72

`+

}

`