From 59ed3e2664fec82be5b838c98ccd36ca0fd2c3c1 Mon Sep 17 00:00:00 2001 From: Konrad Malawski Date: Tue, 7 Apr 2026 22:43:18 +0900 Subject: [PATCH] Make nested arrays a bit safer, don't count on null arrays --- .../BridgedValues/JavaValue+Array.swift | 6 +++--- .../JavaEnvironmentTests.swift | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Sources/SwiftJavaJNICore/BridgedValues/JavaValue+Array.swift b/Sources/SwiftJavaJNICore/BridgedValues/JavaValue+Array.swift index 61ab0cf..2088c71 100644 --- a/Sources/SwiftJavaJNICore/BridgedValues/JavaValue+Array.swift +++ b/Sources/SwiftJavaJNICore/BridgedValues/JavaValue+Array.swift @@ -21,14 +21,14 @@ extension Array: JavaValue where Element: JavaValue { public static var javaType: JavaType { .array(Element.javaType) } public init(fromJNI value: JNIType, in environment: JNIEnvironment) { - let jniCount = environment.interface.GetArrayLength(environment, value) - let count = Int(jniCount) - guard let value else { self = [] return } + let jniCount = environment.interface.GetArrayLength(environment, value) + let count = Int(jniCount) + // Fast path for byte types: Since the memory layout of `jbyte` (Int8) and UInt8/Int8 is identical, // we can rebind the memory and fill it directly without creating an intermediate array. // This mirrors the optimization in `getJNIValue` in the reverse direction. diff --git a/Tests/SwiftJavaJNICoreTests/JavaEnvironmentTests.swift b/Tests/SwiftJavaJNICoreTests/JavaEnvironmentTests.swift index 69466c2..ae650fe 100644 --- a/Tests/SwiftJavaJNICoreTests/JavaEnvironmentTests.swift +++ b/Tests/SwiftJavaJNICoreTests/JavaEnvironmentTests.swift @@ -182,6 +182,25 @@ struct JavaEnvironmentTests { #expect(env.interface.GetArrayLength(env, inner) == 2) } + @Test(.enabled(if: isSupportedPlatform)) + func fromJNI_nestedArrayWithNullInnerElement() throws { + let env = try JavaVirtualMachine.shared().environment() + + let makeOuter = [[UInt8]].jniNewArray(in: env) + let outer = makeOuter(env, 3) + + let inner0 = [UInt8(1)].getJNIValue(in: env) + let inner1nil: jobject? = nil // oh no! + let inner2 = [UInt8(2), UInt8(3)].getJNIValue(in: env) + + env.interface.SetObjectArrayElement(env, outer, 0, inner0) + env.interface.SetObjectArrayElement(env, outer, 1, inner1nil) + env.interface.SetObjectArrayElement(env, outer, 2, inner2) + + let result = [[UInt8]](fromJNI: outer, in: env) // avoid NPE on the inner1nil, just count as 0 length + #expect(result == [[0x01], [], [0x02, 0x03]]) + } + @Test(.enabled(if: isSupportedPlatform)) func getJNIValue_nestedInt32Array() throws { let env = try JavaVirtualMachine.shared().environment()