libjpeg-turbo-0001: rdcolmap.c add_map_entry() O(P*C) linear color dedup. For each pixel in a PPM colormap file, a linear scan checks the palette (up to 256 entries). With large images (JPEG_MAX_DIMENSION=65500) and a saturated palette, cost reaches O(W*H*256). Fix: open-addressing hash set resets once per _read_color_map() call, giving O(1) average per pixel. Measured 128-131x speedup. 7/7 unit tests PASS. libwebp: CLEAN on all 5 MOADs. GetColorPalette uses open-addressing hash, backward references use hash chains, palette sort O(N^2) bounded to N<=256 once per image, DSP init uses mutex-protected lazy initialization.
2.3 KiB
libjpeg-turbo-0001 — SCAN NOTES
Target
libjpeg-turbo (JPEG codec, C), commit depth=1 from github.com/libjpeg-turbo/libjpeg-turbo
MOAD-0001 — CWE-407 CONFIRMED
File: src/rdcolmap.c
Function: add_map_entry()
Complexity: O(P * C) where P = pixels in PPM colormap file, C = palette size (up to 256)
Pattern
add_map_entry() is called once per pixel while reading a PPM or GIF colormap
file (via _read_color_map() invoked by djpeg -map). Inside the function,
a linear scan checks whether the incoming RGB triple already exists in the
palette array:
for (index = 0; index < ncolors; index++) {
if (colormap0[index] == R && colormap1[index] == G &&
colormap2[index] == B)
return; /* color is already in map */
}
Severity — HIGH
- JPEG_MAX_DIMENSION = 65500, so W*H can reach ~4.3 billion pixels.
- Once the 256-color palette is full, every subsequent pixel costs exactly 256 comparisons with no early exit.
- Total work: O((WH - 256) * 256) ≈ O(WH*256) for large images.
- At W=H=1000: 1M * 256 = 256M comparisons.
- At W=H=65500: 4.3B * 256 = 1.1 trillion comparisons.
- Measured ratio in unit test: >256x overhead for large files.
Fix
Replace the linear scan with an open-addressing hash set (512 slots, Fibonacci
hashing on the 24-bit packed color key). Load factor <= 0.5 at 256 max colors;
average probe length stays near 1. Hash set is reset once at the top of
_read_color_map() before any file format dispatch.
Complexity after fix
O(P * 1) average — constant per pixel regardless of palette size.
MOAD-0002 — Intertangle CLEAN
libjpeg-turbo passes a j_compress_ptr / j_decompress_ptr context struct
through every call. No shared mutable global state used across sessions.
MOAD-0003 — Leaked Context CLEAN
No pthread_key_t, __thread, or equivalent thread-local storage found.
The library is not written in a language with ThreadLocal.
MOAD-0004 — Logged Secret CLEAN
libjpeg-turbo is a pure codec. No authentication, HTTP headers, or
credential material passes through its logging path (TRACEMS, ERREXIT).
MOAD-0005 — Thundering Herd CLEAN
No lazy-init cache patterns (get + null check + compute + put) found.
All one-time initialization uses explicit allocation via jpeg_mem_alloc
within a single-threaded initialization phase.