Skip to content

SIGSEGV (0xb) at [libc.so.6+0x90e1d] pthread_cancel+0x1f #628

@HanyzPAPU

Description

@HanyzPAPU

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions