fix: prevent NULL FILE* crash when loading a missing G-code file - #648
Merged
Conversation
Two related defensive fixes for the G-code load path: - GCodeReader::parse_file_raw_internal now returns false when fopen fails, preventing ::fread(buffer.data(), 1, ..., NULL) from triggering a CRT invalid-parameter crash on Windows (and UB elsewhere). - Plater::load_gcode rejects a missing / inaccessible file up front with a precise "does not exist" message, instead of letting the load path proceed and surface the misleading "does not contain valid G-code" error. Originally bundled into PR #589 (filament temp mixing) commit 4d7ffd5; split out per change-scope-control review finding (M3) so any regression on the G-code load path can be bisected independently of the mixing-notification changes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
11 tasks
Two related defensive fixes for the G-code load path: - GCodeReader::parse_file_raw_internal now returns false when fopen fails, preventing ::fread(buffer.data(), 1, ..., NULL) from triggering a CRT invalid-parameter crash on Windows (and UB elsewhere). - Plater::load_gcode rejects a missing / inaccessible file up front with a precise "does not exist" message, instead of letting the load path proceed and surface the misleading "does not contain valid G-code" error. Originally bundled into PR #589 (filament temp mixing) commit 4d7ffd5; split out per change-scope-control review finding (M3) so any regression on the G-code load path can be bisected independently of the mixing-notification changes.
…aker/OrcaSlicer into fix_gcodereader_null_deref
LiuLikeQian
approved these changes
Aug 3, 2026
iesteem
added a commit
that referenced
this pull request
Aug 4, 2026
Brings PR #627 (cold-plate gating), #648 (G-code null FILE* fix), and #626 (flow_ratio_zero blocker) into fix_top_cover, alongside the already-present PR #589 work (filament temp mixing + cached rendering). Conflict resolutions: - Plater.hpp: adopt main's FlowRatioZeroDetail / ColdPlateCompatState / ColdPlateCompatResult (HEAD side had no equivalents). - Plater.cpp (26 conflicts): * Drop main's duplicate filament_display_label / format_filament_slot_list; keep HEAD's Allman versions, but route through main's new tr_u8() helper (fixes I18N::translate_utf8 dangling-pointer trap). * Keep HEAD's mixing preference label "Allow high/low temperature filament mixing" (matches actual Preferences.cpp:1247 setting text); main's older "Allow mixed printing ..." wording was the stale version. * Keep HEAD's Allman brace style and unicode "->"/"—" comment characters per P-tier coding standard. * Keep HEAD's sync_filament_temp_mixing_notification structure (close-old + cache refresh at top of function); drop main's mid-function close-old duplicate. * Keep HEAD's AllowedWarning semantics: cached text excludes the WARNING: prefix so close_validate_warning_notification's prefix matching works. * Adopt main's flow_ratio_zero_error_text and cold_plate_*_text additions unchanged. - GLCanvas3D.cpp / Plater.cpp Preview-tab entry: collapse to single is_plate_sliceable(i) gate from main. - is_plate_sliceable(): swap mixing check to the cached variant (is_plate_blocked_by_filament_temp_mixing_cached) so the GLCanvas3D hot rendering path no longer recomputes check_filament_temp_mixing per plate per frame. This is the PR #589 perf win landing inside the unified gate. - zh_CN.po: keep HEAD's mixing preference msgid; keep main's "does not exist." once (drop the duplicated copy). Compile-verified: libslic3r, libslic3r_gui, Snapmaker_Orca.dll/exe all link (0 errors, only pre-existing C4101/C4996/LNK warnings). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
iesteem
added a commit
that referenced
this pull request
Aug 4, 2026
The previous comment claimed tr_u8 works around a dangling-pointer trap in I18N::translate_utf8. That's inaccurate — by C++ rules the temporaries in wxGetTranslation(...).ToUTF8().data() live until the end of the full expression, which includes the std::string copy construction. Rewrite the comment to state the real reason (defensive against MSVC /O2 mis-optimization of temporary chains, same pattern that bit us in #648). Also add null defenses on both ends of the call: - wxGetTranslation / wxString(nullptr, wxConvUTF8) are UB on null input. - std::string(nullptr, 0) is UB even with zero length, so buf.data() must be checked before construction. Returns "" on null input.
LiuLikeQian
pushed a commit
that referenced
this pull request
Aug 4, 2026
* fix: unify filament temp mixing blocking with plate error gating - Remove has_sliceable_plate_for_slice_all() hijack in Preview tab switch that triggered unintended "slice all" instead of switching to preview - Add m_filament_temp_blocked flag to PartPlate so can_slice() reflects filament temp mixing state, consistent with m_apply_invalid for object-outside errors - Let sync_filament_temp_mixing_notification() manage its own flag, independent of the background validation system - Simplify EVT_GLVIEWTOOLBAR_PREVIEW to use can_slice() as unified gate for both error types Downstream effects: red exclamation icon on plate thumbnails, disabled slice/export buttons, and blocked auto-slice on preview switch now work uniformly for both object-outside and filament-temp-mixing errors. * fix: use on-demand checks instead of cached flag for filament temp mixing Replace the per-plate cached m_filament_temp_blocked flag with on-demand is_plate_blocked_by_filament_temp_mixing() checks in the rendering and preview-switch paths. This eliminates staleness risks identified during code review where non-current plates could retain stale blocked state after filament changes, undo/redo, or plate switching during slicing. Changes: - GLCanvas3D: add on-demand check for red exclamation on plate thumbnails - Plater: add on-demand check in EVT_GLVIEWTOOLBAR_PREVIEW alongside can_slice(), keep sync_filament_temp_mixing_notification() for notification freshness - PartPlate: revert cached flag; can_slice() unchanged Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * refactor: simplify filament slot collection in check_filament_temp_mixing Merge duplicate key lists, rename used_slots for clarity, and group logic into scoped blocks. No semantic change. * refactor: rename STRING_EXCEPT_FILAMENTS_DIFFERENT_TEMP to STRING_EXCEPT_FILAMENTS_MIXING_TEMP Better reflects that the check is about high/low temperature material mixing, not just "different" temperatures. * feat: show per-filament high/low temp breakdown in mixing notifications Add per-filament high/low temperature breakdown to the filament temp mixing warning/error notifications so users can see exactly which slots are in conflict, both for single-plate and slice-all modes. - Plater::check_filament_temp_mixing now exposes a FilamentTempMixingDetail (high/low 1-based slot lists) via a new overload - Notification text becomes dynamic; sync_filament_temp_mixing_notification caches the exact pushed strings to work around NotificationManager's exact-text close matching - confirm_filament_temp_mixing_before_slice / _before_slice_all use the same breakdown in their modal dialogs - Safe translation helper tr_u8() avoids the dangling-pointer trap in I18N::translate_utf8() that crashed in non-English locales - Add zh_CN translations for the new strings Also fix a separate crash: GCodeReader::parse_file_raw_internal no longer dereferences a NULL FILE* when fopen fails (e.g. loading a non-existent gcode file at startup), and Plater::load_gcode now checks wxFileExists up front to give a precise "does not exist" error instead of the vague "does not contain valid G-code". * fix: address PR #589 review findings on filament temp mixing - B1 perf: cache per-plate blocked state in Plater::priv and add is_plate_blocked_by_filament_temp_mixing_cached() for the per-frame plate-thumbnail render path. Cache is refreshed once per sync_filament_temp_mixing_notification() call, which already runs at every state-changing event, so hot reads are O(1). - B2: close previously-pushed mixing notifications BEFORE the curr_plate==nullptr early return so the on-screen banner does not leak when the current plate is transiently null during a switch. - B3: remove the tr_u8() helper. I18N::translate_utf8() returns std::string by value; the dangling-pointer narrative was incorrect. All call sites revert to _u8L(). - B4: warning notification close text mismatch. push_notification stores the body verbatim, but close_validate_warning_notification(text) compares against "WARNING:\n" + text. Cache the un-prefixed body so push/close text match exactly; the previous code never closed the warning banner. - m1: restore Allman brace style in new helpers and check_filament_temp_mixing overload to match the rest of Plater.cpp (project coding standard 2.3). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * revert: move GCodeReader/load_gcode defensive fixes out of PR #589 These two unrelated defensive fixes were bundled into commit 4d7ffd5 alongside the mixing-notification work. Per the change-scope-control review finding (M3), they have an independent regression surface (loading missing / invalid G-code files) and should ship in a separate PR so any regression can be bisected cleanly. Reverted in this commit (will be re-applied on a separate branch): - src/libslic3r/GCodeReader.cpp: NULL FILE* check in parse_file_raw_internal - src/slic3r/GUI/Plater.cpp: wxFileExists early-reject in Plater::load_gcode - localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po: "does not exist." key Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: align mixing notification preference name with actual setting The error/warning notification referenced the filament mixing preference as "Allow mixed printing of high and low temperature materials", which doesn't match the actual preference label "Allow high/low temperature filament mixing". Update the notification source literal and zh_CN translations to use the canonical name so users can locate the preference the notification points them to. * fix: harden tr_u8 with null defenses and correct the rationale comment The previous comment claimed tr_u8 works around a dangling-pointer trap in I18N::translate_utf8. That's inaccurate — by C++ rules the temporaries in wxGetTranslation(...).ToUTF8().data() live until the end of the full expression, which includes the std::string copy construction. Rewrite the comment to state the real reason (defensive against MSVC /O2 mis-optimization of temporary chains, same pattern that bit us in #648). Also add null defenses on both ends of the call: - wxGetTranslation / wxString(nullptr, wxConvUTF8) are UB on null input. - std::string(nullptr, 0) is UB even with zero length, so buf.data() must be checked before construction. Returns "" on null input. --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.
Summary
Two related defensive fixes for the G-code load path, split out of PR #589 (filament temp mixing) per change-scope-control review finding (M3):
GCodeReader::parse_file_raw_internalreturnsfalsewhenfopenfails, preventing::fread(buffer.data(), 1, ..., NULL)from triggering a CRT invalid-parameter crash on Windows (and UB elsewhere).Plater::load_gcoderejects a missing / inaccessible file up front with a precise "does not exist" message, instead of letting the load path proceed and surface the misleading "does not contain valid G-code" error.Why split out
These were originally bundled into PR #589 commit
4d7ffd5alongside the mixing-notification work. They have an independent regression surface (loading missing / invalid G-code files) and should ship in a separate PR so any regression can be bisected cleanly. The split was done as:fix_top_cover(PR fix: unify filament temp mixing blocking with plate error gating #589): addsabe6eb9revert, removing these two changes from the PR fix: unify filament temp mixing blocking with plate error gating #589 diff.fix_gcodereader_null_deref(this PR): contains only these two changes on top ofmain.Test plan
parse_file_raw_internalreturnsfalsecleanly (no CRT crash on Windows).update-translation.ymlsyncs.Downstream
This PR can merge independently of #589. After both merge, the final state of
mainis identical to what PR #589 would have produced if the GCodeReader/load_gcode changes had not been bundled.🤖 Generated with Claude Code