{"record":{"id":"bd8f085fc257e189","repo":"google/ExoPlayer","slug":"top-bit-not-zero-result","errorCode":null,"errorMessage":"Top bit not zero: {result}","messagePattern":"Top bit not zero: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java","lineNumber":403,"sourceCode":"   * @return The parsed value.\n   */\n  public int readSynchSafeInt() {\n    int b1 = readUnsignedByte();\n    int b2 = readUnsignedByte();\n    int b3 = readUnsignedByte();\n    int b4 = readUnsignedByte();\n    return (b1 << 21) | (b2 << 14) | (b3 << 7) | b4;\n  }\n\n  /**\n   * Reads the next four bytes as an unsigned integer into an integer, if the top bit is a zero.\n   *\n   * @throws IllegalStateException Thrown if the top bit of the input data is set.\n   */\n  public int readUnsignedIntToInt() {\n    int result = readInt();\n    if (result < 0) {\n      throw new IllegalStateException(\"Top bit not zero: \" + result);\n    }\n    return result;\n  }\n\n  /**\n   * Reads the next four bytes as a little endian unsigned integer into an integer, if the top bit\n   * is a zero.\n   *\n   * @throws IllegalStateException Thrown if the top bit of the input data is set.\n   */\n  public int readLittleEndianUnsignedIntToInt() {\n    int result = readLittleEndianInt();\n    if (result < 0) {\n      throw new IllegalStateException(\"Top bit not zero: \" + result);\n    }\n    return result;\n  }\n","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/google/ExoPlayer/blob/dd430f7053a1a3958deea3ead6a0565150c06bfc/library/common/src/main/java/com/google/android/exoplayer2/util/ParsableByteArray.java#L385-L421","documentation":"ParsableByteArray.readUnsignedIntToInt() reads the next four bytes as a signed int and throws IllegalStateException if the result is negative, i.e. if the most significant bit (top bit) of the four bytes is set. The method's contract is to narrow a 32-bit unsigned value into a Java int; a set top bit means the byte stream's value actually needs 32 unsigned bits (>= 2^31), which does not fit, so the data is either malformed or being read at the wrong position with the wrong endianness.","triggerScenarios":"Parsing a container/protocol field documented as '31-bit max' where the encoder wrote a full 32-bit value; reading at a wrong offset so a large size/timestamp field lands in the int slot; interpreting big-endian data as big-endian here is correct but data was written little-endian (use readLittleEndianUnsignedIntToInt instead); corrupted or truncated downloads feeding garbage into the parser.","commonSituations":"Custom or evolving MP4/EBML/section parsers (DVB, PES, HLS tags) where a length field occasionally exceeds Integer.MAX_VALUE on 4K/long recordings; partial file reads making subsequent fields misaligned; firmware/encoder writing nonstandard 32-bit values into fields spec'd at 31 bits.","solutions":["Validate position/limit alignment before reading the field — usually the real bug is an earlier misread offset","If the field legitimately needs 32 bits, switch to readUnsignedInt() (returns long) and range-check it yourself","Use the correct endianness variant: readLittleEndianUnsignedIntToInt for little-endian formats","Wrap container parsing per-item so one malformed field skips the section (with a parser exception) instead of crashing playback"],"exampleFix":"// before\nint size = parsableByteArray.readUnsignedIntToInt(); // top bit set on 4GB-ish payloads\n// after\nlong sizeLong = parsableByteArray.readUnsignedInt();\ncheckState(sizeLong <= Integer.MAX_VALUE, \"Size %s exceeds int range\", sizeLong);\nint size = (int) sizeLong;","handlingStrategy":"try-catch","validationCode":"if (data.limit() - data.getPosition() < 4) { /* not enough bytes: fail before reading */ }","typeGuard":null,"tryCatchPattern":"try { v = p.readUnsignedIntToInt(); } catch (IllegalStateException e) { throw new ParserException(\"Malformed 32-bit field\", e); }","preventionTips":["Use the unsigned-to-long reader (readUnsignedInt) when the field may use all 32 bits","Confirm field endianness against the container spec before parsing","Feed parsers through ExtractorOutput error paths so one bad field fails the item, not playback"],"tags":["parsing","binary","endianness","format"],"backgroundTag":null,"analyzedSha":"dd430f7053a1a3958deea3ead6a0565150c06bfc","analyzedAt":"2026-08-14T12:22:02.982Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}