mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 18:01:14 +00:00
fix: size the destination row before migrating per-variant values
update_values_from_multi_to_multi_2 iterates the destination PRINTER's variant list while writing into a row taken from the destination PRINT preset. Those two lengths are maintained independently -- print_extruder_variant against printer_extruder_variant -- and Tab::load_current_preset() runs the migration before the print preset is re-selected for the new printer. Opening a project saved on a single-variant printer and switching to a seven-variant one therefore wrote six elements past the end of a one-element vector. The corruption stays silent until the next allocation, so the abort surfaces somewhere unrelated and the backtrace points at innocent code. Size the row to the variant count before indexing it. Every write is then in range, and the result carries one value per destination variant, which is what the callers consume. Pad with nil rather than a copied value: set_to_index() skips nil entries, so a variant the object has no opinion about keeps tracking the print preset instead of being pinned to another variant's number. The same shape -- a count from one array indexing another -- appears twice more in this file. update_values_from_multi_to_multi has three of these writes protected only by assert(idx < old_count), and NDEBUG is defined for every non-Debug configuration, so those guards are absent from shipping builds. update_values_from_single_to_multi has the read half. Both are bounded here; leaving them would fix one third of one defect. Source reads are bounded too. is_nil(size_t) indexes values[idx] without checking, so an index past the end was undefined behaviour on that side as well. Where the row already matches the variant list -- every case that was not corrupting the heap -- the resize is a no-op and the output is unchanged. Fixes #15455 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9abc3bcaf7
commit
855c1b51ac
@@ -10238,6 +10238,10 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m
|
||||
|
||||
for (int index = 0; index < variant_count; index++)
|
||||
{
|
||||
//variant_count is the variant column width, src_opt the value array;
|
||||
//they disagree when the source was authored at a different width
|
||||
if (index >= (int)src_opt->values.size())
|
||||
break;
|
||||
if (opt->values[index] > src_opt->values[index])
|
||||
opt->values[index] = src_opt->values[index];
|
||||
}
|
||||
@@ -10255,6 +10259,8 @@ int DynamicPrintConfig::update_values_from_single_to_multi(DynamicPrintConfig& m
|
||||
|
||||
for (int index = 0; index < variant_count; index++)
|
||||
{
|
||||
if (index >= (int)src_opt->values.size())
|
||||
break;
|
||||
if (opt->values[index].value > src_opt->values[index].value)
|
||||
opt->values[index] = src_opt->values[index];
|
||||
}
|
||||
@@ -10449,6 +10455,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
|
||||
|
||||
for(auto idx : variant_indices){
|
||||
assert(idx < old_count);
|
||||
//the counts come from the variant columns, the arrays from the options;
|
||||
//they disagree when a config was authored at a different variant width
|
||||
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
|
||||
continue;
|
||||
if (old_values[idx] < opt->values[new_variant_index])
|
||||
opt->values[new_variant_index] = old_values[idx];
|
||||
}
|
||||
@@ -10479,6 +10489,10 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
|
||||
|
||||
for(auto idx : variant_indices){
|
||||
assert(idx < old_count);
|
||||
//the counts come from the variant columns, the arrays from the options;
|
||||
//they disagree when a config was authored at a different variant width
|
||||
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
|
||||
continue;
|
||||
if (old_values[idx] < opt->values[new_variant_index])
|
||||
opt->values[new_variant_index] = old_values[idx];
|
||||
}
|
||||
@@ -10509,6 +10523,8 @@ int DynamicPrintConfig::update_values_from_multi_to_multi(DynamicPrintConfig& ne
|
||||
|
||||
for(auto idx : variant_indices){
|
||||
assert(idx < old_count);
|
||||
if (idx >= old_count || new_variant_index >= (int)opt->values.size())
|
||||
continue;
|
||||
if (old_values[idx]) //enabled
|
||||
opt->values[new_variant_index] = old_values[idx];
|
||||
}
|
||||
@@ -10549,6 +10565,15 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
same_variant_indices.emplace_back(indices);
|
||||
}
|
||||
|
||||
//dst_values below is the destination PRINT preset's per-variant row, sized to its own
|
||||
//print_extruder_variant; dst_extruder_variants is the PRINTER's list. They disagree until
|
||||
//the print preset is re-selected, so size the row to the variant count before indexing it.
|
||||
const size_t dst_variant_count = dst_extruder_variants.size();
|
||||
if (dst_variant_count == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: empty destination variant list")%__LINE__;
|
||||
return -1;
|
||||
}
|
||||
|
||||
t_config_option_keys keys = this->keys();
|
||||
for(auto& key : keys){
|
||||
if(key_sets.find(key) == key_sets.end())
|
||||
@@ -10564,7 +10589,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
{
|
||||
ConfigOptionFloatsNullable* opt = this->option<ConfigOptionFloatsNullable>(key);
|
||||
auto src_values = opt->values;
|
||||
auto dst_values = dst_config.option<ConfigOptionFloatsNullable>(key) ->values;
|
||||
const auto* dst_opt = dst_config.option<ConfigOptionFloatsNullable>(key);
|
||||
if(!dst_opt){
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
|
||||
break;
|
||||
}
|
||||
auto dst_values = dst_opt->values;
|
||||
dst_values.resize(dst_variant_count, ConfigOptionFloatsNullable::nil_value());
|
||||
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
|
||||
auto& indices = same_variant_indices[dst_idx];
|
||||
if(indices.empty())
|
||||
@@ -10572,7 +10603,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
bool has_value = false;
|
||||
double target_value = std::numeric_limits<double>::max();
|
||||
for(auto idx : indices){
|
||||
if(opt && idx < opt->values.size() && !opt->is_nil(idx)){
|
||||
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
|
||||
has_value = true;
|
||||
target_value = std::min(target_value, src_values[idx]);
|
||||
}
|
||||
@@ -10588,7 +10619,13 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
{
|
||||
ConfigOptionFloatsOrPercentsNullable* opt = this->option<ConfigOptionFloatsOrPercentsNullable>(key);
|
||||
auto src_values = opt->values;
|
||||
auto dst_values = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key) ->values;
|
||||
const auto* dst_opt = dst_config.option<ConfigOptionFloatsOrPercentsNullable>(key);
|
||||
if(!dst_opt){
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
|
||||
break;
|
||||
}
|
||||
auto dst_values = dst_opt->values;
|
||||
dst_values.resize(dst_variant_count, ConfigOptionFloatsOrPercentsNullable::nil_value());
|
||||
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
|
||||
auto& indices = same_variant_indices[dst_idx];
|
||||
if(indices.empty())
|
||||
@@ -10596,7 +10633,7 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
bool has_value = false;
|
||||
FloatOrPercent target_value{9999.f, true};
|
||||
for(auto idx : indices){
|
||||
if(opt && !opt->is_nil(idx)){
|
||||
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
|
||||
has_value = true;
|
||||
target_value = src_values[idx].value < target_value.value ? src_values[idx] : target_value;
|
||||
}
|
||||
@@ -10612,15 +10649,21 @@ int DynamicPrintConfig::update_values_from_multi_to_multi_2(const std::vector<st
|
||||
{
|
||||
ConfigOptionBoolsNullable* opt = this->option<ConfigOptionBoolsNullable>(key);
|
||||
auto src_values = opt->values;
|
||||
auto dst_values = dst_config.option<ConfigOptionBoolsNullable>(key) ->values;
|
||||
const auto* dst_opt = dst_config.option<ConfigOptionBoolsNullable>(key);
|
||||
if(!dst_opt){
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", Line %1%: %2% missing from destination config")%__LINE__%key;
|
||||
break;
|
||||
}
|
||||
auto dst_values = dst_opt->values;
|
||||
dst_values.resize(dst_variant_count, ConfigOptionBoolsNullable::nil_value());
|
||||
for(size_t dst_idx =0; dst_idx < same_variant_indices.size(); ++dst_idx){
|
||||
auto indices = same_variant_indices[dst_idx];
|
||||
if(indices.empty())
|
||||
continue;
|
||||
bool has_value = false;
|
||||
bool target_value;
|
||||
bool target_value = false;
|
||||
for(auto idx : indices){
|
||||
if(opt && !opt->is_nil(idx)){
|
||||
if(idx < (int)opt->values.size() && !opt->is_nil(idx)){
|
||||
has_value = true;
|
||||
target_value = src_values[idx];
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user