{"record":{"id":"3c71ec61e00881c9","repo":"apache/pulsar","slug":"off-off-len-len-b-length-b-length","errorCode":null,"errorMessage":"off=${off}, len=${len}, b.length=${b.length}","messagePattern":"off=(.+?), len=(.+?), b\\.length=(.+?)","errorType":"validation","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"tiered-storage/jcloud/src/main/java/org/apache/bookkeeper/mledger/offload/jcloud/impl/BlockAwareSegmentInputStreamImpl.java","lineNumber":223,"sourceCode":"\n                entries.add(entryBuf);\n            }\n            return entries;\n        } catch (InterruptedException | ExecutionException e) {\n            log.error().exception(e).log(\"Exception when getting LedgerEntries\");\n            if (e instanceof InterruptedException) {\n                Thread.currentThread().interrupt();\n            }\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public int read(byte[] b, int off, int len) throws IOException {\n        if (b == null) {\n            throw new NullPointerException(\"The given bytes are null\");\n        } else if (off < 0 || len < 0 || len > b.length - off) {\n            throw new IndexOutOfBoundsException(\"off=\" + off + \", len=\" + len + \", b.length=\" + b.length);\n        } else if (len == 0) {\n            return 0;\n        }\n\n        int offset = off;\n        int readLen = len;\n        int readBytes = 0;\n        // reading header\n        if (dataBlockHeaderStream.available() > 0) {\n            int read = dataBlockHeaderStream.read(b, off, len);\n            offset += read;\n            readLen -= read;\n            readBytes += read;\n            bytesReadOffset += read;\n        }\n        if (readLen == 0) {\n            return readBytes;\n        }","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/tiered-storage/jcloud/src/main/java/org/apache/bookkeeper/mledger/offload/jcloud/impl/BlockAwareSegmentInputStreamImpl.java#L205-L241","documentation":"BlockAwareSegmentInputStreamImpl.read(byte[], int, int) enforces InputStream argument bounds: if off < 0, len < 0, or len > b.length - off, it throws IndexOutOfBoundsException with the offending off/len/b.length values.","triggerScenarios":"Calling read(b, off, len) where off+len exceeds the buffer length, or off/len is negative — e.g. computing len from remaining bytes without clamping after EOF.","commonSituations":"Caller computing len = buffer.length - off with an off larger than the buffer; retry loops not shrinking len after partial reads; mismatched block-size constants between writer and reader.","solutions":["Validate before calling: ensure 0 <= off <= b.length and 0 <= len <= b.length - off","Clamp len to Math.min(len, b.length - off) and bail out when it becomes <= 0","Check block-size/off calculations in the offload copy loop"],"exampleFix":"// before\nint n = stream.read(buf, off, buf.length); // IOOBE when off > 0\n// after\nint len = Math.min(requested, buf.length - off);\nint n = len > 0 ? stream.read(buf, off, len) : -1;","handlingStrategy":"validation","validationCode":"static int[] validated(byte[] b, int off, int len) {\n  if (off < 0 || len < 0 || len > b.length - off)\n    throw new IndexOutOfBoundsException(\"off=\" + off + \", len=\" + len + \", b.length=\" + b.length);\n  return new int[]{off, len};\n}","typeGuard":"static boolean inBounds(byte[] b, int off, int len) {\n  return b != null && off >= 0 && len >= 0 && len <= b.length - off;\n}","tryCatchPattern":"try {\n  int n = stream.read(buf, off, len);\n} catch (IndexOutOfBoundsException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"off=\")) {\n    off = 0; len = Math.min(len, buf.length); // recompute and retry\n  } else throw e;\n}","preventionTips":["Clamp len to b.length - off before every read","Recompute remaining bytes after partial reads instead of reusing stale off/len","Prefer helper wrappers (e.g. DataInputStream.readFully semantics) that handle bounds"],"tags":["indexoutofbounds","io","inputstream","bounds-check"],"backgroundTag":"buffer-out-of-bounds","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}