Uh oh!
There was an error while loading. Please reload this page.
Conversation
When GX_DISABLE_DEPRECATED_STRING_API is not defined (i.e., the pre-5.6 GX_CHAR* API is still enabled), gx_api.h now emits a #pragma message directing developers to define GX_DISABLE_DEPRECATED_STRING_API and migrate to the GX_STRING-based replacement functions. The deprecated functions omit a string length and cannot safely handle non-NUL-terminated strings or prevent buffer overruns. All new applications should use the _ext() replacement variants. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fixed Screen Flow code generation with GX_ANIMATION_POOL_SIZE = 0 GUIX Studio emitted five static helper functions in the generated specification file as soon as a project used Screen Flow. Two of them, gx_studio_action_parent_find() and gx_studio_animation_execute(), are reachable only from the GX_ACTION_TYPE_ANIMATION handler and reference the GUIX animation API, which is compiled out when the animation pool is empty: - gx_system_animation_get() is only defined under "#if (GX_ANIMATION_POOL_SIZE > 0)" in gx_api.h. - The body of _gx_animation_start() is guarded the same way in gx_animation_start.c, so the reference does not resolve at link time either. A project that defined GX_ANIMATION_POOL_SIZE as 0 in gx_user.h to save resources therefore failed to build even when it used no animation action at all. GCC 14 rejects the implicit declaration outright, and MSVC fails on the unresolved external. The screen generator now wraps both helpers and the two GX_ACTION_TYPE_ANIMATION dispatch sites in "#if (GX_ANIMATION_POOL_SIZE > 0)". Every other action type keeps working with an empty pool, and an animation action simply becomes a no-op at runtime. The generator also emits forward prototypes for the four static screen flow helpers, which addresses the secondary request in the issue. Note that MISRA C:2012 Rule 8.1 covers explicitly specified types and Rule 8.4 applies to objects and functions with external linkage, so static helpers without a visible prototype were not a deviation. The prototypes are still worth having and match the declaration the generator already emits for gx_studio_nested_widget_create(). All the checked-in generated specification files were regenerated so that they stay in sync with the generator, including the golden files of the Studio view test. Added test/guix_studio_test/test_demo/test_animation_pool_size.py as a regression test, registered in the demo compile CTest project. It verifies that every checked-in Screen Flow specification file guards the animation helpers, then compiles them all with GX_ANIMATION_POOL_SIZE set to 0, promoting the MSVC implicit declaration warning to an error so the failure mode above is caught. Fixes#172 Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Added hotfix letter support to the release version scripts The release tooling could not express a hotfix version. Two gaps: - Get-StudioReleaseVersion rejected anything that was not major.minor.patch.build, and update_studio_release_version.ps1 hard-coded GUIX_HOTFIX_VERSION as ' '. The documented path to build a hotfix installer was therefore unusable, and running the script after a manual edit would have reset the hotfix constant. - prepare_release.sh looked for gx_port.h under ports only, so it never updated the version string of the GUIX Studio Win32 port in guix_studio/ports/gx_port.h. Get-StudioReleaseVersion now accepts an optional trailing hotfix letter and exposes it as Hotfix and HotfixDefine. The Win32 and MSIX version formats are strictly numeric and cannot carry the letter, so the revision is offset by the position of the letter in the alphabet instead: 6.5.1.202602 keeps revision 2, and 6.5.1.202602a becomes revision 3. That keeps the hotfix installer recognizable as the newer build for Windows upgrade detection and for the Store. Versions without a hotfix letter resolve exactly as before. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Updated version number constants to 6.5.1.202602a Prepares the emergency hotfix release that carries the Screen Flow fix for GX_ANIMATION_POOL_SIZE = 0. Produced by scripts/update_studio_release_version.ps1 -Version 6.5.1.202602a: - gx_api.h: GUIX_HOTFIX_VERSION is now 'a'. The major, minor, patch and build constants are unchanged, as is the 6.5.1 banner. - studiox.rc: FileVersion and ProductVersion strings are 6.5.1.202602a, FILEVERSION and PRODUCTVERSION are 6,5,1,3. - guix_installer_release.iss: StudioFullVersion is 6.5.1.202602a and StudioVersionInfoVersion is 6.5.1.3, so the installer is named guix_studio_setup_version_6.5.1.202602a.exe. - Package.appxmanifest: the MSIX identity version is 6.5.1.03. STUDIOX_VERSION_NUMBER stays at 202602. It stamps the Studio version into .gxp project files, and a hotfix does not change the project file format. Verified against a rebuilt guix_studio.exe, which reports FileVersion 6.5.1.202602a with a numeric file version of 6.5.1.3, matching what verify_studio_installer.ps1 expects. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Updated port version strings to 6.5.1.202602a Updated the _gx_version_id string in all 47 gx_port.h files for the emergency hotfix release, using the same substitution that prepare_release.sh performs. This includes guix_studio/ports/gx_port.h, the GUIX Studio Win32 port, which the release script previously missed because it only searched the ports directory. That gap is fixed in the preceding commit, so a future release picks the file up automatically. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…#174) * Revived the Windows workflows, which had reached no runner since 2025 The four GUIX Studio workflows requested `runs-on: windows-2019`, an image GitHub retired on 2025-06-30. Nothing can match a retired label, so every run queued for the full 24 hours and was then cancelled without ever starting a job: run 28477318708 created 2026-06-30T21:33:40Z cancelled 2026-07-01T21:33:41Z Every run of these workflows since 2025-09-29 has that same created-plus-24h-cancelled shape. The Studio demo, demo compile, view and MSIX package tests have gated nothing for about a year, and a manual workflow_dispatch on 2026-08-25 queued the same way. Three more defects were in the path behind that one, so fixing the image alone would not have produced a green run. - actions/upload-artifact was pinned at v3.1.3 in all four workflows. GitHub began auto-failing every request that used v3 on 2025-01-30, and both upload steps run under `if: success() || failure()`, so every run would have ended red even with the tests passing. - The scripts hard-coded a Visual Studio edition path. build_guix.cmd, test_studio_demo.cmd, test_studio_demo_compile.cmd and test_studio_view.cmd all call VS 2022 *Enterprise*, which no developer machine has, and build_guix_studio.cmd calls VS 2022 *Community*, which no GitHub runner has. So the demo test's build step would have failed on the first line. All five now locate the installation with vswhere, matching what build_guix_studio_msix_package.cmd already did, and check the result instead of assuming the call succeeded. Verified on a Community install, where the Enterprise path does not exist. - studio_msix_package.yml uploaded guix_studio/build/vs_2019/msix_package_project/AppPackages. That directory has not existed since the solution moved to vs_2022, which is where build_guix_studio_msix_package.cmd builds, so the artifact was always empty. Every action reference is now a 40-character commit SHA with the version in a trailing comment, following the pattern eclipse-threadx/threadx adopted in August 2026. A tag can be repointed at any commit; a SHA cannot, which is what makes "which code ran in our CI" answerable from the repository. Versions moved with the pinning: actions/checkout v4 -> v7.0.1 actions/upload-artifact v3.1.3 -> v7.0.1 EnricoMi/publish-unit-test-result-action v2 -> v2.24.0 Compatibility was checked against each new action.yml rather than assumed, for every input these workflows actually pass: checkout keeps `submodules`; upload-artifact keeps `name` and `path`, and the one upload per run means the v4 rule against uploading a name twice does not bite; the publish action keeps `check_name` and `files`, and the `composite` variant still exists at v2.24.0, which is the one a Windows runner needs. All three tags were confirmed to resolve to the SHAs pinned here, and all three are the current latest. The runner image is pinned rather than tracking windows-latest, on the same reasoning threadx applies to ubuntu-24.04: which image the build ran on should be a reviewable commit, not something that changes underneath it. Floating would have hidden this failure differently rather than preventing it. Also removed the dead `C:\Program Files\Python36` PATH lines. No supported runner image has shipped that Python for years, python is already on PATH there, and the lines embedded literal quote characters into PATH. The trigger branches are deliberately left alone in this commit. These workflows fire on master only, so they still gate no pull request to dev -- the same defect threadx fixed in its own suites. That wants a dispatch run to go green first, on evidence rather than hope, and is a separate change. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Added the Dependabot configuration the pinned actions need Follow-up to the pinning in the preceding commit. A SHA pin with nothing moving it is worse than a floating tag: it holds CI on whatever was current the day it was written. This repository is the case study for that. Nothing had ever reported that an action moved, so actions/upload-artifact sat at v3.1.3 in all four Windows workflows -- four majors behind, and a version GitHub began auto-failing every request for on 2025-01-30 -- while actions/checkout sat on an unpinned @v4, three majors behind. This adds .github/dependabot.yml: weekly, github-actions only, and closes the reference to that path which the pinning comment in each workflow now makes. Dependabot understands the SHA form and rewrites the trailing version comment together with the pin, so the comment cannot drift away from the SHA it describes. It follows the configuration eclipse-threadx/threadx added in August 2026, with three differences that are specific to this repository and documented in the file: - Only three distinct actions are in use, so the default limit of five would be enough. Ten is set anyway, to match the sibling repositories and to leave room for a wave of majors after a long gap. - There is no .github/CODEOWNERS here, so no reviewer routing exists for Dependabot to honour. Worth adding, but not by this file. - The "dependencies" label does not exist in this repository yet. Dependabot creates it on the first pull request. Two choices worth stating rather than leaving to be rediscovered. target-branch is dev. Dependabot reads this file from the default branch, which is master -- but master is deliberately kept behind dev, and pull requests belong on dev. So this arms on merge without firing: nothing happens until a release merge carries the file to master. Setting target-branch also opts out of Dependabot security updates, which only ever run against the default branch. For this ecosystem the cost is small, since an action advisory arrives as an ordinary bump on the weekly run, but it is a real trade. Patch and minor are grouped into a single pull request, because a queue reviewed one item at a time is a queue that gets ignored -- which is the failure mode this file exists to prevent. Majors stay ungrouped, one pull request each, because every breaking change met in an action here has been a major: upload-artifact v4 stopped allowing an artifact name to be uploaded twice in a run, and v6 requires a runner of 2.327.1 or newer. Dependabot reports drift, not silence. The Windows workflows rotted because they never reached a runner, not because nobody was told, and the runner image fix in the preceding commit is the cure for that half. The cross-repository reusable workflow in regression_test.yml is correctly left alone: it references a branch, so it carries no version to move. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Renamed the Studio IMAGE_INFO struct, which the Windows SDK now defines With the Windows workflows reaching a runner again, the Studio build failed immediately on both of them: guix_studio\system_pngs.h(15,8): error C2011: 'IMAGE_INFO': 'struct' type redefinition Windows Kits\10\Include\10.0.26100.0\um\Filter.h(340,16): error C2011: 'IMAGE_INFO': 'struct' type redefinition plus eight C2027 "use of undefined type" errors following from it. guix_studio declared its own two-field `IMAGE_INFO` in the global namespace. A newer Windows SDK added a struct of the same name to um/Filter.h, which arrives through the Windows headers the MFC sources already include. SDK 10.0.22621.0 does not define it; 10.0.26100.0 does. This was latent rather than new. studiox.vcxproj sets `<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>`, the MSBuild wildcard for "newest installed SDK", so which SDK compiles the Studio depends entirely on the machine. A developer box with 22621 as its newest builds; the runner image, which carries 26100, does not. The collision was simply waiting for whichever came first. Renamed the Studio type to STUDIO_IMAGE_INFO -- 13 references across five files. It is private to the Studio, so nothing outside guix_studio sees the name. Also dropped the `-winsdk=10.0.22621.0` argument that build_guix_studio.cmd passed to VsDevCmd. It never had the effect it looks like it has: the wildcard in the project file governs the SDK the compile actually uses, so the argument only set the shell environment and left MSBuild to pick the newest SDK anyway. Keeping it would suggest the build is pinned to an SDK when it is not. With the collision fixed there is nothing to pin against. Verified by rebuilding the Studio against SDK 10.0.22621.0 locally; the runner will exercise 10.0.26100.0. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pointed the demo test back at the guix project that exists The demo compile test could not build the GUIX library at all: Exception: guix.sln not found. path=../../../ports/win32/build/vs_2022/guix.vcxproj 522aafc ("Updated scripts for VS Community 2022", February 2025) moved three paths in test_main.py from vs_2019 to vs_2022. Two of them were right: guix_studio/build/vs_2019 really had been renamed to vs_2022. The third was collateral damage from the same search and replace -- ports/win32/build/vs_2019 was never renamed, and still holds the only guix.vcxproj and guix.sln in the repository. So --build_guix has raised this exception for eighteen months, before compiling a single library configuration. Nothing said so, because the workflow that calls it never reached a runner. Restored the vs_2019 path. Verified by building the library locally: guix.vcxproj is Win32-only and still on PlatformToolset v142, and it produces Debug/gx.lib. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Pointed the view test at the Studio build directory that exists The Studio view test could not start the Studio at all: MSBUILD : error MSB1009: Project file does not exist. Switch: ../../../guix_studio/build/vs_2019/studiox.sln Exception: Unable to locate Studio executable. 522aafc ("Updated scripts for VS Community 2022", February 2025) renamed guix_studio/build/vs_2019 to vs_2022 and updated test_demo/test_main.py for it, but never touched the test_view directory. Three references there still named the old directory: - test_view/test_main.py project_sln_path - test_view/test_utils.py studio_exe_path - test_view/test_string_import_export.py studio_release So this suite has been unable to locate the Studio for eighteen months. Like the guix.vcxproj path in the preceding commit, nothing reported it, because the workflow that runs it never reached a runner. The remaining build/vs_2019 references in the tree belong to ports/win32/build/vs_2019, which is a real directory and is left alone. This commit makes the suite able to find and launch the Studio. Whether it then passes on a hosted runner is a separate question -- it drives the Studio through win32 window handles, and no run has got far enough to say. Its trigger branches are deliberately not changed here for that reason. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Ran the Studio demo suites on dev, where the pull requests actually are The demo and demo compile workflows trigger on master only, for both push and pull_request. dev is the integration branch, so these suites have gated no pull request that anybody opened -- the same defect eclipse-threadx/threadx fixed in its own regression suites in August 2026. Switched on only after both suites were verified green on a runner, on this branch, rather than on the assumption that they would be: GUIX Studio Demo Test 227 of 227 generation tests 147 s GUIX Studio Demo Compile Test 212 of 212 compile tests 146 s The other three workflows are deliberately left on their current triggers, and each for its own reason: - regression_test.yml does reach a runner, and is red. Its last real run, 2026-06-30, was 5 failures out of 732: accordion menu, ml_text_view_32bpp, animation_complete, animation_complete_push_stack and one more. Adding dev here would make every pull request red on a suite that has been broken since June. It needs fixing first, and that is not this change. - studio_view_test.yml can now find the Studio again, but no run has got far enough to say whether GUI automation through win32 window handles survives a hosted runner. Enabling gating on an unknown is what this commit is written to avoid. - studio_msix_package.yml is workflow_dispatch only by design. It packages a release rather than testing a change, so there is nothing to gate. Assisted-by: Claude Code (Opus 5) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…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>
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>
b8bb23b (#159) fixed issue #130 by letting the overflow branch of _gx_multi_line_text_view_display_info_get() run when an ASCII space is the character that overflows the available width. That branch consumes the space and any consecutive spaces without adding them to the row width, which is correct, and then breaks. When the whitespace ran to the end of the source line, the line terminator was left behind: the next call started on it, hit the GX_KEY_LINE_FEED case immediately and returned a row of one byte and zero width, which draws as a blank line that is not in the text. The overflow branch now takes the line terminator with the whitespace when nothing else separates them, handling a bare line feed and a carriage return / line feed pair, and guarding the second byte on the remaining length -- unlike the pre-existing GX_KEY_CARRIAGE_RETURN case earlier in the same loop, which reads ch.gx_string_ptr[1] unchecked. gx_text_display_width is untouched, so the issue #130 fix stands. Two such rows appear in the guix_ml_text_view_32bpp fixture, at string offsets 2992 and 23988 of readme_guix_generic.txt: "...Improved internal logic." with twelve trailing spaces, and "...cursor_pos_calculate.c" with one. Both were confirmed with a conditional breakpoint on display_number == 1 and display_width == 0 preceded by a space, which fires exactly twice on the pre-fix code and never after. The two extra rows are why 268 of that test's 300 frames and 144 of guix_bidi_text_draw_32bpp's 429 frames have differed from their golden data since June. Nothing inside GUIX reads gx_text_display_width -- every caller uses only gx_text_display_number, to advance its index -- so the row count alone governs where every row starts, and two extra rows change the scrollbar's value-to-pixel mapping. Every scroll step then lands at a slightly different pixel offset and the whole text block is drawn a few pixels up or down. Of the 300 frames, 297 were a pure vertical shift of otherwise identical text; only 3 were laid out differently, and those 3 are the two places above. No golden data is regenerated. gx_multi_line_text_view_text_total_rows for the long text view goes back from 2226 to 2224, and both tests pass against their existing golden files. guix_ml_text_view_word_wrap_no_output did not protect #159's fix: it passed on the pre-#159 code as well. Its available_width was one pixel too generous -- a_width + space_width, so the over-wide row the old code produced measured exactly available_width and still satisfied "width <= available_width". It is now a_width + space_width - 1, which makes appending the space genuinely overflow, and three cases are added: a line feed terminator, a carriage return / line feed terminator, and the total row count that _gx_multi_line_text_view_string_total_rows_compute() derives from them. That last one is the quantity the golden frames actually depend on, and the only one of the three a unit test can pin without golden data. The test was verified to discriminate in both directions by rebuilding against each. Against the pre-#159 source it fails four width assertions, which is issue #130. Against #159 as shipped it fails the line feed row (2 bytes, not 3), the carriage return / line feed row (2, not 4) and the row count (3, not 2). It passes only with both fixes in place. Verified on Linux across all eighteen build configurations, 1847 tests, no failures. default_build_coverage 733/733, dynamic_bidi_text_build 3/3 including guix_bidi_text_draw_32bpp, no_utf8_build_coverage 135/135. One coverage boundary worth naming: the unit test builds against the all_widgets demo, which is not in NO_UTF8_DEMOS, so it runs in default_build_coverage and disable_error_check_build but not in the GX_UTF8_SUPPORT-off configurations. The changed code is common to both paths -- only the surrounding character advance differs -- and no_utf8_build_coverage covers it through its 135 golden tests. No documentation change is required. _gx_multi_line_text_view_display_info_get is internal, and the GUIX documentation does not describe multi-line text view wrapping behaviour for trailing whitespace. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
) _gx_multi_line_text_view_display_info_get() decided whether a line terminator was "\r" or "\r\n" by examining ch.gx_string_ptr[1], the byte after the current character, without checking that a byte remained. When the carriage return is the last byte of the range, that access is outside the caller's buffer. A GX_STRING carries its own length and need not be NUL terminated -- that is why the _ext string API exists, and it is what the deprecation warning added in #167 says about the older char * API. _gx_multi_line_text_view_text_set_ext() stores the caller's GX_STRING verbatim unless GX_STYLE_TEXT_COPY is set, and callers of this function pass end_index = gx_string_length, so in the default configuration the read lands one byte past what the application supplied. The consequence is not only the read. If that byte happens to be 0x0A, the function reports a two-byte terminator for a one-byte remainder, so every caller advances its index by one more than the string holds. In _gx_multi_line_text_view_string_total_rows_compute() the loop then exits with index == gx_string_length + 1 and evaluates string.gx_string_ptr[index - 1], one byte past the end as well, and can add a row that is not in the text. The same over-advance reaches the line index cache in gx_multi_line_text_view_line_cache_update.c and the cursor arithmetic in gx_multi_line_text_input_cursor_pos_update.c. Both reads now go through string rather than ch. string has already been advanced past the current character and its length is exactly the number of bytes still readable there, so guarding on it bounds the access to what the caller supplied. The same idiom in _gx_multi_line_text_input_new_line_character_get() is corrected as well. That one is not currently reachable as a read past the end: its only caller, _gx_multi_line_text_input_text_set_ext(), writes a NUL immediately after the copied text. It is fixed anyway because it depends on an invariant established in a different function and documented nowhere, and because the byte it reads decides whether the widget inserts a one- or two-byte terminator on every subsequent Enter. The rest of the codebase was audited for the same shape. Five other sites handle a carriage return followed by a possible line feed; all five are already correct. gx_rich_text_view_line_info_get.c, gx_multi_line_text_input_char_insert.c and gx_utility_bidi_paragraph_reorder.c guard on the remaining length, the preprocessed-line-break branch at the top of the changed function guards on it too, and gx_multi_line_text_button_line_pointers_set.c walks a NUL-terminated char * buffer where the byte after a carriage return is at worst the terminator. guix_ml_text_line_terminator_bounds_no_output covers this. It places a line feed immediately after the string under test but outside the length the widget is given, so the over-read is observable without a sanitizer: the unfixed code counts the out-of-bounds byte and reports a 4-byte row for a 3-byte string, which the test catches as "Expected: 3, Got: 4". Two controls pin the cases that must not change -- a "\r\n" pair genuinely inside the string still counts as two bytes, and a carriage return followed by ordinary text still counts as one. The test also asserts the terminator a multi-line text input adopts from its text, for a lone carriage return and for a "\r\n" pair. Those two cases pass both before and after the change, for the reason given above; they are there to pin the behaviour, not to reproduce a fault. Verified on Linux across all eighteen build configurations, no failures. No documentation change is required: no public API or behaviour contract changes, and the corrected behaviour is what the documented terminator handling already describes. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Test Results GUIX Studio Demo227 tests 227 ✅ 23m 30s ⏱️ Results for commit e2d28f5. ♻️ This comment has been updated with latest results. |
Test Results GUIX Studio Demo Compile213 tests 213 ✅ 18m 59s ⏱️ Results for commit e2d28f5. ♻️ This comment has been updated with latest results. |
Test Results GUIX Studio View40 tests 40 ✅ 1h 21m 55s ⏱️ Results for commit e2d28f5. ♻️ This comment has been updated with latest results. |
compare_file() locates the line where comparison should start, so that the banner GUIX Studio writes into every generated file -- which carries a revision string and a generation timestamp -- is skipped rather than compared. It looked that line up correctly in the first file and then looked it up in the first file again for the second: for line in list_2: if compare_start_string in line: start_row_2 = list_1.index(line) So the golden was sliced at the *generated* file's offset. While both files happened to reach "#include" on the same line the mistake was invisible, which is why it survived since the tests were added in #84. The offsets diverged when 6ba13db added a ten-line MIT licence header to all 111 golden .c and .h files. GUIX Studio does not emit that header, so every golden now reaches its first #include ten lines later than the file it is compared against. The golden was therefore sliced ten lines early and compared banner text against source. That made every one of the 107 .c and .h comparisons in the suite fail -- all 29 reported test failures -- while the .csv, .xliff and .xml comparisons passed. Those use skip_line instead of compare_start_string and never reach this code, which is exactly the split the failure log shows. The reported mismatch is the same in all 29: a generated "#include" line against a golden banner comment. Confirmed arithmetically -- in every case the golden line reported sits exactly ten lines before that golden's own first #include: generic_16bpp_resources.c reported idx 13, #include at 23, delta 10 generic_16bpp_resources.h reported idx 16, #include at 26, delta 10 generic_16bpp_specifications.c reported idx 14, #include at 24, delta 10 generic_16bpp_specifications.h reported idx 16, #include at 26, delta 10 compare_output_file() is the only caller that passes compare_start_string, so the change cannot affect the xliff, xml or plain-file comparisons. Verified by running the suite locally against a Studio built from this tree. Seven suites that fail in CI now pass with no mismatches at all, each gaining exactly the tests it had been failing: CI (broken) local (fixed) Font 9 / 1 10 / 0 Multi-Themes 18 / 1 19 / 0 Project Import 10 / 2 12 / 0 Trigger Edit 6 / 1 7 / 0 Trigger Target Rename 1 / 1 2 / 0 Bidi Text 3 / 1 4 / 0 Widget Name 3 / 1 4 / 0 Project Import compares a generated specifications file, so this also shows that the screen flow prototype block added by #173 does not disturb these goldens: that block is only emitted for projects that use Screen Flow, and these do not. No golden file is regenerated. The goldens still carry "GUIX Studio Revision 6.1.12.0" and a 2022 timestamp in their banners, and still name Azure RTOS rather than Eclipse ThreadX, but the banner is what the comparison is supposed to skip -- so none of that needs to be touched to make the suite correct. This workflow had never actually executed before 2026-08-27. Every earlier run was cancelled after queueing 24 hours for the retired windows-2019 image, or sat awaiting approval on a fork pull request, including the run for the v6.5.1 release itself. #174 gave it a runner again; this is the first result it has ever produced, and the defect it found is in the test harness rather than in GUIX or in Studio. Note that studio_view_test.yml triggers only on pull requests targeting master, so this change is not exercised by its own pull request into dev. It is validated by the release pull request that carries dev to master. Assisted-by: Claude Code (Opus 5) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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.
No description provided.