Skip to content

Commit 1e71c8c

Browse files
Docs and Tests
1 parent b9b7343 commit 1e71c8c

File tree

2 files changed

+76
-61
lines changed

2 files changed

+76
-61
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ That does work out of the box when the client passes a reference/slice defined a
3737
`addresses_unique_between_statics()`](https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L72).
3838

3939
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`
40+
or `miri). It affects ("ordinary") `const` values/expressions that equal in value to any `static`
4141
(whether it's a `static` variable, or a static literal), which may be your designated `static`.
4242
Rust/LLVM re-uses address of one such matching `static` for references to any equal value(s) defined
4343
as `const`. See a test [`src/lib.rs` ->
4444
`addresses_not_unique_between_const_and_static()`](https://github.com/peter-lyons-kehl/ndd/blob/26d743d9b7bbaf41155e00174f8827efca5d5f32/src/lib.rs#L95).
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))!
45+
Such `const`, `static` or literal could be in 3rd party code, even private. (See
46+
[`cross_crate_demo_bug/`](https://github.com/peter-lyons-kehl/ndd/tree/main/cross_crate_demo_bug))!
4747

4848
Things get worse: `dev` builds don't have this consistent:
4949

src/lib.rs

Lines changed: 73 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -216,27 +216,27 @@ impl<OWN: Any + Send + Sync, TO: Any + Send + Sync + ?Sized> Drop
216216
}
217217

218218
#[cfg(test)]
219-
mod tests {
220-
use super::*;
221-
use core::ptr;
222-
223-
const fn expect_sync_ref<T: Sync>() {}
224-
const _: () = expect_sync_ref::<NonDeDuplicated<u8>>();
219+
mod tests_shared {
220+
pub const STR_CONST_FROM_BYTE_ARRAY_HI: &str = {
221+
match str::from_utf8(&[b'H', b'i']) {
222+
Ok(s) => s,
223+
Err(_) => unreachable!(),
224+
}
225+
};
225226

226-
#[test]
227-
#[cfg(any(debug_assertions, miri))]
228-
#[should_panic(
229-
expected = "Do not use for local variables, const, or on heap. Use for static variables only."
230-
)]
231-
fn drop_panics_in_debug_and_miri() {
232-
let _: NonDeDuplicated<()> = NonDeDuplicated::new(());
233-
}
227+
pub const STR_CONST_FROM_BYTE_STRING_HELLO: &str = {
228+
match str::from_utf8(b"Hello") {
229+
Ok(s) => s,
230+
Err(_) => unreachable!(),
231+
}
232+
};
233+
}
234234

235-
#[cfg(not(any(debug_assertions, miri)))]
236-
#[test]
237-
fn drop_silent_in_release() {
238-
let _: NonDeDuplicated<()> = NonDeDuplicated::new(());
239-
}
235+
/// These tests don't actually test `ndd`, but they test the behavior **without** `ndd`.
236+
#[cfg(test)]
237+
mod tests_behavior_without_ndd {
238+
use crate::tests_shared::{STR_CONST_FROM_BYTE_ARRAY_HI, STR_CONST_FROM_BYTE_STRING_HELLO};
239+
use core::ptr;
240240

241241
const U8_CONST: u8 = b'A';
242242
static U8_STATIC_1: u8 = b'A';
@@ -262,22 +262,6 @@ mod tests {
262262
assert!(!ptr::eq(&U8_STATIC_1, &U8_CONST));
263263
}
264264

265-
static U8_NDD: NonDeDuplicated<u8> = NonDeDuplicated::new(U8_CONST);
266-
static U8_NDD_REF: &u8 = U8_NDD.get();
267-
#[test]
268-
fn u8_global_const_and_ndd() {
269-
assert!(!ptr::eq(U8_NDD_REF, &U8_CONST));
270-
assert!(!ptr::eq(U8_NDD_REF, &U8_STATIC_1));
271-
assert!(!ptr::eq(U8_NDD_REF, &U8_STATIC_2));
272-
}
273-
274-
const STR_CONST_FROM_BYTE_ARRAY_HI: &str = {
275-
match str::from_utf8(&[b'H', b'i']) {
276-
Ok(s) => s,
277-
Err(_) => unreachable!(),
278-
}
279-
};
280-
281265
#[cfg(not(miri))]
282266
#[test]
283267
#[should_panic(expected = "assertion failed: !ptr::eq(STR_CONST_FROM_BYTE_ARRAY_HI, \"Hi\")")]
@@ -290,27 +274,12 @@ mod tests {
290274
assert!(!ptr::eq(STR_CONST_FROM_BYTE_ARRAY_HI, "Hi"));
291275
}
292276

293-
const STR_CONST_FROM_BYTE_STRING_HELLO: &str = {
294-
match str::from_utf8(b"Hello") {
295-
Ok(s) => s,
296-
Err(_) => unreachable!(),
297-
}
298-
};
299-
300277
/// This is the same for all three: release, debug AND miri!
301278
#[test]
302279
fn str_global_byte_by_byte_const_and_local_static() {
303280
assert!(ptr::eq(STR_CONST_FROM_BYTE_STRING_HELLO, "Hello"));
304281
}
305282

306-
static STR_NDD_HI: NonDeDuplicatedStr<5> = NonDeDuplicatedStr::new("Hello");
307-
#[test]
308-
fn str_ndd_hi() {
309-
assert!(!ptr::eq(STR_NDD_HI.get(), "Hi"));
310-
assert!(!ptr::eq(STR_NDD_HI.get(), STR_CONST_FROM_BYTE_ARRAY_HI));
311-
assert!(!ptr::eq(STR_NDD_HI.get(), STR_CONST_FROM_BYTE_STRING_HELLO));
312-
}
313-
314283
static STR_STATIC: &str = "Ciao";
315284

316285
#[cfg(not(miri))]
@@ -330,14 +299,6 @@ mod tests {
330299
assert!(!ptr::eq(local_const_based_slice, STR_STATIC));
331300
}
332301

333-
static STR_NDD_CIAO: NonDeDuplicatedStr<4> = NonDeDuplicatedStr::new("Ciao");
334-
#[test]
335-
fn str_local_const_based_and_str_ndd() {
336-
const LOCAL_CONST_ARR: [u8; 4] = [b'C', b'i', b'a', b'o'];
337-
let local_const_based_slice: &str = str::from_utf8(&LOCAL_CONST_ARR).unwrap();
338-
assert!(!ptr::eq(local_const_based_slice, STR_NDD_CIAO.get()));
339-
}
340-
341302
mod cross_module_static {
342303
pub static STATIC_OPT_U8_A: Option<u8> = Some(b'A');
343304
}
@@ -366,3 +327,57 @@ mod tests {
366327
}
367328
}
368329
}
330+
331+
#[cfg(test)]
332+
mod tests_behavior_with_ndd {
333+
use super::*;
334+
use crate::tests_shared::{STR_CONST_FROM_BYTE_ARRAY_HI, STR_CONST_FROM_BYTE_STRING_HELLO};
335+
use core::ptr;
336+
337+
const U8_CONST: u8 = b'A';
338+
static U8_STATIC_1: u8 = b'A';
339+
static U8_STATIC_2: u8 = b'A';
340+
341+
const fn expect_sync_ref<T: Sync>() {}
342+
const _: () = expect_sync_ref::<NonDeDuplicated<u8>>();
343+
344+
static U8_NDD: NonDeDuplicated<u8> = NonDeDuplicated::new(U8_CONST);
345+
static U8_NDD_REF: &u8 = U8_NDD.get();
346+
#[test]
347+
fn u8_global_const_and_ndd() {
348+
assert!(!ptr::eq(U8_NDD_REF, &U8_CONST));
349+
assert!(!ptr::eq(U8_NDD_REF, &U8_STATIC_1));
350+
assert!(!ptr::eq(U8_NDD_REF, &U8_STATIC_2));
351+
}
352+
353+
static STR_NDD_HI: NonDeDuplicatedStr<5> = NonDeDuplicatedStr::new("Hello");
354+
#[test]
355+
fn str_ndd_hi() {
356+
assert!(!ptr::eq(STR_NDD_HI.get(), "Hi"));
357+
assert!(!ptr::eq(STR_NDD_HI.get(), STR_CONST_FROM_BYTE_ARRAY_HI));
358+
assert!(!ptr::eq(STR_NDD_HI.get(), STR_CONST_FROM_BYTE_STRING_HELLO));
359+
}
360+
361+
static STR_NDD_CIAO: NonDeDuplicatedStr<4> = NonDeDuplicatedStr::new("Ciao");
362+
#[test]
363+
fn str_local_const_based_and_str_ndd() {
364+
const LOCAL_CONST_ARR: [u8; 4] = [b'C', b'i', b'a', b'o'];
365+
let local_const_based_slice: &str = str::from_utf8(&LOCAL_CONST_ARR).unwrap();
366+
assert!(!ptr::eq(local_const_based_slice, STR_NDD_CIAO.get()));
367+
}
368+
369+
#[test]
370+
#[cfg(any(debug_assertions, miri))]
371+
#[should_panic(
372+
expected = "Do not use for local variables, const, or on heap. Use for static variables only."
373+
)]
374+
fn drop_panics_in_debug_and_miri() {
375+
let _: NonDeDuplicated<()> = NonDeDuplicated::new(());
376+
}
377+
378+
#[cfg(not(any(debug_assertions, miri)))]
379+
#[test]
380+
fn drop_silent_in_release() {
381+
let _: NonDeDuplicated<()> = NonDeDuplicated::new(());
382+
}
383+
}

0 commit comments

Comments
 (0)