Repository navigation
Conversation
Add missing <cassert> include to Color.hpp to fix Flatpak GCC 15 build
…napmaker#974) The root popup maps a hidden selection onto a group header row: selectedItem() falls back to the header of the group that holds the selected preset. render() then painted both the selection rectangle and the check mark on that header, so the parent menu read as if the vendor itself were the selected entry. drawn_row_for_item() adds the missing distinction: it resolves the selection like selected_row_for_item() but reports -1 whenever the mapped row is a group header. A header is also what that mapping returns for the first preset of a group, not only through its fold fallback, so the check cannot be folded into the call. render() uses it, so the header row draws neither the rectangle nor the check mark. ensure_selection_at_top() keeps the original mapping, so opening the popup still scrolls the group that holds the selection to the top, and the submenu highlight is unchanged. The mapping test covers the folded selection, a visible selection, a submenu row and the out-of-range cases. Co-authored-by: zhongzhipan <zhongzhipan@snapmaker.com>
…aker#958) Tool change: by object, move to an absolute height just above the tallest object printed so far, capped at the max print height; by layer, keep the stock relative 1.5 mm lift. main currently lifts by the target height on top of the current height, which rises further than needed and can exceed the printable height on tall prints. The absolute move from Snapmaker#453 was applied to by-layer prints too, sending the nozzle to Z 1.5, and dropped to Z 1.5 when the tallest object was within 2 mm of the max height. End G-code: cap the pre-homing lift at the max print height instead of the uncapped max_layer_z + 2, which the printer rejects near the top of travel. Declare move_z as a decimal first, since max_print_height is passed as an integer and truncated the lift to whole millimeters. Applies to the 0.2, 0.4, 0.6 and 0.8 nozzle profiles.
…tems in GPU pipeline (Snapmaker#983) Unchecking a feature-type legend item (e.g. Top surface) and checking it back could leave Top surface / Bridging / Internal bridging / Internal solid infill unrendered, depending on earlier slider interaction. Two defects in refresh_render_paths_gpu(), both stale state at event time: - visibility inputs were forwarded to the path stack only by render_toolpaths() on the next frame, so the step-table rebuild and the slider-endpoint computation inside refresh_render_paths_gpu() ran with the PREVIOUS state: unchecking kept the endpoints unshrunk, re-checking shrank them under the old visibility, leaving the sequential-view state one event behind. Forward the role flags, filament visibles and view type to the stack at the top of the refresh, mirroring the legacy pipeline which reads the current flags synchronously. - the refresh reset m_sequential_view.current.last without re-syncing the stack's move window, whose only writer was the bottom-slider callback (update_sequential_view_current). PathRenderer::RenderLayers always clips the top layer's draw to that window, so after a slider drag any subsequent legend/view toggle left the top layer truncated at the stale playback position -- exactly where the trailing top-surface moves live. The refresh now re-syncs the move window to the playback position it established. Verified: standard cube sliced, feature-type legend items toggled off/on with and without prior bottom-slider interaction -- paths and slider numbers restore as before.
…ravel values (Snapmaker#980) - first_layer_travel_acceleration/first_layer_travel_jerk are FloatOrPercent options (default 100%); the single-arg get_abs_value() resolved percentages via the static ratio_over chain, using extruder 0's raw config value and bypassing process_flow_value() - in GCode::travel_to(), resolve percentages against process_flow_value(travel_acceleration/travel_jerk), the same values emitted for normal layers - apply the same resolution to the second-layer travel accel/jerk reset condition so the reset tracks the same code path as the first-layer override
…r#986) - Remove the GUI check that auto-reset paint penetration layers when they exceeded the matching shell layers, including the red highlight infrastructure (Field highlight API, highlight callback wiring in Tab/ObjectSettings/ObjectTable) - Remove slice-time checks that blocked slicing when top/bottom shell layers or paint penetration layers exceeded the model total layer count (PEN-015) - The paint penetration parameters and their slicing behavior are unchanged; only the validity constraints are dropped
…hangs (Snapmaker#995) Tree (manual) support is supposed to grow supports only where the user paints, but any layer with painted enforcers also grew tree supports over its unpainted overhang regions. The port of Bambu c03e13340 (STUDIO-11484) flattened the native auto/manual if/else into an unconditional overhang diff + union, so painted layers admitted full-layer auto overhangs into support generation. Restore the mode gate from Bambu c03e13340: in manual mode keep only the painted enforcer overhangs (expanded by the tip diameter per STUDIO-7538), never the full-layer auto diff. Auto mode is unchanged, painted overhangs still merge through OverhangCluster across layers, and blockers keep being subtracted downstream. Bug: 7131842245 Co-authored-by: Zackary <zacakry_shen@qq.com>
_BBS_Backup_Manager's worker loop copied m_post_callback to a local, unlocked, did file IO, then invoked the stale copy. If MainFrame:: shutdown() swapped in nullptr during that window, the worker still called the old callback, wxPostEvent-ing into an already destroyed MainFrame (EXC_BAD_ACCESS, Sentry #7134242393). Serialize callback swaps against in-flight invocations with m_post_callback_mutex and re-read m_post_callback under it, so once set_backup_callback(nullptr) returns the worker can never invoke an old callback. Lock order: m_mutex -> m_post_callback_mutex. Co-Authored-By: Claude Code <noreply@anthropic.com>
…ix/backup-callback-shutdown-race
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the crash tracked in Sentry issue #7134242393 (SNAPMAKER_ORCA-7R, "wxPostEvent", EXC_BAD_ACCESS, still active on 2.4.0). The reported stack is the backup worker thread (boost::thread_proxy -> _BBS_Backup_Manager::operator() -> std::function -> MainFrame ctor lambda -> wxPostEvent) — a data race between the backup worker and the UI thread, platform-neutral UB.
Cause
_BBS_Backup_Manager's worker loop snapshotsm_post_callbackinto a local while holdingm_mutex, releases the lock forprocess_task(), then invokes the stale copy after re-locking. MeanwhileMainFrame::shutdown()— called on app exit and on language-switch recreate — callsSlic3r::set_backup_callback(nullptr)and destroys MainFrame. If shutdown lands inside that window, the worker still calls the old callback, whichwxPostEvents into the already-destroyed MainFrame → use-after-free.The change
Add
m_post_callback_mutexserializing callback swaps against in-flight invocations (bbs_3mf.cpponly, no public API change):set_post_callback()swaps under the new mutexm_post_callbackunder it at fire time — no stale local copyGuarantee: once
set_backup_callback(nullptr)returns, the worker can never invoke an old callback. Lock orderm_mutex -> m_post_callback_mutexis documented at the member;m_mutexcritical sections are otherwise unchanged (the callback was already invoked under it). The UI-thread read inprocess_ui_task()(callback(1)) is untouched — same-thread with the only writer, no race there.Verification
A/B tested on Windows (MSVC 2022, RelWithDebInfo) with a test-only build aid: a 2.5 s sleep in the worker's post-task window plus error-level logging at the callback swap/invoke sites (never committed). Quit during a backup cycle, 5 trials per build:
set_backup_callback(nullptr)landed mid-window in 4/5 runs; in every one the worker invoked the stale callback 150–540 ms after the swap, entering the lambda that captures the dying MainFrame (logged). Across runs this manifested as silent invalid calls, hangs at exit, and abnormal exit codes — the same UAF Sentry reports as EXC_BAD_ACCESS on macOS.m_post_callbackas null under the new mutex in 5/5 and skipped the call — zero invocations after the swap, no hangs or crashes, all exits clean.Sentry cross-check: the issue's newest event stack matches the fixed path frame-by-frame (worker → std::function → MainFrame lambda → wxPostEvent).