Skip to content

Commit e330e1d

Browse files
NonDeDuplicatedCStr; cross_crate_demo_problem/ re-org; removed nightly-only mod infer
1 parent ad399e7 commit e330e1d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+315
-178
lines changed

.github/workflows/main.yml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,21 @@ jobs:
2828
rustup install nightly --profile minimal
2929
rustup +nightly component add miri
3030
cargo +nightly miri test
31-
cross-crate-demo-problem/bin/invocation_scripts/static_option_u8.sh
32-
cross-crate-demo-problem/bin/invocation_scripts/static_str.sh
33-
cross-crate-demo-problem/bin/invocation_scripts/literal_str.sh
34-
cross-crate-demo-problem/bin-fat-lto/invocation_scripts/static_option_u8.sh
35-
cross-crate-demo-problem/bin-fat-lto/invocation_scripts/static_str.sh
36-
cross-crate-demo-problem/bin-fat-lto/invocation_scripts/literal_str.sh
31+
cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh dev literal_str
32+
cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh release literal_str
33+
cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh dev const_str
34+
cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh release const_str
35+
cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh dev const_option_u8
36+
cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh release const_option_u8
37+
cross_crate_demo_bug/bin_non_lto/deduplicated_out.sh dev const_bytes
38+
cross_crate_demo_bug/bin_non_lto/deduplicated_out.sh release const_bytes
39+
40+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev literal_str
41+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release literal_str
42+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev const_str
43+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release const_str
44+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev const_option_u8
45+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release const_option_u8
46+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev const_bytes
47+
cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release const_bytes
3748
shell: sh

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
/target
2-
/cross-crate-demo*/*/target
3-
2+
/cross_crate_demo*/*/target
3+
/cross_crate_demo*/callee/Cargo.lock

CHANGELOG.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,25 @@ This reflects GIT commits on `main` branch (the default branch), that is, `stabl
77
[`nightly` GIT branch](https://github.com/peter-lyons-kehl/ndd/tree/nightly) may occasionally be
88
behind `main`. See also [CONTRIBUTING.md](CONTRIBUTING.md).
99

10+
<!--
11+
## 0.3.7-nightly
12+
13+
`ndd::infer::NonDeDuplicatedStr` and `ndd::infer::NonDeDuplicatedCStr`
14+
-->
15+
1016
## 0.2.7 (stable) and 0.3.7-nightly
1117

12-
`NonDeDuplicatedCStr` for FFI CStr.
18+
- `NonDeDuplicatedCStr` for FFI
19+
[`core::ffi::CStr`](https://doc.rust-lang.org/nightly/core/ffi/struct.CStr.html)
20+
- Renamed `cross-crate-demo-problem/` to `cross_crate_demo_bug/`.
21+
- [`cross_crate_shared_scripts/`](cross_crate_shared_scripts/)
22+
- Created `cross_crate_demo_fix/`, added to `README.md` and GitHub actions.
1323

1424
## 0.2.6 (stable)
1525

1626
- Renamed `cross-crate-demo` -> `cross-crate-demo-problem`.
17-
- Moved `cross-crate-demo/bin*/*.sh` scripts one level deeper to `invocation_scripts`.
27+
- Moved `cross-crate-demo/bin*/*.sh` scripts one level deeper to `invocation_scripts` (later moved
28+
to `cross_crate_shared_scripts/`).
1829
- API
1930
- `NonDeDuplicatedStr`
2031

@@ -23,8 +34,8 @@ behind `main`. See also [CONTRIBUTING.md](CONTRIBUTING.md).
2334
- `NonDeDuplicated`'s generic parameter `T` must now implement
2435
[`core::any::Any`](https://doc.rust-lang.org/nightly/core/any/trait.Any.html).
2536
- Tests with [MIRI](https://github.com/rust-lang/miri).
26-
- [`cross-crate-demo`](cross-crate-demo/) demonstrates effect of Fat LTO (Link Time Optimization)
27-
across crates. Also invoked from GitHub Actions.
37+
- `cross-crate-demo/` (later renamed to `cross_crate_demo_bug/`) demonstrates effect of Fat LTO
38+
(Link Time Optimization) across crates. Also invoked from GitHub Actions.
2839
- Docs.
2940

3041
## 0.2.4 (stable)

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ branch](https://github.com/peter-lyons-kehl/ndd/tree/nightly).
2727
## File formatting
2828

2929
- Use `cargo fmt` for Rust source.
30-
- Leave one empty line at the end of Rust, Markdown and any other source files.
30+
- Leave one empty line at the end of Rust, Markdown, Toml, Yaml and any other source/config files.

README.md

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -13,41 +13,47 @@ address**.
1313
## Problem
1414

1515
Rust (or, rather, LLVM) by default de-duplicates or reuses **addresses** of `static` variables in
16-
`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 is faster.
16+
`release` builds. And somewhat in `dev` (debug) builds, too. For most purposes that is good: The
17+
result binary is smaller, and because of more successful cache hits, the execution is faster.
1818

1919
However, that is counter-productive when the code identifies/compares `static` data by memory
20-
address of the reference (whether a Rust reference/slice, or a pointer/pointer range). For example,
21-
an existing Rust/3rd party API may accept ("ordinary") references/slices. You may want to extend
22-
that API's protocol/behavior with signalling/special handling when the client sends in your
23-
designated `static` variable by reference/slice/pointer/pointer range. (Your special handler may
24-
cast such references/slices to pointers and compare them by address with
20+
address of the reference (whether a Rust reference/slice, a pointer/pointer range, or the pointer
21+
casted to `usize`). For example, an existing Rust/3rd party API may accept ("ordinary")
22+
references/slices. You may want to extend that API's protocol/behavior with signalling/special
23+
handling when the client sends in your designated `static` variable by
24+
reference/slice/pointer/pointer range. (Your special handler may cast such references/slices to
25+
pointers and compare them by address with
2526
[`core::ptr::eq()`](https://doc.rust-lang.org/nightly/core/ptr/fn.eq.html) or
2627
[`core::ptr::addr_eq()`](https://doc.rust-lang.org/nightly/core/ptr/fn.addr_eq.html).)
2728

2829
Then you do **not want** the client, nor the compiler/LLVM, to reuse/share the memory address of
2930
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` ->
31+
local numerical/character/byte/string/c-string slice literals. Otherwise an "ordinary" invocation of
32+
the API could trigger your designated signalling unintentionally.
33+
34+
That does work out of the box when the client passes a reference/slice defined as `static`: each
35+
`static` gets its own memory space (even with the default `release` optimizations). See a test
36+
[`src/lib.rs` ->
3337
`addresses_unique_between_statics()`](https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L72).
3438

35-
However, there is a problem (in `release` mode, and for some types even in `debug` mode). It affects
36-
("ordinary") `const` values/expressions that equal in value to any `static` (which may be your
37-
designated `static`). Rust/LLVM re-uses address of one such matching `static`' for references to any
38-
equal value(s) defined as `const`. See a test [`src/lib.rs` ->
39+
However, there is a problem (caused by de-duplication in `release`, and for some types even in `dev
40+
or `miri`). It affects ("ordinary") `const` values/expressions that equal in value to any `static`
41+
(whether it's a `static` variable, or a static literal), which may be your designated `static`.
42+
Rust/LLVM re-uses address of one such matching `static` for references to any equal value(s) defined
43+
as `const`. See a test [`src/lib.rs` ->
3944
`addresses_not_unique_between_const_and_static()`](https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L95).
40-
Such `const`, `static` or literal could be in 3rd party code, and private - not even exported (see
41-
[`cross-crate-demo-problem`](cross-crate-demo-problem))!
45+
Such `const`, `static` or literal could be in 3rd party, and even in private (not exported), code
46+
(see [`cross_crate_demo_bug`](cross_crate_demo_bug))!
4247

43-
Things get worse: `debug` builds don't have this consistent:
48+
Things get worse: `dev` builds don't have this consistent:
4449

45-
- For some types (`u8`, numeric primitive-based enums) `debug` builds don't reuse `static` addresses
50+
- For some types (`u8`, numeric primitive-based enums) `dev` builds don't reuse `static` addresses
4651
for references/slices to `const` values. But
47-
- For other types (`str`), `debug` builds do reuse them...
52+
- For other types (`str`), `dev` builds do reuse them...
4853

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"`).
54+
`MIRI` reuses `static` addresses even less (than `dev` does), but it still does reuse them sometimes
55+
- for example, between byte (`&CStr`) literals (`b"Hello"`) and equal string (`&str`) literals
56+
(technically, subslices: `"Hello"`).
5157

5258
Even worse so: `release` builds don't have this consistent. De-duplication across crates depends on
5359
"fat" link time optimization (LTO):
@@ -57,6 +63,15 @@ Even worse so: `release` builds don't have this consistent. De-duplication acros
5763
lto = "fat"
5864
```
5965

66+
For `dev` builds cross-crate de-duplication depends on "fat" link time optimization (LTO) AND
67+
`opt-level` being 2 or higher:
68+
69+
```toml
70+
[profile.dev]
71+
lto = "fat"
72+
opt-level = 2
73+
```
74+
6075
## Solution
6176

6277
`ndd:NonDeDuplicated` uses
@@ -79,7 +94,7 @@ See a test [`src/lib.rs` ->
7994
Use `ndd::NonDeDuplicated` to wrap your static data. Use it for (immutable) `static` variables only.
8095
Do **not** use it for locals or on heap. That is validated by implementation of
8196
[core::ops::Drop](https://doc.rust-lang.org/nightly/core/ops/trait.Drop.html), which `panic`-s in
82-
debug builds.
97+
`dev` builds.
8398

8499
See unit tests in [src/lib.rs](src/lib.rs).
85100

@@ -196,7 +211,8 @@ use an asterisk mask for the minor version, like `0.2.*`. But then you lose auto
196211

197212
Functionality of odd-numbered major (`-nightly`) versions is always subject to change.
198213

199-
The following extra functionality is available on `0.3.1-nightly`:
214+
The following extra functionality is available on `0.3.1-nightly`. You need `nightly` Rust toolchain
215+
(of course).
200216

201217
#### as_array_of_cells
202218

@@ -212,16 +228,18 @@ Similar to `as_array_of_cells`, `ndd::NonDeDuplicated` has function `as_slice_of
212228

213229
#### const Deref and From
214230

215-
With `nightly` Rust toolchain and use of `--ignore-rust-version` you can get
216231
[core::ops::Deref](https://doc.rust-lang.org/nightly/core/ops/trait.Deref.html) and
217-
[core::convert::From](https://doc.rust-lang.org/nightly/core/convert/trait.From.html) implemented as
218-
`const`. As of mid 2025, `const` traits are having high traction in Rust. Hopefully this will be
219-
stable not in years, but sooner.
232+
[core::convert::From](https://doc.rust-lang.org/nightly/core/convert/trait.From.html) are
233+
implemented as `const`. As of mid 2025, `const` traits are having high traction in Rust. Hopefully
234+
this will be stable not in years, but sooner.
235+
236+
These traits are **not** implemented in stable versions at all. Why? Because `ndd` types are
237+
intended for `static` variables, so non-`const` functions don't help us.
220238

221239
## Quality
222240

223241
Checks and tests are run by [GitHub Actions (CI)](.github/workflows/main.yml). All scripts run on
224-
Alpine Linux and are POSIX-compliant.
242+
Alpine Linux and are POSIX-compliant:
225243

226244
- `cargo clippy`
227245
- `cargo fmt --check`
@@ -232,13 +250,35 @@ Alpine Linux and are POSIX-compliant.
232250
- `rustup install nightly --profile minimal`
233251
- `rustup +nightly component add miri`
234252
- `cargo +nightly miri test`
235-
- `release`-only demonstration:
236-
- `cross-crate-demo-problem/bin/invocation_scripts/static_option_u8.sh`
237-
- `cross-crate-demo-problem/bin/invocation_scripts/static_str.sh`
238-
- `cross-crate-demo-problem/bin/invocation_scripts/literal_str.sh`
239-
- `cross-crate-demo-problem/bin-fat-lto/invocation_scripts/static_option_u8.sh`
240-
- `cross-crate-demo-problem/bin-fat-lto/invocation_scripts/static_str.sh`
241-
- `cross-crate-demo-problem/bin-fat-lto/invocation_scripts/literal_str.sh`
253+
- demonstration of the problem and fix:
254+
- standard optimization for `dev` and `release` builds: most do not get de-duplicated:
255+
- `cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh dev literal_str`
256+
- `cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh release literal_str`
257+
- `cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh dev const_str`
258+
- `cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh release const_str`
259+
- `cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh dev const_option_u8`
260+
- `cross_crate_demo_bug/bin_non_lto/not_deduplicated.sh release const_option_u8`
261+
- but, some types do get de-duplicated even in standard `dev` and `release`:
262+
- `cross_crate_demo_bug/bin_non_lto/deduplicated_out.sh dev const_bytes`
263+
- `cross_crate_demo_bug/bin_non_lto/deduplicated_out.sh release const_bytes`
264+
- `release` with Fat LTO (and `dev` with Fat LTO and `opt-level` set to `2`): deduplicated:
265+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev literal_str`
266+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev const_str`
267+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release literal_st`r
268+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release const_str`
269+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev const_option_u8`
270+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release const_option_u8`
271+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh dev const_bytes`
272+
- `cross_crate_demo_bug/bin_fat_lto/deduplicated_out.sh release const_bytes`
273+
- fix:
274+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh dev literal_str`
275+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh dev const_str`
276+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh release literal_st`r
277+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh release const_str`
278+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh dev const_option_u8`
279+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh release const_option_u8`
280+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh dev const_bytes`
281+
- `cross_crate_demo_fix/bin_fat_lto/not_deduplicated.sh release const_bytes`
242282
- validate the versioning convention:
243283
- [`pre-commit`](./pre-commit)
244284

cross-crate-demo-problem/README.md

Lines changed: 0 additions & 26 deletions
This file was deleted.

cross-crate-demo-problem/bin-fat-lto/invocation_scripts/literal_str.sh

Lines changed: 0 additions & 14 deletions
This file was deleted.

cross-crate-demo-problem/bin-fat-lto/invocation_scripts/static_option_u8.sh

Lines changed: 0 additions & 14 deletions
This file was deleted.

cross-crate-demo-problem/bin-fat-lto/src/bin/literal_str.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

cross-crate-demo-problem/bin-fat-lto/src/bin/static_option_u8.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)