diff --git a/src/libslic3r/Thread.hpp b/src/libslic3r/Thread.hpp index f9dc07456c..c407159072 100644 --- a/src/libslic3r/Thread.hpp +++ b/src/libslic3r/Thread.hpp @@ -46,11 +46,23 @@ void name_tbb_thread_pool_threads_set_locale(); template 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)}; }