Version
2.11.4, Linux/POSIX backend (src/main/c/Posix/SerialPort_Posix.c)
Crash
Top of call stack:
C [libc.so.6+0x90e1d] pthread_cancel+0x1f
j com.fazecast.jSerialComm.SerialPort$SerialPortEventListener.stopListening()V+63
j com.fazecast.jSerialComm.SerialPort.closePort()Z+18
Triggered by calling closePort() after a USB-serial device is unplugged during an active event listener (e.g. reacting to LISTENING_EVENT_PORT_DISCONNECTED).
Possible cause
eventReadingThread1 and eventReadingThread2 are pthread_detach'd after creation. eventReadingThread1's loop exits on its own when the device disappears, because TIOCMIWAIT starts returning an error and isSupported flips to 0:
isSupported = !ioctl(port->handle, TIOCMIWAIT, mask) && !ioctl(port->handle, TIOCGICOUNT, ...);
Once that thread returns, its detached pthread_t is invalid, but port->eventsThread1 still holds a dangling reference. eventReadingThread2 stays alive, detects POLLHUP, fires LISTENING_EVENT_PORT_DISCONNECTED. The caller reacts by calling closePort() → stopListening() → setEventListeningStatus(..., false), which does:
if (port->eventsThread1)
pthread_cancel(port->eventsThread1); // stale detached ref → SIGSEGV inside libc
Per POSIX, using a pthread_t of an already-terminated detached thread is undefined behavior.
Proposed fix
Zero the thread IDs from inside the threads immediately before they return, so the if (port->eventsThreadN) guard in setEventListeningStatus actually means "thread is still alive":
// at the end of eventReadingThread1, just before `return NULL;`
port->eventsThread1 = 0;
return NULL;
and likewise in eventReadingThread2. There will still be a race though, completely avoiding it would require not detaching and joining the thread to free up resources.
Version
2.11.4, Linux/POSIX backend (src/main/c/Posix/SerialPort_Posix.c)
Crash
Top of call stack:
Triggered by calling closePort() after a USB-serial device is unplugged during an active event listener (e.g. reacting to LISTENING_EVENT_PORT_DISCONNECTED).
Possible cause
eventReadingThread1andeventReadingThread2arepthread_detach'd after creation.eventReadingThread1's loop exits on its own when the device disappears, becauseTIOCMIWAITstarts returning an error andisSupportedflips to 0:Once that thread returns, its detached
pthread_tis invalid, butport->eventsThread1still holds a dangling reference.eventReadingThread2stays alive, detectsPOLLHUP, firesLISTENING_EVENT_PORT_DISCONNECTED. The caller reacts by callingclosePort()→stopListening()→setEventListeningStatus(..., false), which does:Per POSIX, using a
pthread_tof an already-terminated detached thread is undefined behavior.Proposed fix
Zero the thread IDs from inside the threads immediately before they return, so the
if (port->eventsThreadN)guard insetEventListeningStatusactually means "thread is still alive":and likewise in
eventReadingThread2. There will still be a race though, completely avoiding it would require not detaching and joining the thread to free up resources.