Skip to content

Invalidate RXTXPort.eis when the monitor thread goes away (#267) - #269

Open
thomasnikolay wants to merge 1 commit into
NeuronRobotics:masterfrom
thomasnikolay:fix/issue-267-eis-upstream
Open

Invalidate RXTXPort.eis when the monitor thread goes away (#267)#269
thomasnikolay wants to merge 1 commit into
NeuronRobotics:masterfrom
thomasnikolay:fix/issue-267-eis-upstream

Conversation

@thomasnikolay

Copy link
Copy Markdown

Summary

Fixes the JVM crash reported in #267 (EXCEPTION_ACCESS_VIOLATION / SIGSEGV in read_byte_array after a serial adapter is unplugged).

RXTXPort.eis stores a pointer to the struct event_info_struct that RXTXPort(eventLoop) declares as a local, i.e. it lives on the monitor thread's stack. Today the field is only reset after eventLoop() returns normally:

eventLoop();
eis = 0;          // skipped when eventLoop() throws

When the monitor thread ends through the hardware-error path, eis keeps pointing at a stack frame that no longer exists, and the next readArray() dereferences it. The hs_err in #267 faults at eis + 8, which is eventflags[SPE_DATA_AVAILABLE] (int fd + one int) — the eis == NULL guard added in #249 never triggers, because the field is non-NULL garbage.

This clears the pointer on every exit path:

  • Java — MonitorThread.run():
    } catch (Throwable ex) { ... } finally {
        eis = 0;
    }
  • Native — finalize_event_info_struct() calls the new clear_java_eis(), which writes 0 into the Java field. It saves and rethrows a pending exception around the write, because JNI calls are not allowed while an exception is in flight (otherwise an error thrown out of the event loop would be swallowed).

With the field zeroed, the existing NULL check in read_byte_array() turns a post-disconnect read into an IOException instead of terminating the JVM.

Note: the prebuilt native libraries in src/main/c/resources/native/ are not included in this PR; they need to be rebuilt for the fix to take effect on the native side.

Verified by building the JAR and the Linux/Windows natives (JDK 11) and exercising a port over a socat PTY pair: after the monitor thread ends, eis is 0 and subsequent readArray() calls raise IOException instead of crashing. The original unplug scenario needs real hardware and was not reproduced here.

RXTXPort.eis holds a pointer to the struct event_info_struct that
eventLoop() allocates on the monitor thread's stack. It was only reset
after a normal return from eventLoop(), so when the monitor thread ended
through the hardware error path the field kept pointing at a stack frame
that no longer existed and the next readArray() dereferenced it, killing
the JVM with SIGSEGV/EXCEPTION_ACCESS_VIOLATION (issue NeuronRobotics#267).

Clear the field on every exit path: from native code in
finalize_event_info_struct() (preserving a pending exception, since JNI
calls are not allowed while one is in flight) and from Java in a finally
block in MonitorThread.run(). The existing NULL check in
read_byte_array() then turns the situation into an IOException.
@thomasnikolay

Copy link
Copy Markdown
Author

@MrDOS Can you please check this PR and if it ok please merge and release it.

@MrDOS

MrDOS commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

I'd first like to understand the problem description a little bit better – I have not really had time to digest it, sorry. I have also thought for a long time now that event info structs should be heap-allocated and pointed to by a private field on the RXTXPort, rather than being stored as a global linked list (to alleviate exactly this sort of safety/lifetime concern); and so I would like to see if that's an easy change to make, because it would resolve this and other similar issues.

At a higher level, though, and for the same reasons outlined by Twisted's draft AI policy, I am extremely leery of accepting an LLM-authored contribution. This project is LGPL-licensed, not MIT-licensed, and I am wary of accepting code into it which was not knowingly authored in kind. I am also pretty discouraged by the output of the genAI industry at large (both its products and its rhetoric), and so I prefer to stay as far away from it as possible in the things I do in my spare time. All to say that there is a years-long backlog of other PRs and work to do on this project, and I am inclined to spend my very limited time on those human-authored things first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants