Recent Changes - Search:

edit SideBar

NrjavaserialCrashingInReadArray

Summary

Under Mac OS X, running the SerialHelloWorld.xml model was crashing Java in readArray().

The model opens two ports, writes to one port and halts after 5 seconds.

The code does not use the RXTXListener facility, instead it creates reader and writer threads.

The cause is that when the Java RXTXPort.run() method exits, a C struct named eis goes out of scope. If the drain thread tries to access eis after a timeout, then a segfault occurs.

Replicate

Build a copy of nrjavaserial from the TerraSwarm git repo:

mkdir tmp
cd tmp
git clone https://github.com/terraswarm/nrjavaserial
cd nrjavaserial/
make osx
cp ./build/libs/nrjavaserial-3.11.0.jar $PTII/lib/nrjavaserial-3.11.0.devel.jar
$PTII/bin/vergil $PTII/ptolemy/actor/lib/jjs/modules/serial/test/auto/SerialHelloWorld.xml

Run the model, the JVM crashes as the model is wrapping up:

Thread 34 Crashed:: Java: Thread-3
0   libsystem_kernel.dylib              0x00007fff8d4b20ae __pthread_kill + 10
1   libsystem_pthread.dylib             0x00007fff8b1e5500 pthread_kill + 90
2   libsystem_c.dylib                   0x00007fff8f13f41b __abort + 145
3   libsystem_c.dylib                   0x00007fff8f13f38a abort + 144
4   libjvm.dylib                        0x0000000105082bdf os::abort(bool) + 25
5   libjvm.dylib                        0x00000001051a6a2a VMError::report_and_die() + 2304
6   libjvm.dylib                        0x000000010508480a JVM_handle_bsd_signal + 1131
7   libjvm.dylib                        0x0000000105080a6f signalHandler(int, __siginfo*, void*) + 47
8   libsystem_platform.dylib            0x00007fff917f852a _sigtramp + 26
9   ???                                 0x00000000ffffffff 0 + 4294967295
10  libNRJavaSerial.jnilib              0x000000011cea01d7 Java_gnu_io_RXTXPort_readArray + 167
11  ???                                 0x0000000105b9e954 0 + 4391037268
12  ???                                 0x0000000105b90690 0 + 4390979216
13  ???                                 0x0000000105b90690 0 + 4390979216
14  ???                                 0x0000000105b90690 0 + 4390979216
15  ???                                 0x0000000105b90c92 0 + 4390980754
16  ???                                 0x0000000105b897a7 0 + 4390950823
17  libjvm.dylib                        0x0000000104eeab02 JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) + 1710
18  libjvm.dylib                        0x0000000104eeb290 JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) + 356
19  libjvm.dylib                        0x0000000104eeb43c JavaCalls::call_virtual(JavaValue*, Handle, KlassHandle, Symbol*, Symbol*, Thread*) + 74
20  libjvm.dylib                        0x0000000104f45959 thread_entry(JavaThread*, Thread*) + 124
21  libjvm.dylib                        0x00000001051612d3 JavaThread::thread_main_inner() + 155
22  libjvm.dylib                        0x00000001051629ce JavaThread::run() + 450
23  libjvm.dylib                        0x000000010508342e java_start(Thread*) + 246
24  libsystem_pthread.dylib             0x00007fff8b1e29b1 _pthread_body + 131
25  libsystem_pthread.dylib             0x00007fff8b1e292e _pthread_start + 168
26  libsystem_pthread.dylib             0x00007fff8b1e0385 thread_start + 13

Analysis

What's happening is that in nrjavaserial/src/main/c/src/SerialImp.c, readArray() is calling read_byte_array() and read_byte_array() is crashing when eis is accessed:

        while( bytes < length &&  count++ < 20 ) /* && !is_interrupted( eis ) )*/
        {
                if (timeout >= 0) {
                        now = GetTickCount();
                        if ( now-start >= timeout )
                        {
--->                            eis->eventflags[SPE_DATA_AVAILABLE] = flag;
                                return bytes;
                        }
                }

The reason that it is crashing here is because eis is allocated in eventLoop() in SerialImp.c by struct event_info_struct eis:

JNIEXPORT void JNICALL RXTXPort(eventLoop)( JNIEnv *env, jobject jobj )
{
#ifdef WIN32
        int i = 0;
#endif /* WIN32 */
        struct event_info_struct eis;
        eis.jclazz = (*env)->GetObjectClass( env, jobj );
        eis.env = env;
        eis.jobj = &jobj;
        eis.initialised = 0;

        ENTER( "eventLoop\n" );
        if ( !initialise_event_info_struct( &eis ) ) goto end;
        if ( !init_threads( &eis ) ) goto end;

init_threads() sets the Java eis object:

        report("init_threads: get eis\n");
        jeis  = (*eis->env)->GetFieldID( eis->env, eis->jclazz, "eis", "J" );
        report("init_threads: set eis\n");
        (*eis->env)->SetLongField(eis->env, *eis->jobj, jeis, ( size_t ) eis );

nrjavaserial/src/main/java/gnu/io/RXTXPort.java invokes eventLoop()

        /** a pointer to the event info structure used to share information                                                              
            between threads so write threads can send output buffer empty                                                                
            from a pthread if need be.                                                                                                  

            long for 64 bit pointers.                                                                                                    
        */

        long eis = 0;

...

        /** Process SerialPortEvents */
        native void eventLoop();

...


        /**                                                                                                                              
        *  run the thread and call the event loop.                                                                                      
        */

                public void run()
                {
                        if (debug)
                                z.reportln( "RXTXPort:MontitorThread:run()");
                        monThreadisInterrupted=false;
                        eventLoop();
                        if (debug)
                                z.reportln( "eventLoop() returned");
                }

So, if the run() method ends, the eis automatic variable in eventloop() goes out of scope.

Replicating with debugging

The export JAVAFLAGS=-Dgnu.io.log.mode=PRINT_MODE command causes debugging information to appear.

Editing nrjavaserial/src/main/java/gnu/io/RXTXPort.java and changing

        protected final static boolean debug = false;
        protected final static boolean debug = true;

and then recompiling, installing and running:

make osx
cp ./build/libs/nrjavaserial-3.11.0.jar $PTII/lib/nrjavaserial-3.11.0.devel.jar
export JAVAFLAGS=-Dgnu.io.log.mode=PRINT_MODE
$PTII/bin/vergil $PTII/ptolemy/actor/lib/jjs/modules/serial/test/auto/SerialHelloWorld.xml

Below is the run, note that eventLoop() returned appears, which means eis is out of scope.

JavaScript: Closing serial port.
JavaScript: Closing inputStream.
JavaScript: Closing outputStream.
RXTXPort:SerialOutputStream:flush() enter
RXTXPort:SerialOutputStream:flush() leave
JavaScript: About to remove event listeners from the serial port.
RXTXPort:removeEventListener() called
        RXTXPort:Interrupt=true
        RXTXPort:calling interruptEventLoop
        RXTXPort:calling monThread.join()
eventLoop() returned
RXTXPort:removeEventListener() returning
JavaScript: Serial port writer thread exiting.
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x0000000122fe2e62, pid=82142, tid=73079
#
# JRE version: Java(TM) SE Runtime Environment (8.0_65-b17) (build 1.8.0_65-b17)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.65-b01 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [libNRJavaSerial.jnilib+0x5e62]  read_byte_array+0x362
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/cxh/src/tmp/nrjavaserial/hs_err_pid82142.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Abort trap: 6
bash-3.2$

Solution

See When RXTX.run() exits, C code should no longer access the eis structure #59

Edit - History - Print - Recent Changes - Search
Page last modified on December 28, 2015, at 01:44 PM