From b58025575d334300e7631fe376665ce22ff09f21 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Wed, 8 Jul 2026 08:14:05 -0500 Subject: [PATCH] fix: isolate calibration temp paths per user (#14619) * fix: isolate calibration temp paths per user The calibration temp files under /calib were file-scope statics initialized before set_temporary_dir() runs at startup, so they kept using the shared system temp root and missed the per-user isolation added in #14607. On Linux every account shares /tmp, so the first user to calibrate owns /tmp/calib and later users fail to write there, the same cross-user collision #14607 fixed for model backups, STEP import, and part skip. Build the paths lazily from temporary_dir() instead, through a calib_temp_dir() accessor and a calib_temp_file() join helper. The base becomes /orcaslicer_/calib on Linux and is unchanged on Windows, where the temp dir is already per user. Also make StoreParams::path a std::string rather than a non-owning const char*. The calibration code had to keep a std::string alive solely to feed that pointer, and the field was uninitialized by default; owning the string removes the lifetime hazard for all three callers and makes the entry guard a reliable empty() check. Confined to the 3mf project exporter (three callers, two internal reads); no on-disk, format, or ABI impact. Follows up on #14607 per @Noisyfox's review suggestion. --- src/OrcaSlicer.cpp | 2 +- src/libslic3r/Format/bbs_3mf.cpp | 4 ++-- src/libslic3r/Format/bbs_3mf.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/Utils/CalibUtils.cpp | 39 ++++++++++++++++++++------------ 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 7e1341ac18..311451f774 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -7359,7 +7359,7 @@ bool CLI::export_project(Model *model, std::string& path, PlateDataPtrs &partpla bool success = false; StoreParams store_params; - store_params.path = path.c_str(); + store_params.path = path; store_params.model = model; store_params.plate_data_list = partplate_data; store_params.project_presets = project_presets; diff --git a/src/libslic3r/Format/bbs_3mf.cpp b/src/libslic3r/Format/bbs_3mf.cpp index 31519e4fbe..fd395135ae 100644 --- a/src/libslic3r/Format/bbs_3mf.cpp +++ b/src/libslic3r/Format/bbs_3mf.cpp @@ -5949,7 +5949,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result) m_thumbnail_middle = iter->second; } boost::system::error_code ec; - std::string filename = std::string(store_params.path); + std::string filename = store_params.path; boost::filesystem::remove(filename + ".tmp", ec); bool result = _save_model_to_file(filename + ".tmp", *store_params.model, store_params.plate_data_list, store_params.project_presets, store_params.config, @@ -8988,7 +8988,7 @@ bool store_bbs_3mf(StoreParams& store_params) // All export should use "C" locales for number formatting. CNumericLocalesSetter locales_setter; - if (store_params.path == nullptr || store_params.model == nullptr) + if (store_params.path.empty() || store_params.model == nullptr) return false; _BBS_3MF_Exporter exporter; diff --git a/src/libslic3r/Format/bbs_3mf.hpp b/src/libslic3r/Format/bbs_3mf.hpp index df4f91f6e9..c16c423f66 100644 --- a/src/libslic3r/Format/bbs_3mf.hpp +++ b/src/libslic3r/Format/bbs_3mf.hpp @@ -226,7 +226,7 @@ typedef std::map PlateDataMaps; struct StoreParams { - const char* path; + std::string path; Model* model = nullptr; PlateDataPtrs plate_data_list; int export_plate_idx = -1; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 584386d984..a4a4b9a98e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -15742,7 +15742,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy std::vector project_presets = preset_bundle.get_current_project_embedded_presets(); StoreParams store_params; - store_params.path = path_u8.c_str(); + store_params.path = path_u8; store_params.model = &p->model; store_params.plate_data_list = plate_data_list; store_params.export_plate_idx = export_plate_idx; diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 29d302c776..8e7de91318 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -7,6 +7,7 @@ #include "../GUI/PartPlate.hpp" #include "libslic3r/CutUtils.hpp" #include "libslic3r/ClipperUtils.hpp" +#include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" #include "slic3r/GUI/Jobs/BoostThreadWorker.hpp" @@ -27,11 +28,19 @@ const double MIN_PA_K_VALUE = 0.0; const double MAX_PA_K_VALUE = 2.0; std::unique_ptr CalibUtils::print_worker; -wxString wxstr_temp_dir = fs::path(fs::temp_directory_path() / "calib").wstring(); -static const std::string temp_dir = wxstr_temp_dir.utf8_string(); -static const std::string temp_gcode_path = temp_dir + "/temp.gcode"; -static const std::string path = temp_dir + "/test.3mf"; -static const std::string config_3mf_path = temp_dir + "/test_config.3mf"; + +// Built lazily so temporary_dir() is read on first use, after set_temporary_dir() +// has run at startup (it isolates the temp root per user to avoid cross-user collisions). +static const std::string& calib_temp_dir() +{ + static const std::string dir = temporary_dir() + "/calib"; + return dir; +} +static std::string calib_temp_file(const std::string& name) { return calib_temp_dir() + "/" + name; } + +static const std::string gcode_filename = "temp.gcode"; +static const std::string model_filename = "test.3mf"; +static const std::string config_filename = "test_config.3mf"; static std::string MachineBedTypeString[7] = { "auto", @@ -1599,7 +1608,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f part_plate->update_slice_result_valid_state(true); gcode_result->reset(); - fff_print->export_gcode(temp_gcode_path, gcode_result, nullptr); + fff_print->export_gcode(calib_temp_file(gcode_filename), gcode_result, nullptr); std::vector thumbnails; PlateDataPtrs plate_data_list; @@ -1618,7 +1627,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f } for (auto plate_data : plate_data_list) { - plate_data->gcode_file = temp_gcode_path; + plate_data->gcode_file = calib_temp_file(gcode_filename); plate_data->is_sliced_valid = true; plate_data->printer_model_id = obj_->printer_type; FilamentInfo& filament_info = plate_data->slice_filaments_info.front(); @@ -1681,7 +1690,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f } StoreParams store_params; - store_params.path = path.c_str(); + store_params.path = calib_temp_file(model_filename); store_params.model = model; store_params.plate_data_list = plate_data_list; store_params.config = &new_print_config; @@ -1695,7 +1704,7 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f bool success = Slic3r::store_bbs_3mf(store_params); store_params.strategy = SaveStrategy::Silence | SaveStrategy::SplitModel | SaveStrategy::WithSliceInfo | SaveStrategy::SkipAuxiliary; - store_params.path = config_3mf_path.c_str(); + store_params.path = calib_temp_file(config_filename); success = Slic3r::store_bbs_3mf(store_params); release_PlateData_list(plate_data_list); @@ -1784,9 +1793,9 @@ void CalibUtils::send_to_print(const CalibInfo &calib_info, wxString &error_mess PrintPrepareData job_data; job_data.is_from_plater = false; job_data.plate_idx = 0; - job_data._3mf_config_path = config_3mf_path; - job_data._3mf_path = path; - job_data._temp_path = temp_dir; + job_data._3mf_config_path = calib_temp_file(config_filename); + job_data._3mf_path = calib_temp_file(model_filename); + job_data._temp_path = calib_temp_dir(); PlateListData plate_data; plate_data.is_valid = true; @@ -1889,9 +1898,9 @@ void CalibUtils::send_to_print(const std::vector &calib_infos, wxStri PrintPrepareData job_data; job_data.is_from_plater = false; job_data.plate_idx = 0; - job_data._3mf_config_path = config_3mf_path; - job_data._3mf_path = path; - job_data._temp_path = temp_dir; + job_data._3mf_config_path = calib_temp_file(config_filename); + job_data._3mf_path = calib_temp_file(model_filename); + job_data._temp_path = calib_temp_dir(); PlateListData plate_data; plate_data.is_valid = true;