fix: dangling static lambda crashes support G-code export on repeated slices (#14677)

GCode::extrude_support declared its per-path speed helper as a function-local
static lambda that captures `this` by reference. The closure is built once, on
the first extrude_support call, and reused for the rest of the process, so a
second G-code export in the same process runs the helper against a `this` from
the first export's stack frame, which has already returned.

The stale `this` flows through NOZZLE_CONFIG(...) -> cur_extruder_index() ->
GCodeWriter::filament(), reading a garbage current-extruder id and indexing
with it. It is silent whenever the reused stack still holds a usable pointer,
and an order-dependent SIGSEGV otherwise; AddressSanitizer reports it as a
stack-use-after-return in GCodeWriter::filament(). It is the only static
capturing lambda in libslic3r.

Drop static so the closure is rebuilt each call against the live frame. Add an
fff_print regression test that slices a support object twice in one process; it
fails without the fix (stack-use-after-return under ASan) and passes with it.
This commit is contained in:
Kris Austin
2026-07-08 19:56:03 -05:00
committed by GitHub
parent bc6ffcfb31
commit 7d17400443
2 changed files with 13 additions and 1 deletions

View File

@@ -6215,7 +6215,8 @@ std::string GCode::extrude_support(const ExtrusionEntityCollection &support_fill
static constexpr const char* support_transition_label = "support transition";
static constexpr const char* support_ironing_label = "support ironing";
static const auto speed_for_path = [&](double length, ExtrusionRole role, double default_speed = -1.0) {
// Not static: it captures `this` by reference.
const auto speed_for_path = [&](double length, ExtrusionRole role, double default_speed = -1.0) {
if (!is_support(role) || length > SMALL_PERIMETER_LENGTH(NOZZLE_CONFIG(small_support_perimeter_threshold)))
return default_speed;