From a52f9cceb89c8e3846888c100b2fc508ffd7c119 Mon Sep 17 00:00:00 2001 From: "Andreas Fankhauser hiddenalpha.ch" <23085769+hiddenalpha@users.noreply.github.com> Date: Tue, 10 Jun 2025 20:11:23 +0200 Subject: [PATCH 1/2] Treat zero-length read as legal case I think trying to read zero bytes should just throw an exception, as this doesn't make much sense to me. But it seems jssc needs to accept this as a legal case. So jssc will respond with an empty array, exactly as caller did request. Fixes: https://github.com/java-native/jssc/issues/192 --- src/main/cpp/_nix_based/jssc.cpp | 7 +++++-- src/main/cpp/windows/jssc.cpp | 7 +++++-- .../java/jssc/SerialNativeInterfaceTest.java | 19 +++++++++++-------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/cpp/_nix_based/jssc.cpp b/src/main/cpp/_nix_based/jssc.cpp index bcc814784..cab25db09 100644 --- a/src/main/cpp/_nix_based/jssc.cpp +++ b/src/main/cpp/_nix_based/jssc.cpp @@ -662,12 +662,15 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes jbyteArray returnArray = NULL; int byteRemains = byteCount; - if( byteCount <= 0 ){ + if( byteCount < 0 ){ char emsg[64]; emsg[0] = '\0'; - snprintf(emsg, sizeof emsg, "byteCount %d. Expected range: 1..2147483647", byteCount); + snprintf(emsg, sizeof emsg, "byteCount %d. Expected range: 0..2147483647", byteCount); jclass exClz = env->FindClass("java/lang/IllegalArgumentException"); if( exClz ) env->ThrowNew(exClz, emsg); returnArray = NULL; goto Finally; + }else if( byteCount == 0 ){ + returnArray = env->NewByteArray(0); + goto Finally; } lpBuffer = (jbyte*)malloc(byteCount*sizeof*lpBuffer); diff --git a/src/main/cpp/windows/jssc.cpp b/src/main/cpp/windows/jssc.cpp index 595873c1c..0f08718f0 100644 --- a/src/main/cpp/windows/jssc.cpp +++ b/src/main/cpp/windows/jssc.cpp @@ -281,12 +281,15 @@ JNIEXPORT jbyteArray JNICALL Java_jssc_SerialNativeInterface_readBytes jbyte *lpBuffer = NULL; OVERLAPPED *overlapped = NULL; - if( byteCount <= 0 ){ + if( byteCount < 0 ){ char emsg[64]; emsg[0] = '\0'; - snprintf(emsg, sizeof emsg, "byteCount %d. Expected range: 1..2147483647", byteCount); + snprintf(emsg, sizeof emsg, "byteCount %d. Expected range: 0..2147483647", byteCount); jclass exClz = env->FindClass("java/lang/IllegalArgumentException"); if( exClz ) env->ThrowNew(exClz, emsg); returnArray = NULL; goto Finally; + }else if( byteCount == 0 ){ + returnArray = env->NewByteArray(0); + goto Finally; } returnArray = env->NewByteArray(byteCount); diff --git a/src/test/java/jssc/SerialNativeInterfaceTest.java b/src/test/java/jssc/SerialNativeInterfaceTest.java index a1186c923..555508a78 100644 --- a/src/test/java/jssc/SerialNativeInterfaceTest.java +++ b/src/test/java/jssc/SerialNativeInterfaceTest.java @@ -9,6 +9,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -110,16 +111,18 @@ public void throwsIfCountNegative() throws Exception { } } + /** + * I think this case should just throw an exception, as trying to read zero + * bytes doesn't make much sense to me. But it seems we need to accept a + * "read of zero bytes" as a legal case. So jssc will respond with an empty + * array, exactly as caller did request. + * See also "https://github.com/java-native/jssc/issues/192". */ @Test - public void throwsIfCountZero() throws Exception { + public void returnsAnEmptyArrayIfCountIsZero() throws Exception { SerialNativeInterface testTarget = new SerialNativeInterface(); - byte[] ret; - try{ - ret = testTarget.readBytes(0, 0); - fail("Where's the exception?"); - }catch( IllegalArgumentException ex ){ - assertTrue(ex.getMessage().contains("0")); - } + byte[] ret = testTarget.readBytes(0, 0); + assertNotNull(ret); + assertTrue(ret.length == 0); } @Test From c8f0379191d74f39525e0283980a4737a67aa089 Mon Sep 17 00:00:00 2001 From: "Andreas Fankhauser hiddenalpha.ch" <23085769+hiddenalpha@users.noreply.github.com> Date: Tue, 10 Jun 2025 20:24:04 +0200 Subject: [PATCH 2/2] Enhance reasoning. --- src/test/java/jssc/SerialNativeInterfaceTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/jssc/SerialNativeInterfaceTest.java b/src/test/java/jssc/SerialNativeInterfaceTest.java index 555508a78..91adbbf1e 100644 --- a/src/test/java/jssc/SerialNativeInterfaceTest.java +++ b/src/test/java/jssc/SerialNativeInterfaceTest.java @@ -116,7 +116,14 @@ public void throwsIfCountNegative() throws Exception { * bytes doesn't make much sense to me. But it seems we need to accept a * "read of zero bytes" as a legal case. So jssc will respond with an empty * array, exactly as caller did request. - * See also "https://github.com/java-native/jssc/issues/192". */ + * See also "https://github.com/java-native/jssc/issues/192". + * + * Update: According to + * https://github.com/java-native/jssc/issues/192#issuecomment-2960137775 + * there seems to exist some other issue related to events, which occasionly + * provocates zero-length reads. So as long this other issue exists, jssc + * probably should handle zero-length reads, as it seems to cause them + * itself. */ @Test public void returnsAnEmptyArrayIfCountIsZero() throws Exception { SerialNativeInterface testTarget = new SerialNativeInterface();