Skip to content

Harden DMA buffer allocation against transient heap exhaustion#212

Merged
lovyan03 merged 2 commits into
m5stack:developfrom
ainyan03:ai/flipbuffer-dma-hardening
Jul 7, 2026
Merged

Harden DMA buffer allocation against transient heap exhaustion#212
lovyan03 merged 2 commits into
m5stack:developfrom
ainyan03:ai/flipbuffer-dma-hardening

Conversation

@ainyan03

@ainyan03 ainyan03 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #211, extending the null-DMA-buffer protection from the AMOLED framebuffer flush to the whole library.

Problem

IBus::getDMABuffer() returns nullptr when the DMA-capable internal heap is transiently exhausted. #211 guarded one call site, but the same unchecked pattern existed across the panel layer (Panel_LCD, Panel_M5HDMI, Panel_ED2208, Panel_M5UnitLCD, Panel_Device::writeImageARGB), and the underlying buffer classes had a self-inflicted failure mode: on a size change they freed the old buffer before allocating the new one, so a buffer that could still satisfy the request was lost when the allocation failed. SimpleBuffer (used by Bus_I2C) reallocated on any size change, not just growth.

Changes

Buffer layer (platforms/common.hpp)

  • FlipBuffer / SimpleBuffer: shrinking now allocates the smaller buffer first and keeps the old one on failure; a buffer that already satisfies the request is never discarded.
  • New reserve(): pre-allocates and sets a floor below which getBuffer() never shrinks.

Bus layer

  • IBus::reserveDMABuffer() (default no-op), implemented by the esp32-family buses.

Panel layer

  • Panel_Device::init() reserves one line of pixels (covering both rotations), so steady-state draws never reallocate mid-draw.
  • New protected Panel_Device::get_dma_buffer_checked() with edge-triggered ESP_LOGW/ESP_LOGI (no per-frame spam); all live getDMABuffer() call sites in the panel layer now use it and skip the write on failure (Panel_ED2208 breaks to its transaction/CS cleanup instead of returning). Panel_AMOLED migrates its fix: guard against null DMA buffer in Panel_AMOLED_Framebuffer::display() #211-era local helper to the shared one.

Behavior on exhaustion

Instead of a StoreProhibited panic, the affected write is dropped (pixels skipped; the AMOLED framebuffer path retries via its dirty rectangle) and a single warning is logged until recovery.

Notes

  • The init-time reservation makes the previously lazy per-line DMA allocation eager and permanent (e.g. ~5 KB internal RAM for a 1280-wide 16bpp panel). This is intentional: the same memory was allocated on the first full-width draw anyway; now it cannot be lost to transient pressure.
  • Verified with esp32 / esp32s3 builds; an independent adversarial review of the diff found no correctness regressions.
  • Same change ported to LovyanGFX develop.

ainyan03 added 2 commits July 7, 2026 11:37
Follow-up to m5stack#211: apply the same null guard to the three
getDMABuffer() call sites in writeImage(), via a shared
get_dma_buffer_checked() helper with edge-triggered logging.
- FlipBuffer/SimpleBuffer: when shrinking, never discard a buffer that
  still satisfies the request; allocate the smaller one first and keep
  the old one on failure. Add reserve() to pre-size buffers with a
  shrink floor.
- IBus: add reserveDMABuffer(), implemented by esp32-family buses.
- Panel_Device: reserve one line of pixels at init so steady-state
  draws never reallocate; add get_dma_buffer_checked() helper with
  edge-triggered logging.
- Guard the remaining panel-layer getDMABuffer() call sites
  (Panel_LCD, Panel_M5HDMI, Panel_ED2208, Panel_M5UnitLCD,
  writeImageARGB) and migrate Panel_AMOLED to the shared helper.
@lovyan03 lovyan03 merged commit a3673f3 into m5stack:develop Jul 7, 2026
23 checks passed
@lovyan03 lovyan03 deleted the ai/flipbuffer-dma-hardening branch July 7, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants