Serial-ATA / Serial-ATA/lofty-rs
[AI] Batch of bugs found by an autonomous scanner
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 359
- Forks
- 77
- Avg merge
- 12h 54m
- Merged PRs (30d)
- 11
Description
I'm experimenting with autonomous bug finding to speed up the process of finding bugs. It works by running and diagnosing real code instead of just analyzing the source code (just like I did in https://github.com/Serial-ATA/lofty-rs/issues/656), so it produces quite good results.
Reproducible projects, patches and bug explanations - lofty_rs_bughunt_20260826_080738.zip
| # | Class | Candidate | Fix lines | Root cause |
|---|---|---|---|---|
| 001 | logic | iff/chunk.rs Chunks::next() chunk-size header bounds check |
+4/-1 | Off-by-8 chunk-size bounds check let truncated/oversized chunks slip past validation and hit a hard EOF Err instead of BestAttempt degrading gracefully |
| 002 | crash | jpeg SOF0/SOF2 precision * components multiplication width |
+1/-1 | JPEG SOF0/SOF2 precision * components multiplied as u8 before widening, overflowing when the product exceeds 255 |
| 003 | crash | mp4 ALS branch channel-count u8 truncation before +1 |
+6/-1 | MP4 ALS branch's channel count stsd.read_u16()? as u8 + 1 truncates to u8 before adding 1, overflowing when the value's low byte is 0xFF |
| 005 | logic | iff/chunk.rs Chunks::next() chunk-size header bounds check (AIFF) |
+4/-1 | Same shared Chunks::next() off-by-8 bug as 001, independently confirmed for AIFF via AiffFile::read_from |
| 007 | crash | musepack SV7 true_gapless total_samples divide-by-zero guard |
+5/-0 | SV7 true_gapless branch's total_samples computation hits exactly 0 when frame_count==1 and last_frame_length==0 (both individually valid), causing an unconditional integer divide-by-zero in the bitrate calc; unlike the ruled-out SV4-6 case this is integer (not saturating float) division, and unlike sibling SV8 this branch had no total_samples == 0 guard |
| 011 | crash | mp4 FLAC-in-MP4 dfLa atom len subtract-before-check guard |
+3/-1 | MP4 FLAC-in-MP4 branch's if dfla.len - 12 < 18 subtracts before checking, underflowing a u64 whenever a real dfLa atom's on-disk len is 8-11 (only >= 8 is guaranteed by AtomInfo::read); same subtract-before-check shape as candidate 003, via the fLaC/dfLa codec path |
| 013 | crash | jpeg from_jpeg marker-segment section_len - 2 checked subtraction |
+6/-1 | from_jpeg's per-marker-segment section_len - 2 skip-seek is an unchecked u16 subtraction (unlike the first segment's checked_sub-guarded copy of the same computation), underflowing whenever a non-SOS/SOF marker declares a length of 0 or 1 |
| 015 | crash | iff write_to_chunk_file ID3v2 tag-grew stream-len subtraction sign fix |
+1/-1 | WAV/AIFF ID3v2 write path's "tag grew" branch subtracts (updated_stream_len -= tag_chunk_size - existing_tag_len) when it should add, underflowing whenever a real caller replaces a small existing trailing tag with a larger one |
| 016 | crash | iff write_to_chunk_file ID3v2 tag-grew stream-len subtraction sign fix (AIFF) |
+1/-1 | Same bug as 015, independently confirmed for the AIFF (BigEndian) instantiation of the same shared write_to_chunk_file function via AiffFile::save_to |
| 018 | tooling | ASAN cargo fuzz run hang-scope sweep across the larger *file_read_from fuzz targets |
n/a | Default-ASAN cargo fuzz run hangs on the project's larger *file_read_from targets too (not just 009's small picture_from_* ones), tied to a target's first empty-corpus NEW_FUNC symbolization event - not a lofty source bug |
| 019 | tooling | corpus-seeding ASAN-hang workaround sweep across all fuzz targets | n/a | Swept across all 19 fuzz targets: seeding the corpus with one file does NOT reliably avoid the ASAN hang (only fixed 1/18 hanging targets); mp4file_read_from still hung 6/6 runs with a single-file seed, refuting candidate 018's one-off control observation as a general workaround |
| 020 | logic | iff chunk_file JUNK-padding write size-field off-by-header fix |
+9/-2 | WAV JUNK-padding write branch declares its size field as remainder instead of remainder - IFF_CHUNK_HEADER_SIZE, claiming 8 bytes it never reserved and silently eating into whatever real chunk data physically follows on disk whenever an existing ID3v2 tag shrinks |
| 023 | logic | mp4 ilst atom_tree matched-index Option<usize> tracking fix |
+23/-20 | atom_tree's matched-index bookkeeping can't distinguish "matched at index 0" from "never matched", so a real meta atom with children but no ilst among them has its first real child (e.g. hdlr) silently mistaken for the nonexistent ilst atom and destroyed on every write |
| 024 | tooling | ASAN symbolizer-fork RLIMIT_NOFILE close-loop root-cause + ulimit fix |
n/a | Root cause of the ASAN hang (009/018/019): this sandbox's RLIMIT_NOFILE is ~2.1 billion, and ASAN's forked llvm-symbolizer-launcher child loops close()-ing every fd up to that limit before exec, never finishing; lowering RLIMIT_NOFILE (ulimit -Sn) before an ASAN run fixes it while keeping ASAN active, unlike --sanitizer none |
| 025 | logic | mp4 ilst atom_tree duplicate-sibling first-match write selection fix |
+1/-1 | atom_tree picks the LAST of multiple real ilst siblings to overwrite on write, but the read path always returns the FIRST one, so a tag edit through the real public API silently never becomes visible again on the next read |
| 026 | crash | mp4 AtomInfo::read_inner atom-size-vs-budget off-by-header-length check |
+4/-2 | AtomInfo::read_inner's atom-size-vs-budget check is off by ATOM_HEADER_LEN (8 bytes), letting moov (and any atom) declare a size 8 bytes past the real EOF undetected; mp4/ilst/write.rs's "insert new ilst" path then splices at the resulting out-of-buffer meta_end offset and panics |
| 027 | crash | mp4 update_offsets co64/tfhd checked i64 conversion |
+28/-10 | update_offsets's co64/tfhd offset rewrite reinterprets an unvalidated, file-controlled u64 chunk offset as i64 via a raw as cast instead of a checked conversion, so adding the (small) size-change delta overflows i64 and panics on a crafted file with an out-of-range offset |
| 028 | tooling | corpus-saturation threshold characterization for the ASAN hang | n/a | The ASAN hang (009/018/019/024) only clears once a corpus's composition (not just its size) already covers every function libFuzzer's mutations hit that run - the needed fraction is highly target-dependent (~45-50% for mp4file_read_from, ~70-90%+ for speexfile_read_from) and not reliably predictable in advance, reinforcing candidate 024's ulimit-based fix over corpus tuning |
| 030 | logic | mp4 Moov::parse trak->mdia find_child_atom header-inclusive budget fix |
+6/-2 | Moov::parse's trak->mdia find_child_atom call uses a header-inclusive budget, letting a crafted mdia size overrun into the next moov sibling and silently drop the real, untouched udta/ilst tag with no error |
| 031 | crash | lands candidate 026's AtomInfo::read_inner off-by-header-length fix for real |
+4/-2 | Landed candidate 026's already-verified AtomInfo::read_inner off-by-ATOM_HEADER_LEN fix for real (previously only ever applied temporarily); confirmed the bug independently causes candidate 030's silent-tag-loss symptom even with 030's own separate bug fixed in isolation, though this fix alone doesn't close 030's own call site |
| 032 | logic | lands candidate 030's Moov::parse trak->mdia header-budget fix for real |
+6/-2 | Landed candidate 030's already-verified Moov::parse trak->mdia find_child_atom header-inclusive-budget fix (atom.len - 8) for real (previously only ever applied temporarily); reconfirmed fresh against current mainline before landing |
| 033 | logic | mp4 Minf::parse minf->stbl find_child_atom header-inclusive budget fix |
+1/-1 | Minf::parse's minf->stbl find_child_atom call uses a header-inclusive budget (same shape as 030), letting a crafted stbl size overrun past minf's real end - either silently tolerated or, when the overrun lands on a plausible stsd-looking atom, overwriting real audio properties with garbage and spuriously failing the whole parse |
| 034 | logic | lands candidate 033's Minf::parse minf->stbl header-budget fix for real |
+1/-1 | Landed candidate 033's already-verified Minf::parse minf->stbl find_child_atom header-inclusive-budget fix (len - 8) for real (previously only ever applied temporarily); reconfirmed fresh against current mainline before landing |
| 036 | logic | mp4 update_offsets stco checked u32 conversion |
+10/-5 | update_offsets's stco (32-bit) offset rewrite casts i64::from(read_offset) + difference back to u32 with an unchecked as cast, silently wrapping (no panic, no error) instead of erroring whenever the true sum falls outside 0..=u32::MAX, corrupting the on-disk chunk offset |
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the candidate table and the reproducible-projects archive linked in the issue, then inspect the named parsing or fuzzing entry points for one unlanded candidate. Confirm the reported behavior against the supplied reproduction and current main. Done means addressing one clearly scoped candidate and verifying that its specific crash, corruption, or tooling behavior no longer occurs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, testing-qa, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100