mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-21 20:25:20 +00:00
fix(threads): bump worker thread stack to 16MB to survive CGAL emboss (#13772)
The Emboss text-cut workflow can crash with SIGBUS at a stack-guard page on macOS (and equivalent on Linux) when CGAL's Polygon_mesh_processing::corefine falls back from filtered interval arithmetic (Epick) to exact rational arithmetic (Epeck / mpq_class). On near-degenerate inputs -- coplanar triangles in the projection footprint, very thin font stems, sharp edges or seams under the text -- CGAL's Filtered_predicate_with_state cascade ends up inside Triangulation_2<Projection_traits_3<Epeck>>::march_locate_2D, whose recursive walk plus mpq_class arithmetic frames overflows the worker's 4MB default stack. The fault address sits exactly inside the next thread's guard page, which is the textbook macOS signature. Crash trace (BambuStudio v02.07.00.55, macOS 26.4.1 arm64, embossing text into a model): __gmpn_mul_1 __gmpz_mul / __gmpq_mul CGAL::determinant<mpq_class> Projected_orientation_with_normal_3 Filtered_predicate_with_state::operator() Triangulation_2<...>::orientation Triangulation_2<...>::march_locate_2D Surface_intersection_visitor::triangulate_intersected_faces Polygon_mesh_processing::corefine Slic3r::cut_surface Emboss::cut_surface_to_its Emboss::GenerateTextJob::get_text_mesh PlaterWorker::PlaterJob::process The thread's stack region in the report was exactly 4128K -- the default 4MB plus a small TLS overhead -- and the faulting address hit the adjacent guard page. We have one observed reproducer; the 16 MB value is chosen as 4x defensive headroom over that, not as a measured upper bound. Future heavier emboss inputs may need more. Cumulative cost on a 64-bit target. Slic3r::create_thread has 22 callsites across the codebase. Realistic peak concurrent live count is on the order of 10-15 workers (Plater UI worker, slicing process, FDM- support gizmo, STEP loader, network sync helpers, per-task sender threads in TaskManager up to MaxSendingAtSameTime, per-machine info threads in device-list dialogs, long-lived sync helpers in GUI_App). At 16 MB reserve x ~15 = ~240 MB of address-space commitment in the worst case, which is bounded on any 64-bit target. Resident memory remains proportional to actual stack depth on all three platforms: macOS / Linux mmap the thread stack and defer-commit pages on touch, and Boost.Thread on Win32 passes STACK_SIZE_PARAM_IS_A_RESERVATION to _beginthreadex (verified at libs/thread/src/win32/thread.cpp), so on Windows the bumped value is the reserve, not the initial commit. The 32-bit branch of the previous (sizeof(void*) == 4) ternary is removed: BambuStudio doesn't ship a 32-bit build today, and the literal makes the value easier to read at the callsite. (cherry picked from commit e150b502b3d2afc98b83dcc9e5720e998f9eb79a) Co-authored-by: Abdel Gomez-Perez <nabdel07@icloud.com>
This commit is contained in:
@@ -46,11 +46,23 @@ void name_tbb_thread_pool_threads_set_locale();
|
||||
template<class Fn>
|
||||
inline boost::thread create_thread(boost::thread::attributes &attrs, Fn &&fn)
|
||||
{
|
||||
// Duplicating the stack allocation size of Thread Building Block worker
|
||||
// threads of the thread pool: allocate 4MB on a 64bit system, allocate 2MB
|
||||
// on a 32bit system by default.
|
||||
|
||||
attrs.set_stack_size((sizeof(void*) == 4) ? (2048 * 1024) : (4096 * 1024));
|
||||
// Stack size for our worker threads. Originally duplicated TBB's pool
|
||||
// default (4 MB), but the Emboss text-cut path calls into CGAL's
|
||||
// Polygon_mesh_processing::corefine, which falls back from filtered
|
||||
// interval arithmetic to exact rational arithmetic (mpq_class) on
|
||||
// near-degenerate input, and the constrained 2D triangulation walker
|
||||
// (Triangulation_2::march_locate_2D) can recurse deeply enough to
|
||||
// exceed 4 MB on real models -- producing a SIGBUS at the next thread's
|
||||
// stack guard page on macOS / Linux.
|
||||
//
|
||||
// 16 MB chosen as 4x defensive headroom over the observed crash
|
||||
// threshold (n=1 reproducer at exactly 4 MB on macOS arm64). All three
|
||||
// platforms defer-commit reserved stack pages: macOS / Linux mmap the
|
||||
// stack and only fault in pages on touch; Boost.Thread on Win32 passes
|
||||
// STACK_SIZE_PARAM_IS_A_RESERVATION to _beginthreadex, so the value is
|
||||
// a reserve, not the initial commit. Resident memory therefore stays
|
||||
// proportional to actual stack depth on every target.
|
||||
attrs.set_stack_size(16 * 1024 * 1024);
|
||||
return boost::thread{attrs, std::forward<Fn>(fn)};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user