FIX: null deref in ConfigBase::load_from_json when a project config has a malformed array - #12058
Conversation
…nfigBase::load_from_json when a project config has a malformed array
| size_t size = different_settings.size(); | ||
| if (size == 0) { | ||
| size = this->option<ConfigOptionStrings>("filament_settings_id")->values.size() + 2; | ||
| size = this->option<ConfigOptionStrings>("filament_settings_id", true)->values.size() + 2; |
There was a problem hiding this comment.
Hi @ocidburn a nullptr check is preferfed to create when not exist here
@lanewei120 How do you think?
There was a problem hiding this comment.
Thanks — agreed, and checking it made the case stronger than style.
option<>(key, true) does not create an empty option: DynamicConfig::optptr (Config.cpp:1631)
calls create_default_option() (Config.cpp:299), which clones the definition's default, and
filament_settings_id's default is ConfigOptionStrings { "" } (PrintConfig.cpp:3059) — one entry.
So it would give size = 3 and, more to the point, insert the key into the config.
That insertion is not harmless: PresetBundle.cpp:1128-1133 selects the preset collection by
presence, else if (config.has("filament_settings_id")) collection = &filaments; — so a config that
never had the key would start being classified as a filament preset instead of being rejected.
PresetBundle.cpp:3750 also notes the key "sometimes is not generated", which is why num_filaments
comes from filament_colour there — absence is expected, so fabricating it hides something the rest
of the code relies on.
The size difference costs nothing either way: the loop below only writes different_settings[0], and
PresetBundle.cpp:3776 re-resizes to num_filaments + 2 from filament_colour regardless.
Updated:
if (size == 0) {
auto *filament_ids = this->option<ConfigOptionStrings>("filament_settings_id");
size = (filament_ids ? filament_ids->values.size() : 0) + 2;
different_settings.resize(size);
}|
LGTM @lanewei120 |
Title
Body
ConfigBase::load_from_jsondereferences a null option when a 3MF project config contains amalformed array. One word fixes it, and it makes the call consistent with the three around it.
src/libslic3r/Config.cpp:1092-1096:Line 1096 is the only
option<>call in this function that is dereferenced without a guard. Of thesix in
load_from_json, lines 1078, 1083, 1088 and 1093 all pass the create-if-missingtrue, andline 1062 assigns to a pointer that is then null-checked (
if (diff_opt)). Only 1096 does neither,so
option()returnsnullptrand->valuesdereferences null.How the key goes missing
The parse loop abandons the rest of the document on the first malformed array,
src/libslic3r/Config.cpp:1037-1041:nlohmann iterates in sorted key order. In the file I looked at,
extruderis key 86 of 478 andfilament_settings_idis key 128, so thebreakleaves 392 keys unparsed —filament_settings_idamong them. The block above then reads it unconditionally.
The file is a
.3mfsaved by Creality Print 5.1.7. Its per-extruder options are scalars rather thanarrays — of the 20 I checked, 20 are scalars:
Its
extruderkey is a nested object array, whichparse_str_arralso rejects ("we only support2 depth array").
Why it survived this long
Reaching it needs three things at once:
filament_settings_id(hereextruder, key 86against key 128),
different_settings_to_systemin the file, sosize == 0and the branch is taken,is_project_settings.Projects written by BambuStudio emit well-formed arrays, so the path is only reached with a file
from another slicer.
The fix
A null check rather than create-if-missing, per review:
option<>(key, true)would clone thedefinition's default
ConfigOptionStrings { "" }(PrintConfig.cpp:3059) and insert the key, whichPresetBundle.cpp:1128-1133uses as a presence test to classify a preset. The size it produces isdiscarded either way — the loop below only writes
different_settings[0], andPresetBundle.cpp:3776re-resizes tonum_filaments + 2fromfilament_colour.Provenance
The line arrived already missing the
trueina2431d796(2023-02-14, lane.wei, "ENH: add logic toconvert hybrid(auto) to tree(auto) for old 3mf"). Both lines were added in the same hunk:
so the missing argument looks like an oversight at the time rather than something intended.
Scope
I deliberately left the
breakat line 1040 alone. Turning it intocontinuewould keep the rest ofa partially-bad config and would probably have prevented this crash by itself, but it is a real
behaviour change and felt like your call rather than something to fold into a null guard. Happy to
follow up with it if you want it.
What I have and have not verified
bambulab/BambuStudio@masteras it stands today.(OrcaSlicer), which carries this line verbatim:
Exception Code: c0000005 ACCESS_VIOLATION,RAX = 0, andRCX = 0x66696C616D656E74— ASCII"filament"— which is what pointed at thiscall in the first place.
Null deref in ConfigBase::load_from_json when a 3MF project config has a malformed array (Creality Print 5.1.7 file) OrcaSlicer/OrcaSlicer#15337
I can attach the reproducing
.3mfhere as well if that is useful.