Gate network plugin loading to ABI-compatible series

Trim the version whitelist to the latest series plus the pinned legacy build,
and reject out-of-series configured versions at startup, compatibility check,
and load failure - falling back to the latest installed build or the clean
re-download flow so the config never keeps pointing at an unsupported build.
This commit is contained in:
SoftFever
2026-07-18 01:45:54 +08:00
parent 6767ab5ae0
commit 12720ccbd8
3 changed files with 85 additions and 11 deletions

View File

@@ -1967,6 +1967,13 @@ bool GUI_App::check_networking_version()
BOOST_LOG_TRIVIAL(info) << "check_networking_version: network_ver=" << network_ver << ", expected=" << studio_ver;
// A configured version outside the whitelisted series must never pass as compatible,
// even if it matches the loaded library - its ABI does not match this build.
if (!use_legacy_network_plugin() && !is_supported_network_version(studio_ver)) {
m_networking_compatible = false;
return false;
}
if (network_ver.length() >= 8 && studio_ver.length() >= 8) {
if (network_ver.substr(0,8) == studio_ver.substr(0,8)) {
m_networking_compatible = true;
@@ -3451,6 +3458,21 @@ bool GUI_App::on_init_network(bool try_backup)
std::string config_version = app_config->get_network_plugin_version();
if (should_load_networking_plugin) {
// A version outside the whitelisted series (e.g. 02.03.00.62 configured by an older
// Orca release) must not be loaded - its ABI no longer matches this build. Fall back
// to the latest supported build if it is already on disk; otherwise clear the
// configured version so the normal empty-version download flow takes over (the
// download URL and install adoption both derive from the configured version, so it
// must not keep pointing at the unsupported build).
if (!config_version.empty() && !is_supported_network_version(config_version)) {
std::string latest = get_latest_network_version();
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": configured plugin version " << config_version
<< " is no longer supported, falling back to " << latest;
config_version = BBLNetworkPlugin::versioned_library_exists(latest) ? latest : "";
app_config->set_network_plugin_version(config_version);
app_config->save();
}
if (config_version.empty()) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": no version configured, need to download";
m_networking_need_update = true;
@@ -3505,6 +3527,20 @@ bool GUI_App::on_init_network(bool try_backup)
}
} else {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_init_network, load dll failed";
// A failed install can leave the config naming a build that never made it to
// disk (download_plugin() adopts the downloaded version up front so that
// install_plugin() can name the library after it). If the whitelisted latest
// is still installed, fall back to it instead of dropping the user into the
// re-download flow without networking.
std::string latest = get_latest_network_version();
if (config_version != latest && BBLNetworkPlugin::versioned_library_exists(latest)) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": falling back to installed " << latest;
config_version = latest;
app_config->set_network_plugin_version(latest);
app_config->save();
load_agent_dll = Slic3r::NetworkAgent::initialize_network_module(false, config_version);
goto __retry;
}
if (should_load_networking_plugin) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_init_network, need upload network module";
m_networking_need_update = true;

View File

@@ -359,11 +359,12 @@ struct NetworkLibraryVersion {
const char* warning;
};
// Only the latest series and the legacy build are offered/loadable: the host binds the
// modern ABI (by-value struct layouts, function signatures) of exactly one series, plus
// a dedicated shim for the legacy build. Older 02.0x series expect different layouts
// and must not be loaded - see is_supported_network_version().
static const NetworkLibraryVersion AVAILABLE_NETWORK_VERSIONS[] = {
{"02.08.01.52", "02.08.01.52", nullptr, true, nullptr},
{"02.03.00.62", "02.03.00.62", nullptr, false, nullptr},
{"02.01.01.52", "02.01.01.52", nullptr, false, nullptr},
{"02.00.02.50", "02.00.02.50", nullptr, false, "This version may crash on startup due to Bambu Lab's signature verification."},
{BAMBU_NETWORK_AGENT_VERSION_LEGACY, BAMBU_NETWORK_AGENT_VERSION_LEGACY " (legacy)", nullptr, false, nullptr},
};
@@ -377,6 +378,25 @@ inline const char* get_latest_network_version() {
return AVAILABLE_NETWORK_VERSIONS[0].version;
}
// True when the version can be loaded through the ABI this build was compiled against:
// an exact whitelist entry, or a build from the same AA.BB.CC series as a non-legacy
// whitelist entry (the plugin ABI is stable within a series, and the OTA sync only ever
// installs same-series updates). Anything else - in particular older 02.0x series a
// previous Orca release whitelisted - expects different by-value struct layouts and
// function signatures and must not be loaded.
inline bool is_supported_network_version(const std::string& version) {
for (size_t i = 0; i < AVAILABLE_NETWORK_VERSIONS_COUNT; ++i) {
const std::string base = AVAILABLE_NETWORK_VERSIONS[i].version;
if (version == base)
return true;
if (base == BAMBU_NETWORK_AGENT_VERSION_LEGACY)
continue;
if (version.size() >= 8 && base.size() >= 8 && version.compare(0, 8, base, 0, 8) == 0)
return true;
}
return false;
}
struct NetworkLibraryVersionInfo {
std::string version;
std::string base_version;

View File

@@ -66,14 +66,14 @@ TEST_CASE_METHOD(PluginFolderFixture, "Same-series OTA plugin versions are surfa
add_plugin("02.08.01.55"); // same series as the whitelisted latest -> listed
add_plugin("02.09.00.10"); // unknown series -> not listed
add_plugin("02.08.01.52-custom"); // suffixed build of a whitelisted base -> listed (existing behavior)
add_plugin("02.03.00.62"); // exactly a whitelisted version -> no duplicate
add_plugin("02.03.00.62"); // series no longer whitelisted -> not listed
auto versions = get_all_available_versions();
REQUIRE(count_version(versions, "02.08.01.55") == 1);
REQUIRE(count_version(versions, "02.09.00.10") == 0);
REQUIRE(count_version(versions, "02.08.01.52-custom") == 1);
REQUIRE(count_version(versions, "02.03.00.62") == 1);
REQUIRE(count_version(versions, "02.03.00.62") == 0);
size_t latest_pos = versions.size(), ota_pos = versions.size();
for (size_t i = 0; i < versions.size(); ++i) {
@@ -98,16 +98,34 @@ TEST_CASE_METHOD(PluginFolderFixture, "Same-series OTA plugin versions are surfa
REQUIRE_FALSE(versions[latest_pos].is_latest);
REQUIRE_FALSE(versions[latest_pos].is_installed);
// A whitelisted version whose library exists on disk is marked installed.
for (const auto& info : versions) {
if (info.version == "02.03.00.62")
REQUIRE(info.is_installed);
}
// The static default used for download and update-check decisions is unchanged.
REQUIRE(std::string(get_latest_network_version()) == "02.08.01.52");
}
TEST_CASE("Only whitelisted series pass the load gate", "[NetworkVersions]")
{
// Exact whitelist entries.
REQUIRE(is_supported_network_version("02.08.01.52"));
REQUIRE(is_supported_network_version(BAMBU_NETWORK_AGENT_VERSION_LEGACY));
// Same-series OTA builds and suffixed dev builds of the whitelisted latest.
REQUIRE(is_supported_network_version("02.08.01.55"));
REQUIRE(is_supported_network_version("02.08.01.52-custom"));
// Series whitelisted by previous Orca releases - their ABI no longer matches.
REQUIRE_FALSE(is_supported_network_version("02.03.00.62"));
REQUIRE_FALSE(is_supported_network_version("02.01.01.52"));
REQUIRE_FALSE(is_supported_network_version("02.00.02.50"));
// Unknown series, legacy siblings, and malformed values.
REQUIRE_FALSE(is_supported_network_version("02.09.00.10"));
std::string legacy = BAMBU_NETWORK_AGENT_VERSION_LEGACY;
std::string legacy_sibling = legacy.substr(0, 9) + (legacy.substr(9) == "99" ? "98" : "99");
REQUIRE_FALSE(is_supported_network_version(legacy_sibling));
REQUIRE_FALSE(is_supported_network_version(""));
REQUIRE_FALSE(is_supported_network_version("02.08"));
}
TEST_CASE_METHOD(PluginFolderFixture, "Legacy series never adopts discovered builds", "[NetworkVersions]")
{
// A different build of the legacy series must not be surfaced: is_legacy_version()