From: "Max R. Carrara" <m.carrara@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox v2 02/10] proxmox-alloc: document undefined behavior regarding custom allocs
Date: Fri, 21 Aug 2026 16:02:26 +0200 [thread overview]
Message-ID: <20260821140238.615302-3-m.carrara@proxmox.com> (raw)
In-Reply-To: <20260821140238.615302-1-m.carrara@proxmox.com>
Add a new example at examples/ub.rs with tests that demonstrate
incorrect usage & undefined behavior of custom allocations.
Add a hint in the `aware_boxed` module's docs that such an example
exists in the crate.
Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
---
proxmox-alloc/Cargo.toml | 4 ++
proxmox-alloc/examples/ub.rs | 99 ++++++++++++++++++++++++++++++++
proxmox-alloc/src/aware_boxed.rs | 3 +
3 files changed, 106 insertions(+)
create mode 100644 proxmox-alloc/examples/ub.rs
diff --git a/proxmox-alloc/Cargo.toml b/proxmox-alloc/Cargo.toml
index 4eeeb787..b16496f6 100644
--- a/proxmox-alloc/Cargo.toml
+++ b/proxmox-alloc/Cargo.toml
@@ -11,6 +11,10 @@ repository.workspace = true
license.workspace = true
exclude.workspace = true
+[[example]]
+crate-type = ["staticlib"]
+name = "ub"
+
[dependencies]
[dev-dependencies]
diff --git a/proxmox-alloc/examples/ub.rs b/proxmox-alloc/examples/ub.rs
new file mode 100644
index 00000000..aa97b02b
--- /dev/null
+++ b/proxmox-alloc/examples/ub.rs
@@ -0,0 +1,99 @@
+//! This example contains various tests that demonstrate [undefined behavior].
+//! Needless to say, you should not use what's shown here in your own code.
+//!
+//! You can run this example's tests using the following command:
+//!
+//! ```text
+//! cargo test --package proxmox-alloc --example ub
+//! ```
+//!
+//! Alternatively, if you want to see what kinds of [undefined behavior] get
+//! caught by [Miri], use the following instead:
+//!
+//! ```text
+//! cargo +nightly miri nextest run --package proxmox-alloc --example ub
+//! ```
+//!
+//! Note that this requires [`cargo nextest`][nextest] to be installed on your
+//! nightly toolchain. This will guarantee that all tests are run, even if they
+//! fail (which they do when you use Miri).
+//!
+//! [Miri]: https://github.com/rust-lang/miri
+//! [nextest]: https://nexte.st/
+//! [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+
+#[cfg(test)]
+mod test {
+ use proxmox_alloc::LayoutAwareBox;
+
+ /// Rust does not and cannot track the alignment that was used for any given
+ /// allocation and will instead always resort to using the alignment of
+ /// whatever T it is currently dropping during deallocation.
+ ///
+ /// This gets caught by Miri.
+ #[test]
+ fn demo_ub_alignment_mismatch() {
+ let buf_len = 1024;
+ let align = 128;
+
+ let layout = std::alloc::Layout::from_size_align(buf_len, align).unwrap();
+
+ let thin_ptr = unsafe { std::alloc::alloc_zeroed(layout) };
+ let fat_ptr = std::ptr::slice_from_raw_parts_mut(thin_ptr, buf_len);
+ assert!(!fat_ptr.is_null());
+
+ let boxed = unsafe { Box::from_raw(fat_ptr) };
+
+ drop(boxed);
+ }
+
+ /// Rust requires that the size of a pointee is equal to the size of its
+ /// allocation.
+ ///
+ /// This gets caught by Miri.
+ #[test]
+ fn demo_ub_size_mismatch() {
+ type PayloadElement = [u8; 7];
+
+ #[repr(C, packed)]
+ struct PacketHeader {
+ src: [u8; 4],
+ dst: [u8; 4],
+ }
+
+ #[repr(C, packed)]
+ struct Packet {
+ header: PacketHeader,
+ payload: [PayloadElement],
+ }
+
+ let alloc_size = 1024;
+ let align = 128;
+
+ let header_size = size_of::<PacketHeader>();
+ let elem_size = size_of::<PayloadElement>();
+
+ let payload_len = (alloc_size - header_size) / elem_size;
+
+ let layout = std::alloc::Layout::from_size_align(alloc_size, align).expect("infallible");
+
+ // SAFETY: layout's size is not 0.
+ let thin_ptr = unsafe { std::alloc::alloc_zeroed(layout) };
+ assert!(!thin_ptr.is_null(), "thin_ptr is null -- allocation failed");
+
+ let fat_ptr = std::ptr::slice_from_raw_parts_mut(thin_ptr, payload_len) as *mut Packet;
+
+ // In this case you can actually check whether the pointee's size
+ // differs from the allocation's size:
+ let pointee_size = unsafe { size_of_val(&mut *fat_ptr) };
+ assert_ne!(pointee_size, alloc_size);
+
+ // SAFETY: fat ptr is not aliased or null, is valid for reads and
+ // writes, and its pointee was zero-initialized. Its length is within
+ // the bounds of its allocation.
+ // WARNING: This isn't actually safe, as the example implies.
+ let aware_boxed = unsafe { LayoutAwareBox::from_raw_parts(fat_ptr, layout) };
+
+ drop(aware_boxed);
+ }
+}
diff --git a/proxmox-alloc/src/aware_boxed.rs b/proxmox-alloc/src/aware_boxed.rs
index 4ec3811e..ce6005ac 100644
--- a/proxmox-alloc/src/aware_boxed.rs
+++ b/proxmox-alloc/src/aware_boxed.rs
@@ -49,6 +49,9 @@
//! Therefore, one must always track the [`Layout`] that was used for "exotic"
//! kinds of allocations, which [`LayoutAwareBox`] will do for you.
//!
+//! *Hint: This crate's source code contains extra examples that you can compile
+//! and run with [Miri] if you want to see the UB in action.*
+//!
//! # Examples
//!
//! Move a value from the stack on the heap, using a specific alignment for the
--
2.47.3
next prev parent reply other threads:[~2026-08-21 14:02 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-21 14:02 [PATCH proxmox{,-backup} v2 00/10] Fix Undefined Behavior in Tape Block Header Deallocation Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox v2 01/10] proxmox-alloc: introduce proxmox-alloc with `LayoutAwareBox<T>` type Max R. Carrara
2026-08-21 14:02 ` Max R. Carrara [this message]
2026-08-21 14:02 ` [PATCH proxmox-backup v2 03/10] tape: move tape block structs into separate file module Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 04/10] tape: rename `BlockHeader` and `BlockHeaderFlags` Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 05/10] tape: blocked_{reader,writer}: rename `buffer` to `tape_block` Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 06/10] tape: tape block: represent tape block header with its own struct Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 07/10] tape: tape block: make `payload` field private Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 08/10] tape: blocked_{reader,writer}: remove haphazard `unsafe` blocks Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 09/10] tape: tape block: fix undefined behavior on tape block deallocation Max R. Carrara
2026-08-21 14:02 ` [PATCH proxmox-backup v2 10/10] tape: sgutils2: fix undefined behavior in dealloc of buffer Max R. Carrara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260821140238.615302-3-m.carrara@proxmox.com \
--to=m.carrara@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.