1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
[]
= "rusty_alloc"
= "Allocator core of the rusty_alloc pure-Rust remake of mimalloc v2.4.5: segments, free-list-sharded pages, lock-free cross-thread frees, first-class heaps, arenas and a mi_*-compatible surface. Detects double frees. MIT."
= "https://docs.rs/rusty_alloc"
= true
= true
= true
= true
= true
= true
= true
= "README.md"
# The crate has NO dependencies on any target it currently ships to — this
# entry is compiled ONLY for targets that lack a 64-bit atomic (32-bit RISC-V
# and Xtensa: the Janus ESP32-C3/C6/S3 parts), so the x86-64, aarch64, wasm32
# and Windows builds remain dependency-free.
#
# Why a shim here and NARROWING everywhere else (P3 of docs/plans/small-metal.md):
# the crate's other 64-bit atomics are BITMAPS, whose word width is a free
# choice, and those were narrowed to `u32` — no dependency, still lock-free.
# These two are different: `options::{get,set}` are `i64` in an API frozen at
# v2.0.0, and `DeferredFreeFun`'s heartbeat is a `u64` in the C ABI shared with
# mimalloc's `mi_deferred_free_fun`. Narrowing either breaks a contract, and
# hand-rolling a 64-bit atomic out of two 32-bit halves inside an allocator is
# exactly the kind of thing that produces a subtle bug.
#
# `optional`, and enabled by `std` rather than by the target alone. The use site
# is gated `all(not(target_has_atomic = "64"), feature = "std")` -- a `no_std`
# build uses `options::split64` instead -- so a firmware was fetching and
# compiling a crate it then discarded at link time. Zero bytes on the device
# either way (verified: after `split64` landed, `portable_atomic` symbols in a
# shipped ESP32 image went to zero and its 4,288-byte `LOCKS` table left the
# symbol map), but an unused crate still shows up in an SBOM, a `cargo audit`
# and every dependency count a firmware reviewer looks at.
[]
= { = "1", = false, = ["fallback"], = true }
[]
# `std` is DEFAULT and additive — unlike the geometry `--cfg` (P2), which is
# deliberately not a feature. A feature is right here precisely because it IS
# additive: if any consumer in a graph needs `std`, enabling it for all of them
# is harmless. Turning it OFF is what a firmware does, and it selects the
# single-heap profile: no `thread_local!`, no environment, no `process::abort`
# (see `lib.rs`). P3 of docs/plans/small-metal.md.
= ["std"]
# Pulls `portable-atomic` ONLY where it is actually reachable: a target without
# 64-bit atomics that also has `std`. On every other target the dependency is
# not in the graph at all -- the `dep:` reference resolves against a
# target-gated declaration, so it simply does not apply where the target section
# does not match.
= ["dep:portable-atomic"]
# Full invariant checking: list walks, canaries, double-free detection (our `dmi`).
= []
# Feature-gated rdtsc path profiler (§7.5 of the plan). OFF = byte-identical build.
= []
# EXPERIMENTAL (2026-08-20): the free-list link BOUND without the encoding.
#
# `secure` costs a flat ~15 instructions per allocation, and almost all of that
# is the per-page keyed encode/decode plus key generation — not the bound
# itself, which is two ALU ops on a value already in a register. This feature
# isolates the bound so its cost can be measured on its own.
#
# What it buys WITHOUT encoding: an attacker who overwrites a plain link can
# still choose the value, but the bound confines the target to the SAME 32 MiB
# segment — which removes GOT entries, vtables, stack addresses and saved
# return addresses from reach entirely. Strictly weaker than `secure` (which
# also denies steering at all without both per-page keys), strictly stronger
# than today's default, which follows any value it is handed.
#
# Not on by default and not yet recommended: see the plan file for the
# measurement and the false-positive testing before promoting it.
= []
# EXPERIMENTAL (2026-08-20): per-page block-liveness bitmap.
#
# The one defence that actually stops the residual in R-005. Encoding and
# bounds both try to prevent a link being FORGED; this detects the thing a
# forgery is for — `malloc` handing out a block that is already live. It does
# not care how the link was forged, so it covers key recovery, relative
# forgery and blind luck alike.
#
# The bitmap is out-of-band with respect to the free list itself and carries no
# key, so unlike the encoding it is not defeated by a read primitive.
#
# OFF by default and independently switchable from `secure`/`linkcheck` so it
# can be measured, and reverted, on its own. Composes with either.
= []
# Hardened build (our `smi`). M8. Deliberately NOT default — see the cost below.
#
# Always on with this feature: per-page encrypted free-list links, plus a
# same-segment + alignment bound on every decoded link (`page::link_is_plausible`).
#
# Available but INERT until asked for: guarded objects and their guard pages.
# The `guarded_max` OPTION defaults to 0, so `init::create_heap` skips both
# `guarded_set_*` calls and the heap keeps `guarded_rate: 0`. Enabling `secure`
# alone therefore does NOT give you guard pages — set the `guarded_max` option
# > 0, or call `guarded_set_sample_rate` / `mi_heap_guarded_set_sample_rate`.
# And only where a page CAN be protected: `prim::fixed` (bare metal) and
# `prim::wasm` have no MMU, so there the sampler is compiled out and the
# setters leave it off rather than hand out unprotected "guarded" segments.
#
# Measured cost (2026-08-20, callgrind Ir, same binary both arms): a FLAT ~15
# instructions per allocation — 8-25% per-op depending only on how cheap the op
# is (batch 60->75, big 171->185, `usable` and `huge` exactly +0.00 since
# neither walks a free list) and +0.6-1.8% whole-program on lua/perl/sqlite.
# Opt-in because that is enough to forfeit mimalloc parity, which is the
# headline result: perl 0.9991 -> 1.0160, sqlite 1.0003 -> 1.0061,
# calloc 0.949 -> 1.041, batch_lifo 1.008 -> 1.259.
= []
[]
= { = "0.60", = [
"Win32_Foundation",
"Win32_System_Memory",
"Win32_System_SystemInformation",
"Win32_System_Threading",
"Win32_System_Performance",
"Win32_System_ProcessStatus",
"Win32_Security_Cryptography",
] }
[]
= { = "0.2", = false }
[]
= "0.7"
# H-28: the documented invariants get PROPERTIES, not just examples. Kept
# dev-only and vet-exempted at safe-to-run — it can never reach a published
# artifact.
= { = "1", = false, = ["std"] }
[]
= true