You've already forked crosspoint-reader
mirror of
https://github.com/crosspoint-reader/crosspoint-reader.git
synced 2026-04-29 10:26:52 -07:00
83cd96bc2f
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.
69 lines
2.2 KiB
Python
69 lines
2.2 KiB
Python
"""
|
|
PlatformIO pre-build script: patch JPEGDEC for MCU_SKIP wild pointer crash.
|
|
|
|
Problem:
|
|
JPEGDecodeMCU_P computes pMCU = &sMCUs[iMCU & 0xffffff]. When iMCU is
|
|
MCU_SKIP (-8), the bitmask produces index 0xFFFFF8 (16 777 208), creating a
|
|
pointer ~33 MB past the 392-entry sMCUs array. If the progressive JPEG's
|
|
first scan includes AC coefficients (iScanEnd > 0), the AC decode loop writes
|
|
through this wild pointer and crashes with a store-access fault.
|
|
|
|
Upstream commit 8628297 guarded the DC coefficient write (pMCU[0]) but not the
|
|
AC coefficient writes at indices 1-63.
|
|
|
|
Fix:
|
|
Redirect pMCU to sMCUs[0] when MCU_SKIP is active. Writes to sMCUs[1..63]
|
|
are harmless: for JPEG_SCALE_EIGHTH only sMCUs[0] is read for output, and
|
|
the DC write at sMCUs[0] is already guarded by the existing `if (iMCU >= 0)`
|
|
check.
|
|
|
|
Applied idempotently — safe to run on every build.
|
|
"""
|
|
|
|
Import("env")
|
|
import os
|
|
|
|
|
|
def patch_jpegdec(env):
|
|
libdeps_dir = os.path.join(env["PROJECT_DIR"], ".pio", "libdeps")
|
|
if not os.path.isdir(libdeps_dir):
|
|
return
|
|
for env_dir in os.listdir(libdeps_dir):
|
|
jpeg_inl = os.path.join(libdeps_dir, env_dir, "JPEGDEC", "src", "jpeg.inl")
|
|
if os.path.isfile(jpeg_inl):
|
|
_apply_mcu_skip_pointer_fix(jpeg_inl)
|
|
|
|
|
|
def _apply_mcu_skip_pointer_fix(filepath):
|
|
MARKER = "// CrossPoint patch: safe pMCU for MCU_SKIP"
|
|
with open(filepath, "r") as f:
|
|
content = f.read()
|
|
|
|
if MARKER in content:
|
|
return # already patched
|
|
|
|
# The wild-pointer line in JPEGDecodeMCU_P:
|
|
OLD = " signed short *pMCU = &pJPEG->sMCUs[iMCU & 0xffffff];"
|
|
|
|
NEW = (
|
|
" " + MARKER + "\n"
|
|
" signed short *pMCU = (iMCU < 0) ? pJPEG->sMCUs\n"
|
|
" : &pJPEG->sMCUs[iMCU & 0xffffff];"
|
|
)
|
|
|
|
if OLD not in content:
|
|
print(
|
|
"WARNING: JPEGDEC MCU_SKIP pointer patch target not found in %s "
|
|
"— library may have been updated" % filepath
|
|
)
|
|
return
|
|
|
|
content = content.replace(OLD, NEW, 1)
|
|
with open(filepath, "w") as f:
|
|
f.write(content)
|
|
print("Patched JPEGDEC: safe pMCU for MCU_SKIP in JPEGDecodeMCU_P: %s" % filepath)
|
|
|
|
|
|
# Run immediately at script import time (before compilation).
|
|
patch_jpegdec(env)
|