fix: isolate calibration temp paths per user (#14619)

* fix: isolate calibration temp paths per user

The calibration temp files under <temp>/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 <temp>/orcaslicer_<uid>/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.
This commit is contained in:
Kris Austin
2026-07-08 08:14:05 -05:00
committed by GitHub
parent b37fa41742
commit b58025575d
5 changed files with 29 additions and 20 deletions
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -226,7 +226,7 @@ typedef std::map<int, PlateData*> PlateDataMaps;
struct StoreParams
{
const char* path;
std::string path;
Model* model = nullptr;
PlateDataPtrs plate_data_list;
int export_plate_idx = -1;
+1 -1
View File
@@ -15742,7 +15742,7 @@ int Plater::export_3mf(const boost::filesystem::path& output_path, SaveStrategy
std::vector<Preset*> 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;
+24 -15
View File
@@ -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<Worker> 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<ThumbnailData*> 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<CalibInfo> &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;