Repository navigation
fix(lua): address Bitmap image review feedback - #2
Merged
thomaskistler merged 7 commits intoOct 26, 2026
Merged
thomaskistler merged 7 commits into
thomaskistler merged 7 commits into
Conversation
thomaskistler
force-pushed
the
thomaskistler/bitmap-review-fixes
branch
4 times, most recently
from
October 26, 2026 05:04
bed01eb to
b056ca1
Compare
Address review point 1. Release native Bitmap resources immediately but keep the parent-owned registry slot and handle until deferred cleanup. Delete image wrappers exactly once, guard deleted windows, and retain the main Lua thread. Reject only explicit parents whose image window was deleted, so windowless objects such as labels still fall back to the script window. Include lifecycle, ref-slot reuse, coroutine and windowless-parent regressions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Address review point 2. Parse the file/bitmap source after all other image parameters, so a rejected property never replaces it. Validate the new source and acquire its ref and conversion buffer before releasing the old source, so validation and allocation errors leave the current image intact. Read source fields with raw lookups so params table __index metamethods cannot run during the update. Include rejected-update, metamethod and decoded JPEG zero-copy regressions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Address review point 3. Protect image construction and explicitly clean failed objects, native windows, registry refs and conversion charges. Restore parent context on failure, including child construction. Include repeated constructor failure and resource-baseline regressions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Address review point 4. Remove the experimental capability constant and document main's Bitmap addition in 3.0.0 without guessing a 2.12 backport release. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Address review point 5. Allow file plus bitmap=false to select the file source regardless of table traversal order, while rejecting file plus an actual Bitmap. Document and test both source-field orders. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
lvgl.clear(image) cleans the StaticImage window, which deletes its internal LVGL image object without updating StaticImage::image. A later source change or image teardown then deleted the stale pointer again. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
lvgl.build() and children of page/dialog constructors set a temporary parent while building nested objects but never restored it when a child raised. Later constructors were attached to that parent, which might already have been released and deleted. Build nested objects in a protected call and restore the previous parent before rethrowing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
thomaskistler
force-pushed
the
thomaskistler/bitmap-review-fixes
branch
from
October 26, 2026 05:18
b056ca1 to
4ffde23
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes: N/A (review follow-up; no linked issue).
Summary of changes:
Review follow-up to the Bitmap source support for
lvgl.image(#1 / EdgeTX#7947). This PR targets the Bitmap feature branch, so the diff contains only the fixes. Commits 1–5 address the five points in pfeerick's review comment. Fixes for two regressions found later in commits 1 and 2 are folded into those commits. Commits 6 and 7 fix further problems found in a later combined review of #1 and this PR. Each commit has its own regression tests.Behavior note:
image:set({file=...})now actually changes the displayed image and replaces any previous filename callback. Previously the new path was stored but never applied, and an existing callback kept overriding it.1. Native window deletion freed the image's Lua handle early (
047256d0dc, review point 1)Issue: The image's
LV_EVENT_DELETEhandler released the image's registry ref and deleted the wrapper, but the parent's child list still held that ref number. Lua reuses freed registry slots, so afterbox:clear()a newly created object could get the same slot. The parent's next cleanup then cleared that unrelated object instead. The same happened after native page or dialog close. The handler also stored the caller'slua_State, which could be a coroutine that has since been garbage-collected.Fix: The delete handler now only releases the Bitmap (and any conversion buffer) and forgets the window. The handle and its registry slot stay valid until the parent's normal cleanup, which then deletes the wrapper exactly once. Image methods, callbacks and visibility checks are guarded while the window is gone.
set()on such an image raises "Image window has been deleted". The handler uses the main Lua thread rather than the creating coroutine.The new deleted-parent check for
lvgl.image(parent, ...)andlvgl.build(parent, ...)asks the object whether its window was deleted. Only images track that state, so labels, lines and triangles, which have no window, can still be used as parents and fall back to the script window as before.2. A failed
set()could leave the image blank (16a8e27cf8, review point 2)Issue:
image:set({file = {}})cleared the displayed Bitmap before the file value was validated.image:set({bitmap = b2, bogus = 1})could swap the source before the invalid key raised, depending on table iteration order. Either way the image stayed blank until the next successfulset().Fix: The
file/bitmapsource is parsed after all other parameters, so an invalid key raises before the source is touched. The new source is fully validated first: its type, unloaded or oversized Bitmaps, the pixel format and the memory budget. Its ref and conversion buffer are acquired next, and only then is the old source released and replaced. Any error therefore leaves the current image intact.fileandbitmapare read with raw lookups, so an__indexmetamethod on the params table can't run Lua during the update.Other parameters in a rejected
set()behave as for every other widget: keys processed before the error stay applied. Only the image source is guaranteed to stay unchanged.3. Failed constructors leaked the Bitmap and its memory-budget charge (
864507a22e, review point 3)Issue:
lvgl.image({bitmap = b, badkey = 1})raised after taking the Bitmap ref, allocating the ARGB4444 conversion buffer and charging the Lua bitmap memory budget. Nothing released them, so each failure permanently shrank the budget available toBitmap.open().Fix: Image construction runs in a protected call. On failure the image's refs, conversion buffer, budget charge, native window and wrapper are all released. Failures while creating
childrenrelease the partially built object, and the previous temporary parent is restored.4. Remove
lvgl.IMAGE_BITMAP_SUPPORTED(717342fbde, review point 4)Issue: Scripts should detect the feature with a firmware version check, so the extra capability constant and its
@noticearen't needed. The@statusline also needed updating.Fix: Removed the constant and its documentation.
@statusnow says Bitmap support was added in 3.0.0, main's current version. If this is backported to 2.12, the backport needs the matching 2.12.x version.5.
{file = ..., bitmap = false}was rejected (13a1c6b127, review point 5)Issue: The conflict check treated
bitmap = falseas a Bitmap, soimage:set({file = "/IMAGES/a.png", bitmap = false})failed with "Specify either file or bitmap, not both". The result also depended on table iteration order.Fix:
fileandbitmapare read once, after the other parameters, so field order doesn't matter.falsemeans "no Bitmap": withfileit selects the file, alone it clears the image. A real Bitmap together withfileis still rejected.6.
lvgl.clear(image)left a dangling image object (46c307b32f)Issue:
lvgl.clear(image)cleans theStaticImagewindow, which deletes its internal LVGL image object, butStaticImagekept the pointer. The next source change,image:set({bitmap=false})or teardown calledlv_obj_del()on freed memory and crashed.Fix:
StaticImagenow overridesclear()and resets its image pointer after the window is cleaned. Later source changes create a new image object.7. A failed child build left the wrong parent active (
4ffde2356b)Issue:
lvgl.build()and thechildrenof page/dialog constructors set a temporary parent while building nested objects but never restored it when a child raised. Objects created later were attached to that parent. With deferred image deletion, that parent could already be a deleted image wrapper.Fix: Nested objects are built in a protected call, and the previous parent is restored before the error is re-raised.
Validation
Native TX16S Debug build on macOS with AppleClang:
cmake --build native --target gtests-radio: passed for each of the 7 commits../gtests-radio --gtest_filter='LuaBitmapImage.*:Lua.*:MainWindow.*:color.*:Lcd_colorlcd.bitmap:Keyboard.*'at head (4ffde2356b): passed, 57 tests../gtests-radio(full suite) at head: passed, 274 tests.MallocScribble=1 MallocGuardEdges=1 ./gtests-radio --gtest_filter='LuaBitmapImage.*' --gtest_repeat=20at head: passed, all 32 image tests in each of the 20 runs. These macOS malloc debugging settings are not sanitizer coverage.__indexfixes (now in commits 1 and 2) and for commits 6 and 7 were also run against the code without each fix; each one failed or crashed there.Not run: