From 7993eeb7a0bb925338717032fa9977fecca03fd2 Mon Sep 17 00:00:00 2001 From: hedgecrw85 Date: Mon, 16 Mar 2015 10:11:06 -0500 Subject: [PATCH] Fixed JNI crash when calling native functions after port has already closed. --- src/main/cpp/Linux/SerialPort_Linux.cpp | 14 +++++++++++++- src/main/cpp/OSX/SerialPort_OSX.cpp | 14 +++++++++++++- src/main/cpp/Windows/SerialPort_Windows.cpp | 16 ++++++++++++++-- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/main/cpp/Linux/SerialPort_Linux.cpp b/src/main/cpp/Linux/SerialPort_Linux.cpp index 69bf8f3..eecbdb1 100644 --- a/src/main/cpp/Linux/SerialPort_Linux.cpp +++ b/src/main/cpp/Linux/SerialPort_Linux.cpp @@ -101,6 +101,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J struct serial_struct serialInfo; jclass serialCommClass = env->GetObjectClass(obj); int portFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (portFD <= 0) + return JNI_FALSE; // Set raw-mode to allow the use of tcsetattr() and ioctl() fcntl(portFD, F_SETFL, 0); @@ -146,6 +148,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configFlowCo struct termios options; jclass serialCommClass = env->GetObjectClass(obj); int portFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (portFD <= 0) + return JNI_FALSE; // Get port parameters from Java class int flowControl = env->GetIntField(obj, env->GetFieldID(serialCommClass, "flowControl", "I")); @@ -175,6 +179,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou int serialFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); int timeoutMode = env->GetIntField(obj, env->GetFieldID(serialCommClass, "timeoutMode", "I")); int readTimeout = env->GetIntField(obj, env->GetFieldID(serialCommClass, "readTimeout", "I")); + if (serialFD <= 0) + return JNI_FALSE; // Retrieve existing port configuration struct termios options; @@ -222,6 +228,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventF { jclass serialCommClass = env->GetObjectClass(obj); int serialFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialFD <= 0) + return JNI_FALSE; // Get event flags from Java class int eventsToMonitor = env->GetIntField(obj, env->GetFieldID(serialCommClass, "eventFlags", "I")); @@ -249,6 +257,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI { jclass serialCommClass = env->GetObjectClass(obj); int serialFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialFD <= 0) + return 0; // Initialize the waiting set and the timeouts struct timeval timeout = { 1, 0 }; @@ -267,6 +277,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat { // Close port int portFD = (int)env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J")); + if (portFD <= 0) + return JNI_TRUE; close(portFD); env->SetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J"), -1l); env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_FALSE); @@ -279,7 +291,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(J int serialPortFD = (int)env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J")); int numBytesAvailable = -1; - if (serialPortFD != -1) + if (serialPortFD > 0) ioctl(serialPortFD, FIONREAD, &numBytesAvailable); return numBytesAvailable; diff --git a/src/main/cpp/OSX/SerialPort_OSX.cpp b/src/main/cpp/OSX/SerialPort_OSX.cpp index 2161e2f..2f122aa 100644 --- a/src/main/cpp/OSX/SerialPort_OSX.cpp +++ b/src/main/cpp/OSX/SerialPort_OSX.cpp @@ -116,6 +116,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J struct termios options; jclass serialCommClass = env->GetObjectClass(obj); int portFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (portFD <= 0) + return JNI_FALSE; // Set raw-mode to allow the use of tcsetattr() and ioctl() fcntl(portFD, F_SETFL, 0); @@ -152,6 +154,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configFlowCo struct termios options; jclass serialCommClass = env->GetObjectClass(obj); int portFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (portFD <= 0) + return JNI_FALSE; // Get port parameters from Java class int flowControl = env->GetIntField(obj, env->GetFieldID(serialCommClass, "flowControl", "I")); @@ -181,6 +185,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou int serialFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); int timeoutMode = env->GetIntField(obj, env->GetFieldID(serialCommClass, "timeoutMode", "I")); int readTimeout = env->GetIntField(obj, env->GetFieldID(serialCommClass, "readTimeout", "I")); + if (serialFD <= 0) + return JNI_FALSE; // Retrieve existing port configuration struct termios options; @@ -228,6 +234,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventF { jclass serialCommClass = env->GetObjectClass(obj); int serialFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialFD <= 0) + return JNI_FALSE; // Get event flags from Java class int eventsToMonitor = env->GetIntField(obj, env->GetFieldID(serialCommClass, "eventFlags", "I")); @@ -255,6 +263,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI { jclass serialCommClass = env->GetObjectClass(obj); int serialFD = (int)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialFD <= 0) + return 0; // Initialize the waiting set and the timeouts struct timeval timeout = { 1, 0 }; @@ -273,6 +283,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat { // Close port int portFD = (int)env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J")); + if (portFD <= 0) + return JNI_TRUE; close(portFD); env->SetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J"), -1l); env->SetBooleanField(obj, env->GetFieldID(env->GetObjectClass(obj), "isOpened", "Z"), JNI_FALSE); @@ -285,7 +297,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(J int serialPortFD = (int)env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J")); int numBytesAvailable = -1; - if (serialPortFD != -1) + if (serialPortFD > 0) ioctl(serialPortFD, FIONREAD, &numBytesAvailable); return numBytesAvailable; diff --git a/src/main/cpp/Windows/SerialPort_Windows.cpp b/src/main/cpp/Windows/SerialPort_Windows.cpp index a07c964..9a6b6a1 100644 --- a/src/main/cpp/Windows/SerialPort_Windows.cpp +++ b/src/main/cpp/Windows/SerialPort_Windows.cpp @@ -223,9 +223,11 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J DCB dcbSerialParams = {0}; dcbSerialParams.DCBlength = sizeof(DCB); jclass serialCommClass = env->GetObjectClass(obj); + HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialPortHandle == INVALID_HANDLE_VALUE) + return JNI_FALSE; // Get port parameters from Java class - HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); DWORD baudRate = (DWORD)env->GetIntField(obj, env->GetFieldID(serialCommClass, "baudRate", "I")); BYTE byteSize = (BYTE)env->GetIntField(obj, env->GetFieldID(serialCommClass, "dataBits", "I")); int stopBitsInt = env->GetIntField(obj, env->GetFieldID(serialCommClass, "stopBits", "I")); @@ -257,6 +259,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configFlowCo dcbSerialParams.DCBlength = sizeof(DCB); jclass serialCommClass = env->GetObjectClass(obj); HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialPortHandle == INVALID_HANDLE_VALUE) + return JNI_FALSE; // Get flow control parameters from Java class int flowControl = env->GetIntField(obj, env->GetFieldID(serialCommClass, "flowControl", "I")); @@ -303,6 +307,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou int timeoutMode = env->GetIntField(obj, env->GetFieldID(serialCommClass, "timeoutMode", "I")); DWORD readTimeout = (DWORD)env->GetIntField(obj, env->GetFieldID(serialCommClass, "readTimeout", "I")); DWORD writeTimeout = (DWORD)env->GetIntField(obj, env->GetFieldID(serialCommClass, "writeTimeout", "I")); + if (serialHandle == INVALID_HANDLE_VALUE) + return JNI_FALSE; // Set updated port timeouts timeouts.WriteTotalTimeoutMultiplier = 0; @@ -361,6 +367,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventF { jclass serialCommClass = env->GetObjectClass(obj); HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialPortHandle == INVALID_HANDLE_VALUE) + return JNI_FALSE; // Get event flags from Java class int eventsToMonitor = env->GetIntField(obj, env->GetFieldID(serialCommClass, "eventFlags", "I")); @@ -393,12 +401,14 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI { jclass serialCommClass = env->GetObjectClass(obj); HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(serialCommClass, "portHandle", "J")); + if (serialPortHandle == INVALID_HANDLE_VALUE) + return 0; OVERLAPPED overlappedStruct = {0}; overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (overlappedStruct.hEvent == NULL) { CloseHandle(overlappedStruct.hEvent); - return -1; + return 0; } // Wait for a serial port event @@ -427,6 +437,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat { // Purge any outstanding port operations HANDLE serialPortHandle = (HANDLE)env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "portHandle", "J")); + if (serialPortHandle == INVALID_HANDLE_VALUE) + return JNI_TRUE; PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); // Close port