From a06edda3ad9abd4f07d07bbe46cb488efeebbbd0 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 9 Sep 2020 10:16:03 -0400 Subject: [PATCH 1/2] Fix segfault if pthread_getattr_np fails glibc destroys[1] the passed pthread_attr_t if pthread_getattr_np() fails. Destroying it again leads to a segfault. Fix it by only destroying it on success for glibc. [1]: https://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_getattr_np.c;h=ce437205e41dc05653e435f6188768cccdd91c99;hb=HEAD#l205 --- library/std/src/sys/unix/thread.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 04da9812ddc45..569aedd741192 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -305,7 +305,9 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); ret = Some(stackaddr); } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(not(target_env = "gnu")) { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } @@ -446,7 +448,9 @@ pub mod guard { Some(stackaddr..stackaddr + guardsize) }; } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(not(target_env = "gnu")) { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } } From a684153f2920729f9fc3ea27ddb77d7cc3543214 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 9 Sep 2020 11:10:43 -0400 Subject: [PATCH 2/2] Only call pthread_attr_destroy() after getattr_np() succeeds on all libcs The calling convention of pthread_getattr_np() is to initialize the pthread_attr_t, so _destroy() is only necessary on success (and _init() isn't necessary beforehand). On the other hand, FreeBSD wants the attr_t to be initialized before pthread_attr_get_np(), and therefore it should always be destroyed afterwards. --- library/std/src/sys/unix/thread.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 569aedd741192..652219e28f6e0 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -294,6 +294,7 @@ pub mod guard { unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -305,7 +306,7 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); ret = Some(stackaddr); } - if e == 0 || cfg!(not(target_env = "gnu")) { + if e == 0 || cfg!(target_os = "freebsd") { assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); } ret @@ -405,6 +406,7 @@ pub mod guard { pub unsafe fn current() -> Option { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -448,7 +450,7 @@ pub mod guard { Some(stackaddr..stackaddr + guardsize) }; } - if e == 0 || cfg!(not(target_env = "gnu")) { + if e == 0 || cfg!(target_os = "freebsd") { assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); } ret