aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShengYi Hung <aokblast@FreeBSD.org>2026-11-05 00:03:01 +0000
committerShengYi Hung <aokblast@FreeBSD.org>2026-11-05 16:01:55 +0000
commit2734bbbcba3cd6ff2bf4382fb6e85b884beb966e (patch)
tree9be632c3180758b08c908da5b0cdb612deb03c3a
parent71937d8e11a6b7fdb3c1b308d5f7c8b30dac5ca7 (diff)
libthr: Create landing pad in thr_once in C++ exception
In _thr_once, if init_routine fails with exception, the stack allocate __cup will become invalid when unwinder walk back and free the stack of thr_once. This cause cleanup linked list be dangling. In here, we give the cleanup function a landing pad so that we td can correctly point to previous cleanup function. Reviewed by: kib MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D61212
-rw-r--r--lib/libthr/thread/thr_private.h16
1 files changed, 15 insertions, 1 deletions
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 3cc0fe61de00..9ea56b5b8a35 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -249,7 +249,9 @@ struct pthread_cleanup {
};
#define THR_CLEANUP_PUSH(td, func, arg) { \
- struct pthread_cleanup __cup; \
+ struct pthread_cleanup __cup \
+ __attribute__((__cleanup__( \
+ _thr_cleanup_unwind))); \
\
__cup.routine = func; \
__cup.routine_arg = arg; \
@@ -949,6 +951,18 @@ _thr_check_init(void)
_libpthread_init(NULL);
}
+static inline void
+_thr_cleanup_unwind(struct pthread_cleanup *cup)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+ if (curthread->cleanup == cup) {
+ curthread->cleanup = cup->prev;
+ cup->routine(cup->routine_arg);
+ }
+}
+
struct wake_addr *_thr_alloc_wake_addr(void);
void _thr_release_wake_addr(struct wake_addr *);
int _thr_sleep(struct pthread *, int, const struct timespec *);