{"record":{"id":"fc118165231807e5","repo":"apache/pulsar","slug":"nbits-0-nbits","errorCode":null,"errorMessage":"nbits < 0: <nbits>","messagePattern":"nbits < 0: <nbits>","errorType":"validation","errorClass":"NegativeArraySizeException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java","lineNumber":128,"sourceCode":"     */\n    public BitSetRecyclable() {\n        initWords(BITS_PER_WORD);\n        sizeIsSticky = false;\n    }\n\n    /**\n     * Creates a bit set whose initial size is large enough to explicitly\n     * represent bits with indices in the range {@code 0} through\n     * {@code nbits-1}. All bits are initially {@code false}.\n     *\n     * @param  nbits the initial size of the bit set\n     * @throws NegativeArraySizeException if the specified initial size\n     *         is negative\n     */\n    public BitSetRecyclable(int nbits) {\n        // nbits can't be negative; size 0 is OK\n        if (nbits < 0)\n            throw new NegativeArraySizeException(\"nbits < 0: \" + nbits);\n\n        initWords(nbits);\n        sizeIsSticky = true;\n    }\n\n    private void initWords(int nbits) {\n        words = new long[wordIndex(nbits-1) + 1];\n    }\n\n    /**\n     * Creates a bit set using words as the internal representation.\n     * The last word (if there is one) must be non-zero.\n     */\n    private BitSetRecyclable(long[] words) {\n        this.words = words;\n        this.wordsInUse = words.length;\n        checkInvariants();\n    }","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java#L110-L146","documentation":"BitSetRecyclable(int nbits) mirrors java.util.BitSet's constructor: a negative initial bit count is rejected with NegativeArraySizeException(\"nbits < 0: \" + nbits) before any words are allocated. The library throws this to fail fast rather than letting an internal long[] allocation fail confusingly, since a negative length array is impossible. A size of 0 is explicitly allowed.","triggerScenarios":"Constructing new BitSetRecyclable(n) where n < 0, typically when n comes from a computation such as (numBits/8 + 1)*8 gone wrong, an unchecked cast, a corrupted length header, or a recycled/recyclable value that was reset to -1 as a sentinel and passed straight to the constructor.","commonSituations":"Deserializing a payload whose declared bit-set length is negative (corrupt or hostile data); arithmetic overflow wrapping a large positive count to negative; calling the constructor inside a recycling path where a sentinel value (-1 meaning 'uninitialized') leaks through; off-by-one/negative results from subtracting sizes.","solutions":["Clamp or reject before construction: if (n < 0) n = 0; or throw a domain-specific error naming the source of n.","If n is a sentinel for 'not set', branch on it explicitly instead of passing it to the constructor.","Check the arithmetic producing n for overflow (use Math.addExact/Math.multiplyExact) and for integer division/cast errors.","If the value comes from deserialized data, validate the length header against remaining bytes before trusting it."],"exampleFix":"// before\nint nbits = header.getLength(); // may be -1 sentinel\nBitSetRecyclable set = new BitSetRecyclable(nbits);\n\n// after\nint nbits = header.getLength();\nif (nbits < 0) nbits = 0; // treat sentinel/invalid as empty bit set\nBitSetRecyclable set = new BitSetRecyclable(nbits);","handlingStrategy":"validation","validationCode":"static BitSetRecyclable newBitSet(int nbits) {\n    if (nbits < 0) {\n        throw new IllegalArgumentException(\"nbits must be >= 0, got \" + nbits + \" (check sentinel/overflow)\");\n    }\n    return new BitSetRecyclable(nbits);\n}","typeGuard":"static boolean isValidBitSetSize(int n) { return n >= 0; }","tryCatchPattern":"try {\n    BitSetRecyclable set = new BitSetRecyclable(nbits);\n} catch (NegativeArraySizeException e) {\n    log.warn(\"Non-positive bit-set size requested: {}\", e.getMessage());\n    BitSetRecyclable set = new BitSetRecyclable(0); // or rethrow as a data-corruption error\n}","preventionTips":["Handle -1-style sentinels explicitly before passing values to the constructor.","Use Math.addExact/Math.multiplyExact for size arithmetic to catch overflow.","Validate length fields from deserialized/wire data before using them as sizes.","Write a unit test asserting the constructor rejects negative sizes so regressions surface early."],"tags":["java","bitset","negative-array-size"],"backgroundTag":"negative-array-size","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}