{"record":{"id":"cb35e9334cf3e8e3","repo":"prestodb/presto","slug":"arrayoffset-is-negative-cb35e9","errorCode":null,"errorMessage":"arrayOffset is negative","messagePattern":"arrayOffset is negative","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/ByteArrayBlock.java","lineNumber":66,"sourceCode":"    public static final int SIZE_IN_BYTES_PER_POSITION = Byte.BYTES + Byte.BYTES;\n\n    private final int arrayOffset;\n    private final int positionCount;\n    @Nullable\n    private final boolean[] valueIsNull;\n    private final byte[] values;\n\n    private final long retainedSizeInBytes;\n\n    public ByteArrayBlock(int positionCount, Optional<boolean[]> valueIsNull, byte[] values)\n    {\n        this(0, positionCount, valueIsNull.orElse(null), values);\n    }\n\n    ByteArrayBlock(int arrayOffset, int positionCount, boolean[] valueIsNull, byte[] values)\n    {\n        if (arrayOffset < 0) {\n            throw new IllegalArgumentException(\"arrayOffset is negative\");\n        }\n        this.arrayOffset = arrayOffset;\n        if (positionCount < 0) {\n            throw new IllegalArgumentException(\"positionCount is negative\");\n        }\n        this.positionCount = positionCount;\n\n        if (values.length - arrayOffset < positionCount) {\n            throw new IllegalArgumentException(\"values length is less than positionCount\");\n        }\n        this.values = values;\n\n        if (valueIsNull != null && valueIsNull.length - arrayOffset < positionCount) {\n            throw new IllegalArgumentException(\"isNull length is less than positionCount\");\n        }\n        this.valueIsNull = valueIsNull;\n\n        retainedSizeInBytes = (INSTANCE_SIZE + sizeOf(valueIsNull) + sizeOf(values));","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/ByteArrayBlock.java#L48-L84","documentation":"The package-private ByteArrayBlock constructor validates its arrayOffset parameter and throws this IllegalArgumentException if it is negative. arrayOffset is the starting index into the shared byte[] values array; a negative offset would make all position math invalid. It is a defensive precondition against malformed construction arguments.","triggerScenarios":"Constructing ByteArrayBlock (directly in package code, or via the public constructor paths that forward) with a negative arrayOffset, usually from bad offset arithmetic when wrapping a sub-range of a larger byte buffer.","commonSituations":"Custom connector code slicing a page/buffer with a computed offset that underflowed (offset -= size going negative); reusing offset variables across loops; buggy serialization/deserialization code that reconstructs blocks with incorrect offsets.","solutions":["Fix the offset computation so it is never negative; clamp with Math.max(0, offset) only if a negative value is legitimate 'no data' semantics.","If the intent was an empty view, pass arrayOffset 0 with positionCount 0 instead of a negative offset.","Audit the code that wraps sub-arrays and add an explicit assertion offset >= 0 near the slice computation."],"exampleFix":"// before\nint offset = previousEnd - sliceSize; // can go negative\nnew ByteArrayBlock(offset, count, valueIsNull, values);\n// after\nint offset = Math.max(0, previousEnd - sliceSize);\ncheckArgument(offset >= 0, \"computed slice offset is negative\");\nnew ByteArrayBlock(offset, count, valueIsNull, values);","handlingStrategy":"validation","validationCode":"if (arrayOffset < 0) {\n    throw new IllegalArgumentException(\"computed arrayOffset is negative: \" + arrayOffset);\n}\nnew ByteArrayBlock(arrayOffset, positionCount, valueIsNull, values);","typeGuard":"boolean isValidBlockArgs(int arrayOffset, int positionCount) {\n    return arrayOffset >= 0 && positionCount >= 0;\n}","tryCatchPattern":"try {\n    block = new ByteArrayBlock(arrayOffset, positionCount, valueIsNull, values);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"arrayOffset is negative\")) {\n        throw new IllegalStateException(\"negative slice offset from \" + offsetSource, e);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Clamp or assert slice offsets with Math.max(0, ...) / checkArgument(offset >= 0) at the slicing site.","Avoid reusing offset accumulators across iterations without resetting them.","Use 0 offset with positionCount 0 to represent an empty view.","Add range assertions in any custom code that wraps sub-arrays of larger buffers."],"tags":["presto","block","argument-validation","bytearray"],"backgroundTag":"invalid-argument","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}