Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fixed issue 148 draw context stack overflow - #158

Merged
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow
Jun 1, 2026
Merged

Fixed issue 148 draw context stack overflow#158
fdesbiens merged 2 commits into
eclipse-threadx:devfrom
fdesbiens:fix/issue-148-draw-context-stack-overflow

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

No description provided.

fdesbiensand others added 2 commits June 1, 2026 17:23
All callers of _gx_canvas_drawing_initiate() must check the return
value before calling draw functions or _gx_canvas_drawing_complete().
When GX_DRAW_NESTING_EXCEEDED is returned the context stack is NOT
pushed, so calling _gx_canvas_drawing_complete() corrupts the outer
context's nesting counter.
Fix pattern (matching _gx_widget_children_draw.c reference impl):
status = _gx_canvas_drawing_initiate(...);
if (status == GX_SUCCESS) { draw(); _gx_canvas_drawing_complete(); }
else if (status == GX_NO_VIEWS) { _gx_canvas_drawing_complete(); }
// else: stack overflow or invalid memory -- do nothing
Files fixed:
- gx_animation_start.c
- gx_animation_drag_tracking_start.c
- gx_multi_line_text_view_text_draw.c
- gx_multi_line_text_input_draw.c
- gx_rich_text_view_text_draw.c
- gx_single_line_text_input_draw.c
- gx_radial_progress_bar_background_draw.c (GX_BRUSH_ALPHA_SUPPORT path)
- gx_widget_block_move.c
- gx_system_canvas_refresh.c (partial and non-partial paths)
- gx_system_error_process.c (Copilot attribution only; functional changes via eclipse-threadx#156)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…k overflow
Tests that _gx_canvas_drawing_initiate() overflow does not corrupt the
draw context state:
1. Overflow detection: GX_DRAW_NESTING_EXCEEDED returned at max depth
(GX_MAX_CONTEXT_NESTING = 8 levels).
2. No state corruption: gx_canvas_draw_nesting and
_gx_system_current_draw_context are unchanged after overflow.
3. Caller regression (_gx_widget_block_move): does not corrupt nesting
counter or context pointer when overflow occurs at max depth. This
would fail against the pre-fix code, which called
_gx_canvas_drawing_complete() unconditionally.
4. Full unwind: gx_canvas_draw_nesting == 0 and context pointer == NULL
after GX_MAX_CONTEXT_NESTING calls to gx_canvas_drawing_complete().
5. Recovery: a fresh drawing initiate/complete pair succeeds after full
unwind.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@fdesbiens
fdesbiens merged commit 8a35f69 into eclipse-threadx:devJun 1, 2026
1 check passed
@fdesbiens
fdesbiens deleted the fix/issue-148-draw-context-stack-overflow branch June 1, 2026 21:29
fdesbiens added a commit that referenced this pull request Aug 27, 2026
…ng (#175)
Commit 8a35f69 (#158) made _gx_animation_start() assign the return value of
_gx_canvas_drawing_initiate() to its local "status" variable. That variable is
both the value returned to the caller and the flag that gates linking the
animation into the active list, so the drawing status leaked into the
completion status.
_gx_widget_show() releases the view list of the animation root window on the
line just above that call, so _gx_canvas_drawing_initiate() reports
GX_NO_VIEWS every time an animation canvas is used. The animation was
therefore never linked into _gx_system_animation_list, the frame timer was
never started and _gx_animation_complete() never ran: no animation frames
were produced and GX_ANIMATION_PUSH_STACK never pushed its target onto the
screen stack.
The drawing status is now held in a separate draw_status variable. The #148
guard that keeps _gx_canvas_drawing_complete() from being called after
GX_DRAW_NESTING_EXCEEDED is preserved, while the completion status returned
to the caller is left untouched.
_gx_animation_drag_tracking_start() contains the identical block but returns
GX_SUCCESS unconditionally, so it was not affected. Its variable is renamed to
draw_status as well, with no change in behaviour, so the two functions cannot
drift apart again.
Verified on Linux with the default_build_coverage regression suite. Before the
fix, matching CI run 28477318897 exactly:
447 guix_all_widgets_16bpp_canvas_animation SEGFAULT
457 guix_animation_complete golden_file_frame_id = 1, test_frame_id = 3
458 guix_animation_complete_push_stack Failed, no output
After the fix all three pass and 730 of 732 tests pass. The two remaining
failures, guix_ml_text_view_32bpp and guix_all_widgets_accordion_menu, are
unrelated to animation and are diagnosed separately.
No new regression test is added: guix_animation_complete,
guix_animation_complete_push_stack and guix_all_widgets_16bpp_canvas_animation
already cover this path and are the tests that caught the regression. No
golden file is regenerated, since the change restores the recorded behaviour
rather than altering it. guix_canvas_draw_nesting_overflow_no_output, the test
added by #158, still passes.
No documentation change is required: no public API or behaviour contract
changes.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
fdesbiens added a commit that referenced this pull request Aug 27, 2026
The fix for issue #148 (#158) made every caller of
_gx_canvas_drawing_initiate() skip its draw when the call returns
GX_DRAW_NESTING_EXCEEDED. Four of those callers push a nested context on the
widget they are already drawing, for one reason only: to narrow the clipping
rectangle to the widget's client area. For them, skipping the draw turns a
correct rendering into no rendering at all, which is what made
guix_all_widgets_accordion_menu report "Frame 12 is different".
The accordion menu screen of the all_widgets demo nests widgets nine levels
deep - multi_level_accordion, menu_list, mla_menu_1_accordion, menu_list,
text_view_3 - and _gx_system_canvas_refresh() consumes two contexts before the
widget tree is walked, so the eight slots of GX_MAX_CONTEXT_NESTING are
exhausted before _gx_multi_line_text_view_text_draw() can push its own. Raising
the limit in a scratch build makes frame 12 match the existing golden file
exactly, which shows that the golden records the correct rendering and that the
text is now being lost rather than merely clipped differently.
When the stack is full there is nothing to push, but the caller's context is
still the right context to draw through: it was created for the same widget and
differs only in its clipping rectangle. These four callers now narrow the
caller's clipping rectangle, draw, and restore it, instead of dropping the draw.
_gx_canvas_drawing_complete() is still not called on overflow, so the stack
corruption that #158 fixed stays fixed.
Applied to _gx_multi_line_text_view_text_draw, _gx_multi_line_text_input_draw,
_gx_rich_text_view_text_draw and _gx_single_line_text_input_draw.
_gx_widget_block_move and _gx_radial_progress_bar_background_draw are left
alone: neither pushes a clip-only context on the widget being drawn.
guix_canvas_draw_nesting_overflow_render_no_output closes the coverage gap that
#158 left. guix_canvas_draw_nesting_overflow_no_output covers detection and
state preservation; the new test covers what a caller must render: that the text
is still drawn at maximum nesting depth, that the borrowed context is handed
back with its nesting count, context pointer and clipping rectangle unchanged,
and that the pixels match those produced when a nested context is available.
Assisted-by: Claude Code (Opus 5)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@fdesbiens