@@ -14,39 +14,48 @@ address**.
1414
1515Rust (or, rather, LLVM) by default de-duplicates or reuses ** addresses** of ` static ` variables in
1616` release ` builds. And somewhat in ` debug ` builds, too. For most purposes that is good: The result
17- binary is smaller, and because of more successful cache hits, the execution may be faster.
17+ binary is smaller, and because of more successful cache hits, the execution is faster.
1818
1919However, that is counter-productive when the code identifies/compares ` static ` data by memory
2020address of the reference (whether a Rust reference/slice, or a pointer/pointer range). For example,
2121an existing Rust/3rd party API may accept ("ordinary") references/slices. You may want to extend
2222that API's protocol/behavior with signalling/special handling when the client sends in your
2323designated ` static ` variable by reference/slice/pointer/pointer range. (Your special handler may
2424cast such references/slices to pointers and compare them by address with
25- [ ` core::ptr::eq() ` ] ( https://doc.rust-lang.org/nightly/core/ptr/fn.eq.html ) .)
26-
27- Then you don't want the client, nor the compiler/LLVM, to reuse/share the memory address of such a
28- designated ` static ` for any other ("ordinary") ` static ` or ` const ` values/expressions, or local
29- numerical/character/byte/string slice literals. That does work out of the box when the client passes
30- a reference/slice defined as ` static ` : (even with the default ` release ` optimizations) each ` static `
31- gets its own memory space. See a test [ ` src/lib.rs ` ->
25+ [ ` core::ptr::eq() ` ] ( https://doc.rust-lang.org/nightly/core/ptr/fn.eq.html ) or
26+ [ ` core::ptr::addr_eq() ` ] ( https://doc.rust-lang.org/nightly/core/ptr/fn.addr_eq.html ) .)
27+
28+ Then you do ** not want** the client, nor the compiler/LLVM, to reuse/share the memory address of
29+ such a designated ` static ` for any other ("ordinary") ` static ` or ` const ` values/expressions, or
30+ local numerical/character/byte/string slice literals. That does work out of the box when the client
31+ passes a reference/slice defined as ` static ` : each ` static ` gets its own memory space (even with the
32+ default ` release ` optimizations). See a test [ ` src/lib.rs ` ->
3233` addresses_unique_between_statics() ` ] ( https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L72 ) .
3334
3435However, there is a problem (in ` release ` mode, and for some types even in ` debug ` mode). It affects
3536("ordinary") ` const ` values/expressions that equal in value to any ` static ` (which may be your
36- designated ` static ` ). Rust/LLVM re-uses address of one such matching ` static ` ' for references to
37+ designated ` static ` ). Rust/LLVM re-uses address of one such matching ` static ` ' for references to any
3738equal value(s) defined as ` const ` . See a test [ ` src/lib.rs ` ->
3839` addresses_not_unique_between_const_and_static() ` ] ( https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L95 ) .
39- Such ` const ` , ` static ` or literal could be in 3rd party code, and even private (see
40- [ ` demo-fat-lto ` ] ( ./demo-fat-lto ) )!
40+ Such ` const ` , ` static ` or literal could be in 3rd party code, and private - not even exported (see
41+ [ ` cross-crate-demo ` ] ( cross-crate-demo ) )!
4142
42- Things get worse: ` debug ` builds don't have this consistent.
43+ Things get worse: ` debug ` builds don't have this consistent:
4344
4445- For some types (` u8 ` , numeric primitive-based enums) ` debug ` builds don't reuse ` static ` addresses
4546 for references/slices to ` const ` values. But
4647- For other types (` str ` ), ` debug ` builds do reuse them...
47- - Only ` MIRI ` doesn't reuse ` static ` addresses at all.
4848
49- Even worse so: ` release ` builds don't have this consistent.
49+ ` MIRI ` reuses ` static ` addresses even less (than ` debug ` does), but it still does reuse them
50+ sometimes - for example, between byte literals (` b"Hello" ` ) and equal string literals (` "Hello" ` ).
51+
52+ Even worse so: ` release ` builds don't have this consistent. De-duplication across crates depends on
53+ "fat" link time optimization (LTO):
54+
55+ ``` toml
56+ [profile .release ]
57+ lto = " fat"
58+ ```
5059
5160## Solution
5261
@@ -102,7 +111,8 @@ versions `1.0` or higher.
102111- ** Odd** -numbered major versions (` 0.3 ` , ` 0.5 ` ...)
103112 - always contain ` -nightly ` (pre-release identifier) in their name.
104113 - are, indeed, for ` nightly ` (** unstable** ) functionality, and need ` nightly ` Rust toolchain
105- (indicated with ` rust-toolchain.toml ` which is present on ` nightly ` branch only).
114+ (indicated with ` rust-toolchain.toml ` which is present on [ ` nightly `
115+ branch] ( https://github.com/peter-lyons-kehl/ndd/tree/nightly ) GIT branch only).
106116 - include functionality already present in some lower stable versions. Not all of them - only:
107117 - stable versions with a ** lower major** numeric version, and
108118 - if the stable ** major** version is lower by ** ` 0.1 ` only** (and not by more), then the stable
@@ -210,22 +220,27 @@ stable not in years, but sooner.
210220
211221## Quality
212222
213- Checked and tested (also with [ MIRI] ( https://github.com/rust-lang/miri ) ):
223+ Checks and tests are run by [ GitHub Actions (CI)] ( .github/workflows/main.yml ) . All scripts run on
224+ Alpine Linux and are POSIX-compliant.
225+
214226- ` cargo clippy `
227+ - ` cargo fmt --check `
228+ - ` cargo doc --no-deps --quiet `
215229- ` cargo test `
216230- ` cargo test --release `
217- - ` rustup install nightly --profile minimal `
218- - ` rustup +nightly component add miri `
219- - ` cargo +nightly miri test `
220- - ` release ` -only tests:
221- - ` demo-fat-lto/static_option_u8.sh `
222- - ` demo-fat-lto/static_str.sh `
223- - ` demo-fat-lto/literal_str.sh `
224-
225- The versioning convention is validated:
226-
227- - locally with GIT [ pre-commit] ( ./pre-commit ) hook, and
228- - with a [ GitHub action] ( .github/workflows/main.yml ) .
231+ - with [ MIRI] ( https://github.com/rust-lang/miri ) :
232+ - ` rustup install nightly --profile minimal `
233+ - ` rustup +nightly component add miri `
234+ - ` cargo +nightly miri test `
235+ - ` release ` -only demonstration:
236+ - ` cross-crate-demo/bin/static_option_u8.sh `
237+ - ` cross-crate-demo/bin/static_str.sh `
238+ - ` cross-crate-demo/bin/literal_str.sh `
239+ - ` cross-crate-demo/bin-fat-lto/static_option_u8.sh `
240+ - ` cross-crate-demo/bin-fat-lto/static_str.sh `
241+ - ` cross-crate-demo/bin-fat-lto/literal_str.sh `
242+ - validate the versioning convention:
243+ - [ ` pre-commit ` ] ( ./pre-commit )
229244
230245## Use cases
231246
0 commit comments