mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-15 23:12:08 +00:00
Fixed a rare crash on app startup caused by ENOTSUP (errno 45) on Mac (#14686)
fix: prevent startup crash when preset-sync directory scan hits a transient FS error On startup the user-preset sync thread scans the preset folder for orphaned .info files (scan_orphaned_info_files). It iterated the directory with a throwing boost::filesystem::directory_iterator while running on a background thread that has no exception guard. On macOS, readdir() can intermittently fail with ENOTSUP (errno 45); boost then throws filesystem_error, which -- uncaught on the sync thread -- calls std::terminate and aborts the whole application on startup. - Iterate with the error_code-based directory_iterator so a transient read failure is logged and skipped instead of thrown. The orphan scan is best-effort and re-runs on the next sync, so skipping a cycle is harmless. This mirrors the existing pattern in has_json_presets() and the plugin scan. - Wrap the entire sync-thread body in try/catch as defense-in-depth, so no future uncaught exception on that otherwise-unguarded thread can abort the app.
This commit is contained in:
@@ -6965,6 +6965,10 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg)
|
||||
// finishFn tears down the progress dialog (and clears the re-entrancy guard), so it
|
||||
// must run on every exit path — otherwise an early bail-out would leak the modal
|
||||
// dialog and leave the guard stuck, blocking all later manual syncs.
|
||||
// Guard the whole thread body: an uncaught exception here (e.g. a transient
|
||||
// boost::filesystem error while scanning the preset folder) would otherwise
|
||||
// propagate out of the thread and terminate the entire application.
|
||||
try {
|
||||
if (!m_agent) { finishFn(false); return; }
|
||||
|
||||
// One-time scan for orphaned .info files left over from offline deletions; queues HTTP DELETEs.
|
||||
@@ -7206,6 +7210,11 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg)
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "user preset sync thread terminated by exception: " << e.what();
|
||||
} catch (...) {
|
||||
BOOST_LOG_TRIVIAL(error) << "user preset sync thread terminated by unknown exception";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8526,8 +8535,13 @@ void GUI_App::scan_orphaned_info_files()
|
||||
if (!fs::exists(type_dir))
|
||||
continue;
|
||||
|
||||
// Iterate through all .info files
|
||||
for (auto& entry : boost::filesystem::directory_iterator(type_dir)) {
|
||||
// Iterate through all .info files. Use the error_code-based iterator so a transient
|
||||
// directory-read failure (e.g. macOS readdir returning ENOTSUP) is logged and skipped
|
||||
// instead of throwing an uncaught exception that would terminate the app from the
|
||||
// background sync thread this runs on.
|
||||
boost::system::error_code ec;
|
||||
for (boost::filesystem::directory_iterator it(type_dir, ec), end; !ec && it != end; it.increment(ec)) {
|
||||
const auto& entry = *it;
|
||||
if (entry.path().extension() != ".info")
|
||||
continue;
|
||||
|
||||
@@ -8546,6 +8560,8 @@ void GUI_App::scan_orphaned_info_files()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ec)
|
||||
BOOST_LOG_TRIVIAL(warning) << "scan_orphaned_info_files: failed to scan " << type_dir.string() << ": " << ec.message();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user