{"record":{"id":"7017c012572fe1c5","repo":"TooTallNate/Java-WebSocket","slug":"destination-array-with-length-d-cannot-have-offse","errorCode":null,"errorMessage":"Destination array with length %d cannot have offset of %d and still store three bytes.","messagePattern":"Destination array with length (.+?) cannot have offset of (.+?) and still store three bytes\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/java_websocket/util/Base64.java","lineNumber":819,"sourceCode":"   */\n  private static int decode4to3(\n      byte[] source, int srcOffset,\n      byte[] destination, int destOffset, int options) {\n\n    // Lots of error checking and exception throwing\n    if (source == null) {\n      throw new IllegalArgumentException(\"Source array was null.\");\n    }   // end if\n    if (destination == null) {\n      throw new IllegalArgumentException(\"Destination array was null.\");\n    }   // end if\n    if (srcOffset < 0 || srcOffset + 3 >= source.length) {\n      throw new IllegalArgumentException(String.format(\n          \"Source array with length %d cannot have offset of %d and still process four bytes.\",\n          source.length, srcOffset));\n    }   // end if\n    if (destOffset < 0 || destOffset + 2 >= destination.length) {\n      throw new IllegalArgumentException(String.format(\n          \"Destination array with length %d cannot have offset of %d and still store three bytes.\",\n          destination.length, destOffset));\n    }   // end if\n\n    final byte[] DECODABET = getDecodabet(options);\n\n    // Example: Dk==\n    if (source[srcOffset + 2] == EQUALS_SIGN) {\n      // Two ways to do the same thing. Don't know which way I like best.\n      //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )\n      //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );\n      int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)\n          | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);\n\n      destination[destOffset] = (byte) (outBuff >>> 16);\n      return 1;\n    }\n","sourceCodeStart":801,"sourceCodeEnd":837,"githubUrl":"https://github.com/TooTallNate/Java-WebSocket/blob/afeacbf8c0f6f6a761c9d9daed8c813dd3b8ed7d/src/main/java/org/java_websocket/util/Base64.java#L801-L837","documentation":"The mirror check on the output side: decode4to3 needs room to write 3 bytes at destOffset. If destOffset is negative or destOffset + 2 >= destination.length, it throws IllegalArgumentException with the destination length and offset. This prevents silent buffer overflow during decoding.","triggerScenarios":"A decode call supplying an output buffer/offset where fewer than 3 bytes remain after destOffset — e.g. destination sized as src.length/3 instead of src.length/4*3, or an offset into a small scratch buffer.","commonSituations":"Miscomputing decoded size (encoded length * 3/4 vs /4*3); reusing a too-small pooled buffer; decoding chunks into a fixed-size output array without bounds tracking.","solutions":["Size the destination as (source.length / 4) * 3 for the full decode, or ensure at least 3 bytes remain from destOffset per call.","Clamp per-iteration writes to the remaining output capacity.","Prefer the single-shot Base64.decode API over manual buffer management."],"exampleFix":"// before\nbyte[] dest = new byte[src.length / 3];\nBase64.decode(src, 0, src.length, dest, 0);\n\n// after\nbyte[] dest = new byte[src.length / 4 * 3];\nBase64.decode(src, 0, src.length, dest, 0);","handlingStrategy":"validation","validationCode":"int outLen = src.length / 4 * 3;\nif (dest == null || destOffset < 0 || destOffset + 3 > dest.length) {\n    dest = new byte[outLen];\n    destOffset = 0;\n}","typeGuard":"static boolean canWriteThreeBytes(byte[] a, int off) {\n    return a != null && off >= 0 && off + 3 <= a.length;\n}","tryCatchPattern":"try {\n    Base64.decode(src, 0, src.length, dest, 0);\n} catch (IllegalArgumentException e) {\n    dest = new byte[src.length / 4 * 3];\n    Base64.decode(src, 0, src.length, dest, 0);\n}","preventionTips":["Size decode output buffers as (input.length / 4) * 3.","Track remaining output capacity when decoding chunks into a shared buffer.","Let the library allocate: use Base64.decode(...) returning a new array."],"tags":["java","base64","out-of-bounds","buffer"],"backgroundTag":"argument-out-of-range","analyzedSha":"afeacbf8c0f6f6a761c9d9daed8c813dd3b8ed7d","analyzedAt":"2026-09-09T14:39:47.546Z","contentChangedAt":"2026-09-09T14:39:47.546Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}