Size the IMEX test fixtures' flush matrix per nozzle

The IMEX fixtures set seven nozzles but kept multifilament_config's single
filaments x filaments flush block. get_flush_volumes_matrix splits that block
across the nozzles, leaving each with 7 values, and
ToolOrdering::reorder_extruders_for_minimum_flush_volume then reads them as a
7 x 7 matrix, past the end of the buffer. One of the affected tests segfaulted
on Windows x64; ASan reproduces the overflow in that test on Linux, where it
passed only by luck.

The fixtures now repeat the block once per nozzle, as the GUI does, and size
flush_multiplier to match, since append_full_config takes the nozzle count from
it. The helper is shared in test_helpers.

Co-authored-by: HanifKoh <76276251+HanifKoh@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Clifford Garwood
2026-10-02 08:22:36 -04:00
co-authored by HanifKoh Claude Opus 5.5
parent c9b2b89b2b
commit 47de490647
5 changed files with 20 additions and 0 deletions
+13
View File
@@ -224,6 +224,19 @@ DynamicPrintConfig multifilament_config(unsigned int filaments, std::initializer
return config;
}
void size_flush_to_nozzles(DynamicPrintConfig &config)
{
// One filaments x filaments flush block and one flush multiplier per nozzle, as the GUI
// sizes them when the nozzle count changes; a single block leaves each nozzle's slice short.
const size_t nozzles = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
auto &flush = config.option<ConfigOptionFloats>("flush_volumes_matrix", true)->values;
const std::vector<double> block = flush;
for (size_t i = 1; i < nozzles; ++i)
flush.insert(flush.end(), block.begin(), block.end());
for (const char *key : { "flush_multiplier", "flush_multiplier_fast" })
config.option<ConfigOptionFloats>(key, true)->resize(nozzles);
}
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> *per_object_overrides, bool arrange, size_t instances)
{
+4
View File
@@ -72,6 +72,10 @@ Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh);
DynamicPrintConfig multifilament_config(unsigned int filaments,
std::initializer_list<Slic3r::ConfigBase::SetDeserializeItem> extra = {});
// Repeat multifilament_config's single flush block, and the flush multipliers, once per nozzle.
// Call after setting nozzle_diameter to more than one nozzle.
void size_flush_to_nozzles(DynamicPrintConfig &config);
// Apply `meshes` and config to `print`/`model`, each object with `instances` copies; optional per-object overrides,
// auto-arranged unless `arrange` is false.
void init_print(std::vector<TriangleMesh> &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in,
+1
View File
@@ -114,6 +114,7 @@ static void imex_7x4_printer(DynamicPrintConfig &config)
// compares the two scripts and nothing else.
{ "gcode_flavor", "klipper" },
});
size_flush_to_nozzles(config);
}
// Set the mode scripts positionally, one per name in imex_mode_names. Assigning the vector
@@ -173,6 +173,7 @@ static void imex_printer(DynamicPrintConfig &config)
{ "initial_layer_print_height","0.2" },
{ "gcode_flavor", "klipper" },
});
size_flush_to_nozzles(config);
}
// Route every region to one filament. An unset *_filament_id is not "inherit":
+1
View File
@@ -741,6 +741,7 @@ static void imex_7x4_printer(DynamicPrintConfig &config)
// "G10 S<t> P<n>" from the same code, so the flavor is pinned rather than defaulted.
{ "gcode_flavor", "klipper" },
});
size_flush_to_nozzles(config);
}
// Route every region to one filament. An unset *_filament_id is not "inherit":