Skip to content

Commit

Permalink
avoid UB with self pthread_join()
Browse files Browse the repository at this point in the history
  • Loading branch information
mdavidsaver authored and anjohnson committed Oct 2, 2024
1 parent 0121396 commit 152d306
Showing 1 changed file with 33 additions and 13 deletions.
46 changes: 33 additions & 13 deletions modules/libcom/src/osi/os/posix/osdThread.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,34 +687,54 @@ static epicsThreadOSD *createImplicit(void)

void epicsThreadMustJoin(epicsThreadId id)
{
void *ret = NULL;
int status;
int prev;
epicsThreadId self;

if(!id) {
if(!id)
return;
} else if(epicsAtomicCmpAndSwapIntT(&id->joinable, 1, 0)!=1) {
if(epicsThreadGetIdSelf()==id) {
errlogPrintf("Warning: %s thread self-join of unjoinable\n", id->name);

prev = epicsAtomicCmpAndSwapIntT(&id->joinable, 1, 0);
self = epicsThreadGetIdSelf();

if(prev==0) {
/* join of unjoinable */
if(self==id) {
errlogPrintf(ERL_WARNING ": %s thread self-join of unjoinable\n", id->name);
return;

} else {
/* try to error nicely, however in all likelihood de-ref of
* 'id' has already caused SIGSEGV as we are racing thread exit,
* which free's 'id'.
*/
cantProceed("Error: %s thread not joinable.\n", id->name);
cantProceed(ERL_ERROR ": %s can't join unjoinable %s\n", self->name, id->name);
}
return;

} else if(prev!=1) { /* also not 0, the only other allowed value. */
cantProceed(ERL_ERROR ": %s joins corrupt thread handle\n", self->name);
}

status = pthread_join(id->tid, &ret);
if(status == EDEADLK) {
/* Thread can't join itself (directly or indirectly)
* so we detach instead.
/* from this point, we are responsible to either detach or join (or leak memory) */

if(self!=id) {
status = pthread_join(id->tid, NULL);
checkStatusOnce(status, "pthread_join");
/* on error, continue and attempt to detach */

} else {
/* Thread self pthread_join() isn't portable.
* We choose to allow, and treat as detach.
*/
status = EDEADLK;
}

if(status) {
status = pthread_detach(id->tid);
checkStatusOnce(status, "pthread_detach");
} else checkStatusOnce(status, "pthread_join");
free_threadInfo(id);
}

free_threadInfo(id); /* release joinable reference */
}

LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Expand Down

0 comments on commit 152d306

Please sign in to comment.