Reserve stack for wolfSSL's static TLS, and report a failed thread
Some checks are pending
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI Linux / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI MacOS / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI Windows / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (macos-15) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-24.04-arm) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (ubuntu-latest) (push) Waiting to run
C/C++ CI cmake / ${{ matrix.target }} (windows-2022) (push) Waiting to run
C/C++ CI cmake / ubuntu-latest (wolfSSL) (push) Waiting to run

wolfSSL reserves about 48K of static thread-local storage. glibc counts
that against the thread stack, so pthread_create() was refused with EINVAL
and no service thread was ever created: the process started, listened on
nothing, logged nothing and waited forever on the semaphore the thread was
supposed to release. Every wolfSSL build on glibc was affected.

Add that reserve to the thread stack when built against wolfSSL. musl puts
the block beside the stack rather than inside it and needs nothing extra,
and OpenSSL has no static TLS at all, so neither pays for it.

Check the pthread_create() return value as well, so a thread that cannot be
created reports itself and suggests stacksize instead of hanging.
This commit is contained in:
Vladimir Dubrovin 2026-08-25 19:05:10 +03:00
parent a11427afe9
commit 36979639b7
3 changed files with 24 additions and 2 deletions

View File

@ -182,7 +182,7 @@ int timeouts[12] = {
EINVAL below it and the thread silently gets the 8M system default stack.
*/
size_t threadstacksize(int extra){
long size = BASESTACKSIZE + extra;
long size = BASESTACKSIZE + TLSSTACKSIZE + extra;
if(size < (long)PTHREAD_STACK_MIN) size = (long)PTHREAD_STACK_MIN;
return (size_t)size;

View File

@ -158,7 +158,12 @@ int start_proxy_thread(struct child * chp){
pthread_attr_init(&pa);
pthread_attr_setstacksize(&pa,threadstacksize(conf.stacksize));
pthread_attr_setdetachstate(&pa,PTHREAD_CREATE_DETACHED);
pthread_create(&thread, &pa, startsrv, (void *)chp);
if(pthread_create(&thread, &pa, startsrv, (void *)chp)){
pthread_attr_destroy(&pa);
fprintf(stderr, "Failed to create service thread on line %d, try to set larger stacksize\n", linenum);
_3proxy_sem_unlock(conf.threadinit);
return(40);
}
pthread_attr_destroy(&pa);
#endif
_3proxy_sem_lock(conf.threadinit);

View File

@ -135,6 +135,23 @@ void daemonize(void);
#endif
#endif
/* wolfSSL reserves around 48K of static thread-local storage. glibc counts
that against the thread stack, so pthread_create() fails with EINVAL and
no thread starts at all. musl places the block next to the stack instead
of inside it and needs nothing extra, and OpenSSL has no static TLS.
musl identifies itself by no macro of its own, but it does not define
__GLIBC__, which any libc header pulled in above would have set.
*/
#ifndef TLSSTACKSIZE
#if defined(__linux__) && !defined(__GLIBC__)
#define TLSSTACKSIZE 0
#elif defined(WITH_WOLFSSL)
#define TLSSTACKSIZE 49152
#else
#define TLSSTACKSIZE 0
#endif
#endif
#ifndef _WIN32
size_t threadstacksize(int extra);
#endif