{"record":{"id":"d5eeddeb95341107","repo":"Tencent/tinker","slug":"length-arraylength-regionstart-offset-regi","errorCode":null,"errorMessage":"length=${arrayLength}; regionStart=${offset}; regionLength=${count}","messagePattern":"length=(.+?); regionStart=(.+?); regionLength=(.+?)","errorType":"exception","errorClass":"ArrayIndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/AlignedZipOutputStream.java","lineNumber":474,"sourceCode":"    @Override\r\n    public void write(byte[] buffer, int offset, int byteCount) throws IOException {\r\n        checkOffsetAndCount(buffer.length, offset, byteCount);\r\n        if (currentEntry == null) {\r\n            throw new ZipException(\"No active entry\");\r\n        }\r\n\r\n        if (currentEntry.getMethod() == STORED) {\r\n            out.write(buffer, offset, byteCount);\r\n        } else {\r\n            super.write(buffer, offset, byteCount);\r\n        }\r\n        crc.update(buffer, offset, byteCount);\r\n        crcDataSize += byteCount;\r\n    }\r\n\r\n    private void checkOffsetAndCount(int arrayLength, int offset, int count) {\r\n        if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {\r\n            throw new ArrayIndexOutOfBoundsException(\"length=\" + arrayLength + \"; regionStart=\" + offset\r\n                    + \"; regionLength=\" + count);\r\n        }\r\n    }\r\n\r\n    private void checkOpen() throws IOException {\r\n        if (closed) {\r\n            throw new IOException(\"Stream is closed\");\r\n        }\r\n    }\r\n}\r\n","sourceCodeStart":456,"sourceCodeEnd":485,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/AlignedZipOutputStream.java#L456-L485","documentation":"checkOffsetAndCount is a bounds guard for (buffer, offset, byteCount) triples, mirroring Arrays.checkOffsetAndCount: it rejects negative offset/count, offset beyond arrayLength, or offset+count exceeding arrayLength, throwing ArrayIndexOutOfBoundsException with a diagnostic message showing all three values. It exists to give a precise message instead of the JVM's generic AIOOBE when write() is called with a bad slice.","triggerScenarios":"Calling AlignedZipOutputStream.write(byte[] buffer, int offset, int byteCount) (or an internal path that funnels through this check) with offset/count that do not describe a valid region of buffer — e.g. offset == buffer.length with byteCount > 0, or negative byteCount from an upstream length computation.","commonSituations":"Streaming loops that compute remaining lengths incorrectly (int underflow near end of stream); passing (buffer, start, buffer.length) instead of (buffer, start, buffer.length - start); reused buffer pools where the working length is tracked separately from the array length and drifts.","solutions":["Fix the slice arithmetic at the call site: valid ranges satisfy offset >= 0, byteCount >= 0, offset + byteCount <= buffer.length.","In streaming loops, compute byteCount = Math.min(chunkSize, total - position) rather than reusing stale lengths.","Add an assertion/log of (buffer.length, offset, byteCount) before write while debugging to see which term drifts."],"exampleFix":"// before: wrong slice length passed to write\nzos.write(buf, off, buf.length); // throws when off > 0\n\n// after: pass the remaining region, not the full array length\nzos.write(buf, off, buf.length - off);","handlingStrategy":"validation","validationCode":"// Validate the (buffer, offset, count) triple before writing\nstatic boolean validRegion(byte[] buf, int off, int count) {\n    return off >= 0 && count >= 0 && off <= buf.length && buf.length - off >= count;\n}\nif (!validRegion(buffer, offset, byteCount)) throw new IndexOutOfBoundsException(\"bad write slice\");\nzos.write(buffer, offset, byteCount);","typeGuard":null,"tryCatchPattern":"try {\n    zos.write(buffer, offset, byteCount);\n} catch (ArrayIndexOutOfBoundsException e) {\n    throw new IllegalStateException(\"bad slice: buf.length=\" + buffer.length\n        + \" offset=\" + offset + \" count=\" + byteCount, e);\n}","preventionTips":["In streaming loops compute count = Math.min(chunk, remaining) fresh each iteration.","Never pass buffer.length as count when offset is non-zero — use buffer.length - offset.","Prefer ByteBuffer.slice() to hand-rolled offset arithmetic."],"tags":["zip","bounds-check","array-index","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}