Skip to content

chore: rustc: 1.99.0 -> 1.99.1 - #11935

Merged
basvandijk merged 2 commits into
masterfrom
bas/rust-1.99.1
Oct 23, 2026
Merged

basvandijk merged 2 commits into
masterfrom
bas/rust-1.99.1

Conversation

@basvandijk

@basvandijk basvandijk commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Upgrade the rust toolchain from 1.99.0 to 1.99.1. See:
https://blog.rust-lang.org/2026/10/15/Rust-1.99.1/.

1.99.1 is a point release with three backported fixes
(1.99.0...1.99.1). This PR is only the
version bump in rust-toolchain.toml and bazel/rust.MODULE.bazel. No clippy fixes, test data or
canbench baselines need to change. Clippy (Cargo Lint Linux and PocketIC Lint on Windows) is
clean on 1.99.1.

The x86_64 bool miscompilation did not affect the IC

rust#163911: rust#159317, new in 1.99.0, dropped
zeroext from bool return values of extern "C" and most other non-Rust ABIs ("C-unwind",
"system", "sysv64", ...) on x86_64 targets other than macOS and Windows, such as
x86_64-unknown-linux-gnu. A Rust callee built with 1.99.0 can then return false with bits 1-7
of al set, which a caller that tests the whole byte reads as true. Rust callers are not
affected, because 1.99.0 only tests bit 0. 1.99.1 restores zeroext (rust#163917, backported in
rust#164232).

The one place in the IC where this could bite is Wasmtime. Every host function (the ic0.* system
API, __.out_of_instructions, __.internal_trap, ...) is called through Wasmtime's
extern "C" fn array_call_trampoline(..) -> bool, which returns false when the host call traps.
Cranelift's wasm-to-host trampolines test that byte with test %al,%al. A dirty false would
therefore have let canister code keep running after a host call that trapped.

That did not happen. //publish/binaries:canister_sandbox and //publish/binaries:replica were
built from master 592d14c with both toolchains, with the release settings (-c opt,
-Cdebug-assertions=off), and compared:

  • All 166 array_call_trampoline instances (the 83 func_wrap closures in linker.rs, each
    compiled for 32- and 64-bit main memory) and the 10 Wasmtime libcalls that return bool (5 of
    them are compiled out in the IC and only panic) set al only with xor %eax,%eax, mov $0x1,%al
    or a call to such a function, on every return path, in both binaries. Apart from breakpoint,
    which returns a constant 1, they return the result of catch_unwind_and_record_trap, a Rust-ABI
    function, and Rust-ABI bool returns kept zeroext in 1.99.0.
  • Comparing every function of the two builds finds no function where 1.99.1 adds masking before a
    ret. The only bool-ABI changes are on the caller side, in three Wasmtime functions
    (catch_traps twice and CodeMemory::publish), where for example test $0x1,%r15b becomes
    test %r15b,%r15b. Their callees (Cranelift's array-to-wasm trampolines, the host trampolines
    above when an exported function is an imported one, and a C helper) always return 0 or 1, so
    behaviour does not change.
  • Apart from Wasmtime, neither IC code nor any other third-party crate in the lock files defines a
    non-Rust-ABI function returning bool that C, asm or JIT code calls. Wasmtime's other such
    functions (component model, stack switching) are not compiled into the IC.

The remaining machine-code differences (under 1% of the functions in each binary, plus renamed
symbols) are optimisation churn. rustc hashes its version string into every crate's StableCrateId.
That changes symbol names, TypeIds and how items are partitioned and ordered, and with them some
inlining and function-merging decisions. With the compiler held fixed, changing only that hash input
reproduces the same kinds of differences in test builds of Wasmtime and of a canister.

canbench

All 8 _update targets were run on the same commit with both toolchains. No benchmark or scope
moves beyond its noise threshold, so no baseline is updated (as with the suites that stayed within
their thresholds in #11735). All 8 _test targets pass on 1.99.1 against the committed baselines.

suite _test target threshold rustc 1.99.0 → 1.99.1, same commit committed baseline → 1.99.1 (what _test checks)
ckBTC minter //rs/bitcoin/ckbtc/minter:ckbtc_minter_canbench_test 2% identical 0.00% … +0.25%
ckETH minter //rs/ethereum/cketh/minter:cketh_minter_canbench_test 2% +50 instructions +1.72%
ICP ledger //rs/ledger_suite/icp/ledger:ledger_canbench_test 2% identical -1.19% … +0.19%
ICRC-1 ledger (u64) //rs/ledger_suite/icrc1/ledger:canbench_u64_test 2% identical -<0.01% … +0.01%
ICRC-1 ledger (u256) //rs/ledger_suite/icrc1/ledger:canbench_u256_test 2% identical -0.04% … +1.68%
NNS governance //rs/nns/governance:governance-canbench_test 5% 30 of 30 entries, -0.90% … +1.14% -2.59% … +1.14%
Registry //rs/registry/canister:registry-canbench_test 2% identical -0.35% … +0.01%
SNS governance //rs/sns/governance:governance-canbench_test 2% identical +0.01%

None of the three fixes changes wasm32 codegen, so 1.99.1's own effect on canister Wasm is the same
version-hash churn as above. Across the 8 modules, about 180 of ~20,400 functions get a different
instruction sequence, and nearly all other differences in function bodies are renumbered function
indices, data addresses and table slots. With the crate hashes pinned (RUSTC_FORCE_RUSTC_VERSION),
1.99.0 and 1.99.1 produce identical code and data for the SNS governance canister. The churn moves
NNS governance by -0.90% to +1.14% and ckETH by 50 instructions, and leaves the other six suites
identical. The rest of the last column is drift that master already has. Regenerating the baselines
with 1.99.0 on master gives the same numbers for the other six suites, and all of ckETH's +1.72%
except those 50 instructions.

NNS governance, rustc 1.99.0 → 1.99.1 on the same commit (30 entries)
name ins (1.99.1) ins Δ ins Δ%
add_neuron_active_maximum 65.33M +737.49K +1.14%
add_neuron_inactive_maximum 65.33M +737.48K +1.14%
add_neuron_active_typical 4.61M +41.97K +0.92%
add_neuron_inactive_typical 4.61M +41.96K +0.92%
list_ready_to_spawn_neuron_ids 37.14M -336.15K -0.90%
unstake_maturity_of_dissolved_neurons::list_neuron_ids 38.52M -347.15K -0.89%
list_active_neurons_fund_neurons 2.18M -18.87K -0.86%
unstake_maturity_of_dissolved_neurons 63.97M -368.75K -0.57%
compute_ballots_for_new_proposal_with_stable_neurons 2.35M -11.26K -0.48%
list_neurons_by_subaccount 33.07M +144.90K +0.44%
list_neurons 34.20M +134.28K +0.39%
with_neuron_mut_all_sections_typical 852.14K +2.98K +0.35%
neuron_metrics_calculation 3.32M -11.24K -0.34%
range_neurons_performance 50.71M +156.18K +0.31%
record_neuron_vote_known_neuron_voting_history 143.65K +419 +0.29%
single_vote_all 279.43K +755 +0.27%
voting_power_snapshots_latest_snapshot_timestamp_seconds 7.58K -19 -0.25%
record_known_neuron_vote 183.62K +442 +0.24%
distribute_rewards_with_stable_neurons 2.80M -5.71K -0.20%
voting_power_snapshots_is_latest_snapshot_a_spike_false 30.05K -38 -0.13%
voting_power_snapshots_is_latest_snapshot_a_spike_true 30.07K -38 -0.13%
centralized_following_all 42.26M +52.89K +0.13%
neuron_data_validation 205.01M -211.68K -0.10%
with_neuron_mut_all_sections_maximum 4.12M +4.17K +0.10%
draw_maturity_from_neurons_fund 7.58M +7.60K +0.10%
list_proposals 77.12K -72 -0.09%
unstake_maturity_of_dissolved_neurons::unstake_maturity 25.45M -21.60K -0.08%
cascading_vote_stable_everything 105.40M -38.92K -0.04%
with_neuron_mut_main_section_typical 393.94K +75 +0.02%
with_neuron_mut_main_section_maximum 2.25M -384 -0.02%

Other checks

  • //rs/recovery/subnet_splitting:integration_test passes on 1.99.1 without a re-pin.
  • rust#163614 (wcslen): compiler-builtins now
    provides a weak wcslen on wasm32-unknown-unknown. It is only linked when referenced, and no
    canister references it: code that did would have failed to link on 1.99.0.
  • rust#163947 (macOS rust-lld): rust-lld
    could not load libLLVM.dylib when rustc ran without the rustup proxy. The arm64-darwin CI job,
    which builds canister Wasm with Bazel, never hit this: rules_rust unpacks llvm-tools into the
    same directory as rustc, and llvm-tools ships libLLVM.dylib in lib/rustlib/<host>/lib/,
    which is where rust-lld looks for it.
  • No repin is needed: Bazel accepts the existing Cargo.Bazel.*.lock files and no third-party crate
    changed. rules_rust 0.74.0 ships no checksums for 1.99.1, so the toolchain is downloaded
    unverified, as 1.99.0 is today.
  • bazel build //... --nobuild and buildifier pass. CI passes on all targets
    (CI_ALL_BAZEL_TARGETS), including the arm64-linux and arm64-darwin builds and the Windows
    PocketIC jobs.

🤖 Generated with Claude Code

https://blog.rust-lang.org/2026/10/15/Rust-1.99.1/

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@basvandijk basvandijk added the CI_ALL_BAZEL_TARGETS Runs all bazel targets label Oct 23, 2026
@github-actions github-actions Bot added the chore label Oct 23, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Both version pins are consistent, the change is limited to a patch upgrade, and no blocking issues were identified.

No open issues 🎉

What changed in this PR

Updates the repository’s Rust toolchain from 1.99.0 to 1.99.1, keeping rustup and Bazel aligned on the patch release.

Changes:

  • Updates both toolchain version pins to 1.99.1.
  • Leaves compiler settings, dependencies, test data, and benchmark baselines unchanged.
File Description
rust-toolchain.toml Selects Rust 1.99.1 for rustup-based tooling.
bazel/​rust.MODULE.bazel Selects Rust 1.99.1 for Bazel builds.

Review effort: Balanced

@basvandijk
basvandijk marked this pull request as ready for review October 23, 2026 14:59
@basvandijk
basvandijk requested review from a team as code owners October 23, 2026 14:59
@basvandijk
basvandijk enabled auto-merge October 23, 2026 15:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

Both version pins are consistent, the patch upgrade has reported cross-platform validation, and no blocking issues were identified.

No open issues 🎉

Review effort: Balanced

@basvandijk
basvandijk added this pull request to the merge queue Oct 23, 2026
Merged via the queue into master with commit e0eac78 Oct 23, 2026
47 of 48 checks passed
@basvandijk
basvandijk deleted the bas/rust-1.99.1 branch October 23, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants