Skip to content

Commit d51bc5e

Browse files
authored
Some error handling in get serial port names (#171)
Add some error handling in SerialNativeInterface.getSerialPortNames()
1 parent c4a4015 commit d51bc5e

1 file changed

Lines changed: 69 additions & 34 deletions

File tree

src/main/cpp/windows/jssc.cpp

Lines changed: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
#include <jni.h>
2626
#include <stdlib.h>
27+
#include <stdio.h>
2728
#include <windows.h>
2829
#include <jssc_SerialNativeInterface.h>
2930
#include "version.h"
@@ -643,47 +644,81 @@ JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_waitEvents
643644
*/
644645
JNIEXPORT jobjectArray JNICALL Java_jssc_SerialNativeInterface_getSerialPortNames
645646
(JNIEnv *env, jobject){
646-
HKEY phkResult;
647+
HKEY phkResult = NULL;
647648
LPCSTR lpSubKey = "HARDWARE\\DEVICEMAP\\SERIALCOMM\\";
648649
jobjectArray returnArray = NULL;
649-
if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &phkResult) == ERROR_SUCCESS){
650-
boolean hasMoreElements = true;
651-
DWORD keysCount = 0;
652-
char valueName[256];
653-
DWORD valueNameSize;
654-
DWORD enumResult;
655-
while(hasMoreElements){
656-
valueNameSize = 256;
657-
enumResult = RegEnumValueA(phkResult, keysCount, valueName, &valueNameSize, NULL, NULL, NULL, NULL);
658-
if(enumResult == ERROR_SUCCESS){
659-
keysCount++;
660-
}
661-
else if(enumResult == ERROR_NO_MORE_ITEMS){
662-
hasMoreElements = false;
663-
}
664-
else {
665-
hasMoreElements = false;
666-
}
650+
byte lpDataOnStack[256];
651+
byte *lpData = lpDataOnStack;
652+
DWORD lpData_capacity = 256;
653+
char valueName[256];
654+
DWORD valueNameSize;
655+
DWORD enumResult;
656+
boolean hasMoreElements = true;
657+
DWORD keysCount = 0;
658+
if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &phkResult) != ERROR_SUCCESS){
659+
returnArray = NULL;
660+
goto Finally;
661+
}
662+
/* Iterate a 1st time to see how long our resulting array has to be. */
663+
while(hasMoreElements){
664+
valueNameSize = 256;
665+
enumResult = RegEnumValueA(phkResult, keysCount, valueName, &valueNameSize, NULL, NULL, NULL, NULL);
666+
if(enumResult == ERROR_SUCCESS){
667+
keysCount++;
667668
}
668-
if(keysCount > 0){
669-
jclass stringClass = env->FindClass("java/lang/String");
670-
returnArray = env->NewObjectArray((jsize)keysCount, stringClass, NULL);
671-
char lpValueName[256];
672-
DWORD lpcchValueName;
673-
byte lpData[256];
674-
DWORD lpcbData;
675-
DWORD result;
676-
for(DWORD i = 0; i < keysCount; i++){
677-
lpcchValueName = 256;
678-
lpcbData = 256;
679-
result = RegEnumValueA(phkResult, i, lpValueName, &lpcchValueName, NULL, NULL, lpData, &lpcbData);
680-
if(result == ERROR_SUCCESS){
681-
env->SetObjectArrayElement(returnArray, i, env->NewStringUTF((char*)lpData));
669+
else if(enumResult == ERROR_NO_MORE_ITEMS){
670+
hasMoreElements = false;
671+
}
672+
else {
673+
hasMoreElements = false;
674+
}
675+
}
676+
if(keysCount > 0){
677+
jclass stringClass = env->FindClass("java/lang/String");
678+
returnArray = env->NewObjectArray((jsize)keysCount, stringClass, NULL);
679+
DWORD lpcbData;
680+
DWORD result;
681+
/* iterate 2nd time but this time our array is ready to catch results. */
682+
for(DWORD i = 0; i < keysCount; i++){
683+
valueNameSize = 256;
684+
lpcbData = lpData_capacity;
685+
result = RegEnumValueA(phkResult, i, valueName, &valueNameSize, NULL, NULL, lpData, &lpcbData);
686+
if(result == ERROR_SUCCESS){
687+
env->SetObjectArrayElement(returnArray, i, env->NewStringUTF((char*)lpData));
688+
}else if(result == ERROR_MORE_DATA && lpData_capacity < UINT_MAX){
689+
/* whoops our supplied buffer was not large enough. Fallback to a heap
690+
* allocd one. RegEnumValueA was kind enough to set 'lpcbData' to the
691+
* required length before return. */
692+
lpData = (lpData == lpDataOnStack) ? NULL : lpData;
693+
/* MS doc is unclear to me if returned size includes the required
694+
* zero-term. So to stay safe, we provide one byte more. */
695+
if(lpcbData < UINT_MAX) lpcbData += 1;
696+
byte *tmp = (byte*)realloc(lpData, lpcbData*sizeof*tmp);
697+
if(tmp == NULL){
698+
jclass exClz = env->FindClass("java/lang/OutOfMemoryError");
699+
if(exClz != NULL) env->ThrowNew(exClz, NULL);
700+
returnArray = NULL;
701+
goto Finally;
682702
}
703+
/* install new buffer and reset 'i' so we try the same element again. */
704+
lpData_capacity = lpcbData;
705+
lpData = tmp;
706+
i -= 1;
707+
}else{
708+
char exMsg[128];
709+
snprintf(exMsg, sizeof exMsg, "RegEnumValueA(): Code %ld: "
710+
"https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes",
711+
result);
712+
jclass exClz = env->FindClass("java/lang/RuntimeException");
713+
if(exClz != NULL) env->ThrowNew(exClz, exMsg);
714+
returnArray = NULL;
715+
goto Finally;
683716
}
684717
}
685-
CloseHandle(phkResult);
686718
}
719+
Finally:
720+
if(lpData != NULL && lpData != lpDataOnStack) free(lpData);
721+
if(phkResult != NULL) CloseHandle(phkResult);
687722
return returnArray;
688723
}
689724

0 commit comments

Comments
 (0)