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 committed Jun 11, 2024
1 parent b081a07 commit f3fec39
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions modules/libcom/src/osi/os/posix/osdThread.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,32 +689,45 @@ 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;
}

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

} else if(self==id) {
/* Thread can't join itself (directly or indirectly)
* so we detach instead.
*/
status = pthread_detach(id->tid);
checkStatusOnce(status, "pthread_detach");
} else checkStatusOnce(status, "pthread_join");
free_threadInfo(id);

} else {
status = pthread_join(id->tid, &ret);
checkStatusOnce(status, "pthread_join");
}

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

LIBCOM_API void epicsStdCall epicsThreadSuspendSelf(void)
Expand Down

0 comments on commit f3fec39

Please sign in to comment.