Skip to content

Fix socket write NPE and avoid throwaway allocation on partial writes (#5139)#5140

Merged
shai-almog merged 1 commit into
masterfrom
fix-socket-npe-offset-write
Jun 1, 2026
Merged

Fix socket write NPE and avoid throwaway allocation on partial writes (#5139)#5140
shai-almog merged 1 commit into
masterfrom
fix-socket-npe-offset-write

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Fixes the two problems raised in #5139 about the socket write path.

1. NPE instead of IOException

The reported crash was a NullPointerException thrown deep in the platform implementation:

at com_codename1_impl_ios_IOSImplementation.writeToSocketStream:9242
at com_codename1_io_Socket_SocketOutputStream.write:423

The only Java-level null dereference in that path is ((Long)socket).longValue() in IOSImplementation.writeToSocketStream when the socket handle is null — i.e. a writer thread reached a socket whose native handle was already torn down. That surfaced as an opaque NPE rather than an IOException the caller could catch.

SocketOutputStream now routes all three write(...) overloads through a single guarded helper that throws IOException("Socket is not connected") when the handle is null, and validates the offset/len arguments of write(byte[], int, int).

2. Throwaway allocation on partial writes

As noted in the issue, write(b, off, len) with a non-zero offset allocated a fresh byte[] and System.arraycopy'd into it on every call, purely to hand a whole-array view to the implementation.

This adds an offset-aware writeToSocketStream(Object socket, byte[] data, int offset, int len) to the implementation API:

  • CodenameOneImplementation — default implementation keeps the copy (backward compatible for any port/lib that doesn't override it).
  • iOS — overrides it and threads offset/len down to a new native binding; the C side builds a sub-range NSData via a new arrayToDataRange helper, so no intermediate Java array is allocated.
  • Android / JavaSE — override it to call OutputStream.write(data, offset, len) directly.

Notes

  • iOS adds one native method (IOSNative.writeToSocketStream(long, byte[], int, int)); the iOS port must be rebuilt.
  • core compiles cleanly with JDK 8. JavaSEPort.java compiles (the only errors in a local javase build are pre-existing JavaFX-not-on-classpath issues in the unrelated fx/ package).

🤖 Generated with Claude Code

…#5139)

Two issues reported in #5139 against the iOS socket code:

1. NPE instead of IOException: a write reaching a torn-down native socket
   handle surfaced as a NullPointerException deep inside the platform
   implementation (((Long)socket).longValue() on a null handle) rather than
   an IOException the caller can handle. SocketOutputStream now routes every
   write overload through a single guarded path that throws IOException when
   the socket handle is null, and validates the offset/length arguments.

2. Throwaway allocation on partial writes: write(b, off, len) with a non-zero
   offset allocated a fresh byte[] + System.arraycopy on every call just to
   pass the data down. Added an offset-aware
   writeToSocketStream(socket, data, offset, len) to the implementation API.
   The base implementation keeps the copy as a backward-compatible default;
   the iOS (native sub-range via arrayToDataRange), Android and JavaSE ports
   override it to write the sub-range directly with no intermediate copy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 1, 2026

Compared 11 screenshots: 11 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Cloudflare Preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 1, 2026

Compared 122 screenshots: 122 matched.

Native Android coverage

  • 📊 Line coverage: 12.78% (7491/58603 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.40% (37475/360472), branch 4.36% (1476/33876), complexity 5.45% (1776/32607), method 9.52% (1457/15311), class 15.53% (332/2138)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 12.78% (7491/58603 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.40% (37475/360472), branch 4.36% (1476/33876), complexity 5.45% (1776/32607), method 9.52% (1457/15311), class 15.53% (332/2138)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1192.000 ms
Base64 CN1 encode 354.000 ms
Base64 encode ratio (CN1/native) 0.297x (70.3% faster)
Base64 native decode 1079.000 ms
Base64 CN1 decode 222.000 ms
Base64 decode ratio (CN1/native) 0.206x (79.4% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 1, 2026

Compared 122 screenshots: 122 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 115 seconds

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 777.000 ms
Base64 CN1 encode 1734.000 ms
Base64 encode ratio (CN1/native) 2.232x (123.2% slower)
Base64 native decode 471.000 ms
Base64 CN1 decode 1258.000 ms
Base64 decode ratio (CN1/native) 2.671x (167.1% slower)
Base64 SIMD encode 516.000 ms
Base64 encode ratio (SIMD/native) 0.664x (33.6% faster)
Base64 encode ratio (SIMD/CN1) 0.298x (70.2% faster)
Base64 SIMD decode 437.000 ms
Base64 decode ratio (SIMD/native) 0.928x (7.2% faster)
Base64 decode ratio (SIMD/CN1) 0.347x (65.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 75.000 ms
Image createMask (SIMD on) 28.000 ms
Image createMask ratio (SIMD on/off) 0.373x (62.7% faster)
Image applyMask (SIMD off) 225.000 ms
Image applyMask (SIMD on) 119.000 ms
Image applyMask ratio (SIMD on/off) 0.529x (47.1% faster)
Image modifyAlpha (SIMD off) 195.000 ms
Image modifyAlpha (SIMD on) 99.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.508x (49.2% faster)
Image modifyAlpha removeColor (SIMD off) 202.000 ms
Image modifyAlpha removeColor (SIMD on) 105.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.520x (48.0% faster)
Image PNG encode (SIMD off) 1296.000 ms
Image PNG encode (SIMD on) 1017.000 ms
Image PNG encode ratio (SIMD on/off) 0.785x (21.5% faster)
Image JPEG encode 627.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 1, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 248 seconds

Build and Run Timing

Metric Duration
Simulator Boot 85000 ms
Simulator Boot (Run) 1000 ms
App Install 11000 ms
App Launch 7000 ms
Test Execution 283000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 749.000 ms
Base64 CN1 encode 1573.000 ms
Base64 encode ratio (CN1/native) 2.100x (110.0% slower)
Base64 native decode 351.000 ms
Base64 CN1 decode 1297.000 ms
Base64 decode ratio (CN1/native) 3.695x (269.5% slower)
Base64 SIMD encode 536.000 ms
Base64 encode ratio (SIMD/native) 0.716x (28.4% faster)
Base64 encode ratio (SIMD/CN1) 0.341x (65.9% faster)
Base64 SIMD decode 475.000 ms
Base64 decode ratio (SIMD/native) 1.353x (35.3% slower)
Base64 decode ratio (SIMD/CN1) 0.366x (63.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 57.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.158x (84.2% faster)
Image applyMask (SIMD off) 189.000 ms
Image applyMask (SIMD on) 49.000 ms
Image applyMask ratio (SIMD on/off) 0.259x (74.1% faster)
Image modifyAlpha (SIMD off) 228.000 ms
Image modifyAlpha (SIMD on) 129.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.566x (43.4% faster)
Image modifyAlpha removeColor (SIMD off) 203.000 ms
Image modifyAlpha removeColor (SIMD on) 262.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.291x (29.1% slower)
Image PNG encode (SIMD off) 1166.000 ms
Image PNG encode (SIMD on) 876.000 ms
Image PNG encode ratio (SIMD on/off) 0.751x (24.9% faster)
Image JPEG encode 470.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented Jun 1, 2026

Compared 122 screenshots: 122 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 343 seconds

Build and Run Timing

Metric Duration
Simulator Boot 91000 ms
Simulator Boot (Run) 2000 ms
App Install 17000 ms
App Launch 9000 ms
Test Execution 376000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 923.000 ms
Base64 CN1 encode 1921.000 ms
Base64 encode ratio (CN1/native) 2.081x (108.1% slower)
Base64 native decode 441.000 ms
Base64 CN1 decode 1505.000 ms
Base64 decode ratio (CN1/native) 3.413x (241.3% slower)
Base64 SIMD encode 611.000 ms
Base64 encode ratio (SIMD/native) 0.662x (33.8% faster)
Base64 encode ratio (SIMD/CN1) 0.318x (68.2% faster)
Base64 SIMD decode 543.000 ms
Base64 decode ratio (SIMD/native) 1.231x (23.1% slower)
Base64 decode ratio (SIMD/CN1) 0.361x (63.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 74.000 ms
Image createMask (SIMD on) 12.000 ms
Image createMask ratio (SIMD on/off) 0.162x (83.8% faster)
Image applyMask (SIMD off) 212.000 ms
Image applyMask (SIMD on) 129.000 ms
Image applyMask ratio (SIMD on/off) 0.608x (39.2% faster)
Image modifyAlpha (SIMD off) 160.000 ms
Image modifyAlpha (SIMD on) 92.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.575x (42.5% faster)
Image modifyAlpha removeColor (SIMD off) 239.000 ms
Image modifyAlpha removeColor (SIMD on) 142.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.594x (40.6% faster)
Image PNG encode (SIMD off) 1417.000 ms
Image PNG encode (SIMD on) 1365.000 ms
Image PNG encode ratio (SIMD on/off) 0.963x (3.7% faster)
Image JPEG encode 758.000 ms

@shai-almog shai-almog merged commit 03eacf0 into master Jun 1, 2026
31 checks passed
@shai-almog shai-almog deleted the fix-socket-npe-offset-write branch June 1, 2026 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant