MuntashirAkon/AppManager · error · IOException
Block overrun in MTF, " + lastShadow + " exceeds " + limitLa
Error message
Block overrun in MTF, " + lastShadow + " exceeds " + limitLast
What it means
In the MTF (move-to-front) decoding stage, a plain symbol increments lastShadow; if it reaches or exceeds limitLast the block produced more output than its declared size, indicating corruption. This guard prevents writing past the block's bounds.
Source
Thrown at app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java:659
checkBounds(s, this.data.ll8.length, "s");
final int yy0 = yy[0];
checkBounds(yy0, 256, "yy");
final byte ch = seqToUnseq[yy0];
unzftab[ch & 0xff] += s + 1;
final int from = ++lastShadow;
lastShadow += s;
checkBounds(lastShadow, this.data.ll8.length, "lastShadow");
Arrays.fill(ll8, from, lastShadow + 1, ch);
if (lastShadow >= limitLast) {
throw new IOException("Block overrun while expanding RLE in MTF, "
+ lastShadow + " exceeds " + limitLast);
}
} else {
if (++lastShadow >= limitLast) {
throw new IOException("Block overrun in MTF, "
+ lastShadow + " exceeds " + limitLast);
}
checkBounds(nextSym, 256 + 1, "nextSym");
final char tmp = yy[nextSym - 1];
checkBounds(tmp, 256, "yy");
unzftab[seqToUnseq[tmp] & 0xff]++;
ll8[lastShadow] = seqToUnseq[tmp];
/*
* This loop is hammered during decompression, hence avoid
* native method call overhead of System.arraycopy for very
* small ranges to copy.
*/
if (nextSym <= 16) {
for (int j = nextSym - 1; j > 0;) {
yy[j] = yy[--j];
}View on GitHub (pinned to 0152f468fc)
Solutions
- Re-verify/re-download the archive; the data is corrupt.
- Don't reuse or resume partially read streams; decompress from the beginning.
- Catch IOException and handle as 'corrupt input', not as a library bug.
- Constrain decompressed output size for untrusted inputs (decompression-bomb defense).
Example fix
// before
readAll(bz); // crashes with raw IOException
// after
try { readAll(bz); }
catch (IOException e) { log.warn("Corrupt bzip2 member skipped: " + e.getMessage()); } Defensive patterns
Strategy: try-catch
Try / catch
try { readAll(bz); }
catch (IOException e) {
log.warn("Skipping corrupt bzip2 member: {}", e.getMessage());
} Prevention
- Decompress from byte 0; never reuse partially-consumed streams
- Detect truncation before reading (compare file size/checksum)
- Apply output-size limits for hostile inputs
- Fail fast: don't write partially decoded output to final storage
When it happens
Trigger: BZip2CompressorInputStream.read() while decoding a bzip2 block: an MTF symbol increments lastShadow to >= limitLast.
Common situations: Bit-corrupted .bz2 files, truncated transfers, hostile/fuzzed inputs, wrong decoder fed non-bzip2 bytes.
Related errors
- Corrupted input, " + name + " value negative
- Corrupted input, " + name + " value too big
- Corrupted input, nSelectors value negative
- Block overrun while expanding RLE in MTF, " + lastShadow + "
- Stream corrupted
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/29506fc882ceb355.
Report an issue: GitHub.