A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: Wild pointer crash in JPEGDEC MCU_SKIP handling (#1627)

Adds a PlatformIO pre-build script to patch JPEGDEC library. When
decoding progressive JPEGs with AC coefficients, MCU_SKIP (-8) causes
array index 0xFFFFF8, creating a wild pointer ~33MB past the sMCUs
array. The patch redirects pMCU to sMCUs[0] when MCU_SKIP is active,
preventing store-access faults while maintaining correct behavior for
JPEG_SCALE_EIGHTH decoding. Devices with larger framebuffers (like the
x3) (792×528 = 52,272 bytes vs 800×480 = 48,000 bytes) have less free
heap, shifting the allocation and changing where the wild pointer lands.

Commit 8628297 guarded the DC coefficient write (pMCU[0]) with if (iMCU
>= 0), which prevents crashes for progressive JPEGs whose first scan is
DC-only (iScanEnd == 0). However, if the first scan includes AC
coefficients (iScanEnd > 0), the AC decode loop still writes through the
wild pointer and crashes.

authored by

Justin Mitchell and committed by
GitHub
83cd96bc 14ec53a3

+69
+1
platformio.ini
··· 51 51 pre:scripts/build_html.py 52 52 pre:scripts/gen_i18n.py 53 53 pre:scripts/git_branch.py 54 + pre:scripts/patch_jpegdec.py 54 55 55 56 ; Libraries 56 57 lib_deps =
+68
scripts/patch_jpegdec.py
··· 1 + """ 2 + PlatformIO pre-build script: patch JPEGDEC for MCU_SKIP wild pointer crash. 3 + 4 + Problem: 5 + JPEGDecodeMCU_P computes pMCU = &sMCUs[iMCU & 0xffffff]. When iMCU is 6 + MCU_SKIP (-8), the bitmask produces index 0xFFFFF8 (16 777 208), creating a 7 + pointer ~33 MB past the 392-entry sMCUs array. If the progressive JPEG's 8 + first scan includes AC coefficients (iScanEnd > 0), the AC decode loop writes 9 + through this wild pointer and crashes with a store-access fault. 10 + 11 + Upstream commit 8628297 guarded the DC coefficient write (pMCU[0]) but not the 12 + AC coefficient writes at indices 1-63. 13 + 14 + Fix: 15 + Redirect pMCU to sMCUs[0] when MCU_SKIP is active. Writes to sMCUs[1..63] 16 + are harmless: for JPEG_SCALE_EIGHTH only sMCUs[0] is read for output, and 17 + the DC write at sMCUs[0] is already guarded by the existing `if (iMCU >= 0)` 18 + check. 19 + 20 + Applied idempotently — safe to run on every build. 21 + """ 22 + 23 + Import("env") 24 + import os 25 + 26 + 27 + def patch_jpegdec(env): 28 + libdeps_dir = os.path.join(env["PROJECT_DIR"], ".pio", "libdeps") 29 + if not os.path.isdir(libdeps_dir): 30 + return 31 + for env_dir in os.listdir(libdeps_dir): 32 + jpeg_inl = os.path.join(libdeps_dir, env_dir, "JPEGDEC", "src", "jpeg.inl") 33 + if os.path.isfile(jpeg_inl): 34 + _apply_mcu_skip_pointer_fix(jpeg_inl) 35 + 36 + 37 + def _apply_mcu_skip_pointer_fix(filepath): 38 + MARKER = "// CrossPoint patch: safe pMCU for MCU_SKIP" 39 + with open(filepath, "r") as f: 40 + content = f.read() 41 + 42 + if MARKER in content: 43 + return # already patched 44 + 45 + # The wild-pointer line in JPEGDecodeMCU_P: 46 + OLD = " signed short *pMCU = &pJPEG->sMCUs[iMCU & 0xffffff];" 47 + 48 + NEW = ( 49 + " " + MARKER + "\n" 50 + " signed short *pMCU = (iMCU < 0) ? pJPEG->sMCUs\n" 51 + " : &pJPEG->sMCUs[iMCU & 0xffffff];" 52 + ) 53 + 54 + if OLD not in content: 55 + print( 56 + "WARNING: JPEGDEC MCU_SKIP pointer patch target not found in %s " 57 + "— library may have been updated" % filepath 58 + ) 59 + return 60 + 61 + content = content.replace(OLD, NEW, 1) 62 + with open(filepath, "w") as f: 63 + f.write(content) 64 + print("Patched JPEGDEC: safe pMCU for MCU_SKIP in JPEGDecodeMCU_P: %s" % filepath) 65 + 66 + 67 + # Run immediately at script import time (before compilation). 68 + patch_jpegdec(env)