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

@@ -93,3 +93,14 @@ SCENARIO("Support layer Z honors contact distance", "[SupportMaterial]")
}
}
}
// extrude_support once held a `static` lambda capturing `this`, so a second export in the
// same process dereferenced a returned stack frame (ASan: stack-use-after-return).
TEST_CASE("Support G-code emission survives a second slice in the same process", "[SupportMaterial][Regression]")
{
const std::string first = slice({ TestMesh::overhang }, { { "enable_support", 1 } });
REQUIRE(! layers_with_role(first, "support").empty());
const std::string second = slice({ TestMesh::overhang }, { { "enable_support", 1 } });
REQUIRE(! layers_with_role(second, "support").empty());
}