From b1355352d14a0a67107aba7ec6f233336f17716a Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Fri, 30 Nov 2018 07:32:12 -0800 Subject: [PATCH] bpo-33015: Fix UB in pthread PyThread_start_new_thread (GH-6008) Fix an undefined behaviour in the pthread implementation of PyThread_start_new_thread(): add a function wrapper to always return NULL. Add pythread_callback struct and pythread_wrapper() to thread_pthread.h. (cherry picked from commit 9eea6eaf23067880f4af3a130e3f67c9812e2f30) Co-authored-by: Siddhesh Poyarekar --- .../2018-08-24-09-48-25.bpo-33015.s21y74.rst | 3 ++ Python/thread_pthread.h | 40 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2018-08-24-09-48-25.bpo-33015.s21y74.rst diff --git a/Misc/NEWS.d/next/Build/2018-08-24-09-48-25.bpo-33015.s21y74.rst b/Misc/NEWS.d/next/Build/2018-08-24-09-48-25.bpo-33015.s21y74.rst new file mode 100644 index 000000000000..8c5a0c91a46b --- /dev/null +++ b/Misc/NEWS.d/next/Build/2018-08-24-09-48-25.bpo-33015.s21y74.rst @@ -0,0 +1,3 @@ +Fix an undefined behaviour in the pthread implementation of +:c:func:`PyThread_start_new_thread`: add a function wrapper to always return +``NULL``. diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 697140558fdc..f79f9b90a671 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -152,6 +152,28 @@ PyThread__init_thread(void) * Thread support. */ +/* bpo-33015: pythread_callback struct and pythread_wrapper() cast + "void func(void *)" to "void* func(void *)": always return NULL. + + PyThread_start_new_thread() uses "void func(void *)" type, whereas + pthread_create() requires a void* return value. */ +typedef struct { + void (*func) (void *); + void *arg; +} pythread_callback; + +static void * +pythread_wrapper(void *arg) +{ + /* copy func and func_arg and free the temporary structure */ + pythread_callback *callback = arg; + void (*func)(void *) = callback->func; + void *func_arg = callback->arg; + PyMem_RawFree(arg); + + func(func_arg); + return NULL; +} unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg) @@ -188,21 +210,31 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); #endif + pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback)); + + if (callback == NULL) { + return PYTHREAD_INVALID_THREAD_ID; + } + + callback->func = func; + callback->arg = arg; + status = pthread_create(&th, #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) &attrs, #else (pthread_attr_t*)NULL, #endif - (void* (*)(void *))func, - (void *)arg - ); + pythread_wrapper, callback); #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) pthread_attr_destroy(&attrs); #endif - if (status != 0) + + if (status != 0) { + PyMem_RawFree(callback); return PYTHREAD_INVALID_THREAD_ID; + } pthread_detach(th); -- 2.47.3