Skip to content

Commit 8741303

Browse files
committed
TB: document TB changes in README
1 parent 8bbb040 commit 8741303

File tree

4 files changed

+218
-118
lines changed

4 files changed

+218
-118
lines changed

src/tools/miri/README.md

Lines changed: 13 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ for example:
1515
or an invalid enum discriminant)
1616
* **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing
1717
for reference types
18+
* **Experimental**: Violations of the Tree Borrows aliasing rules, as an optional
19+
alternative to [Stacked Borrows]
1820
* **Experimental**: Data races
1921

2022
On top of that, Miri will also tell you about memory leaks: when there is memory
@@ -357,9 +359,11 @@ to Miri failing to detect cases of undefined behavior in a program.
357359
* `-Zmiri-disable-data-race-detector` disables checking for data races. Using
358360
this flag is **unsound**. This implies `-Zmiri-disable-weak-memory-emulation`.
359361
* `-Zmiri-disable-stacked-borrows` disables checking the experimental
360-
[Stacked Borrows] aliasing rules. This can make Miri run faster, but it also
361-
means no aliasing violations will be detected. Using this flag is **unsound**
362-
(but the affected soundness rules are experimental).
362+
aliasing rules to track borrows ([Stacked Borrows] and Tree Borrows).
363+
This can make Miri run faster, but it also means no aliasing violations will
364+
be detected. Using this flag is **unsound** (but the affected soundness rules
365+
are experimental). Later flags take precedence: borrow tracking can be reactivated
366+
by `-Zmiri-tree-borrows`.
363367
* `-Zmiri-disable-validation` disables enforcing validity invariants, which are
364368
enforced by default. This is mostly useful to focus on other failures (such
365369
as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs
@@ -421,6 +425,9 @@ to Miri failing to detect cases of undefined behavior in a program.
421425
* `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated
422426
value from a load. This can help diagnose problems that disappear under
423427
`-Zmiri-disable-weak-memory-emulation`.
428+
* `-Zmiri-tree-borrows` replaces [Stacked Borrows] with the Tree Borrows rules.
429+
The soundness rules are already experimental without this flag, but even more
430+
so with this flag.
424431
* `-Zmiri-force-page-size=<num>` overrides the default page size for an architecture, in multiples of 1k.
425432
`4` is default for most targets. This value should always be a power of 2 and nonzero.
426433

@@ -435,7 +442,7 @@ Some native rustc `-Z` flags are also very relevant for Miri:
435442
functions. This is needed so that Miri can execute such functions, so Miri
436443
sets this flag per default.
437444
* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri
438-
enables this per default because it is needed for [Stacked Borrows].
445+
enables this per default because it is needed for [Stacked Borrows] and Tree Borrows.
439446

440447
Moreover, Miri recognizes some environment variables:
441448

@@ -501,120 +508,8 @@ binaries, and as such worth documenting:
501508
## Miri `extern` functions
502509

503510
Miri provides some `extern` functions that programs can import to access
504-
Miri-specific functionality:
505-
506-
```rust
507-
#[cfg(miri)]
508-
extern "Rust" {
509-
/// Miri-provided extern function to mark the block `ptr` points to as a "root"
510-
/// for some static memory. This memory and everything reachable by it is not
511-
/// considered leaking even if it still exists when the program terminates.
512-
///
513-
/// `ptr` has to point to the beginning of an allocated block.
514-
fn miri_static_root(ptr: *const u8);
515-
516-
// Miri-provided extern function to get the amount of frames in the current backtrace.
517-
// The `flags` argument must be `0`.
518-
fn miri_backtrace_size(flags: u64) -> usize;
519-
520-
/// Miri-provided extern function to obtain a backtrace of the current call stack.
521-
/// This writes a slice of pointers into `buf` - each pointer is an opaque value
522-
/// that is only useful when passed to `miri_resolve_frame`.
523-
/// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space.
524-
/// The `flags` argument must be `1`.
525-
fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
526-
527-
/// Miri-provided extern function to resolve a frame pointer obtained
528-
/// from `miri_get_backtrace`. The `flags` argument must be `1`,
529-
/// and `MiriFrame` should be declared as follows:
530-
///
531-
/// ```rust
532-
/// #[repr(C)]
533-
/// struct MiriFrame {
534-
/// // The size of the name of the function being executed, encoded in UTF-8
535-
/// name_len: usize,
536-
/// // The size of filename of the function being executed, encoded in UTF-8
537-
/// filename_len: usize,
538-
/// // The line number currently being executed in `filename`, starting from '1'.
539-
/// lineno: u32,
540-
/// // The column number currently being executed in `filename`, starting from '1'.
541-
/// colno: u32,
542-
/// // The function pointer to the function currently being executed.
543-
/// // This can be compared against function pointers obtained by
544-
/// // casting a function (e.g. `my_fn as *mut ()`)
545-
/// fn_ptr: *mut ()
546-
/// }
547-
/// ```
548-
///
549-
/// The fields must be declared in exactly the same order as they appear in `MiriFrame` above.
550-
/// This function can be called on any thread (not just the one which obtained `frame`).
551-
fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame;
552-
553-
/// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`.
554-
/// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`.
555-
/// The flags argument must be `0`.
556-
fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8);
557-
558-
/// Miri-provided extern function to begin unwinding with the given payload.
559-
///
560-
/// This is internal and unstable and should not be used; we give it here
561-
/// just to be complete.
562-
fn miri_start_panic(payload: *mut u8) -> !;
563-
564-
/// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer
565-
/// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort.
566-
///
567-
/// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because
568-
/// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation.
569-
/// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so
570-
/// inherits all of its instability.
571-
fn miri_get_alloc_id(ptr: *const ()) -> u64;
572-
573-
/// Miri-provided extern function to print (from the interpreter, not the program) the contents of all
574-
/// borrow stacks in an allocation. The leftmost tag is the bottom of the stack.
575-
/// The format of what this emits is unstable and may change at any time. In particular, users should be
576-
/// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of
577-
/// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
578-
///
579-
/// This function is extremely unstable. At any time the format of its output may change, its signature may
580-
/// change, or it may be removed entirely.
581-
fn miri_print_borrow_stacks(alloc_id: u64);
582-
583-
/// Miri-provided extern function to print (from the interpreter, not the
584-
/// program) the contents of a section of program memory, as bytes. Bytes
585-
/// written using this function will emerge from the interpreter's stdout.
586-
fn miri_write_to_stdout(bytes: &[u8]);
587-
588-
/// Miri-provided extern function to print (from the interpreter, not the
589-
/// program) the contents of a section of program memory, as bytes. Bytes
590-
/// written using this function will emerge from the interpreter's stderr.
591-
fn miri_write_to_stderr(bytes: &[u8]);
592-
593-
/// Miri-provided extern function to allocate memory from the interpreter.
594-
///
595-
/// This is useful when no fundamental way of allocating memory is
596-
/// available, e.g. when using `no_std` + `alloc`.
597-
fn miri_alloc(size: usize, align: usize) -> *mut u8;
598-
599-
/// Miri-provided extern function to deallocate memory.
600-
fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
601-
602-
/// Convert a path from the host Miri runs on to the target Miri interprets.
603-
/// Performs conversion of path separators as needed.
604-
///
605-
/// Usually Miri performs this kind of conversion automatically. However, manual conversion
606-
/// might be necessary when reading an environment variable that was set on the host
607-
/// (such as TMPDIR) and using it as a target path.
608-
///
609-
/// Only works with isolation disabled.
610-
///
611-
/// `in` must point to a null-terminated string, and will be read as the input host path.
612-
/// `out` must point to at least `out_size` many bytes, and the result will be stored there
613-
/// with a null terminator.
614-
/// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
615-
fn miri_host_to_target_path(path: *const std::ffi::c_char, out: *mut std::ffi::c_char, out_size: usize) -> usize;
616-
}
617-
```
511+
Miri-specific functionality. They are declared in
512+
[/tests/utils/miri\_extern.rs](/tests/utils/miri_extern.rs).
618513

619514
## Contributing and getting help
620515

src/tools/miri/tests/utils/macros.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#![allow(unused_macros)]
2+
#![allow(unused_macro_rules)]
3+
#![allow(unused_imports)]
4+
5+
/// `alloc_id!(ptr)`: obtain the allocation id from a pointer.
6+
///
7+
/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`.
8+
///
9+
/// The id obtained can be passed directly to `print_state!`.
10+
macro_rules! alloc_id {
11+
($ptr:expr) => {
12+
crate::utils::miri_extern::miri_get_alloc_id($ptr as *const u8 as *const ())
13+
};
14+
}
15+
16+
/// `print_state!(alloc_id, show_unnamed)`: print the internal state of the borrow
17+
/// tracker (stack or tree).
18+
///
19+
/// `alloc_id` should be obtained from `alloc_id!`.
20+
///
21+
/// `show_unnamed` is an optional boolean that determines if Tree Borrows displays
22+
/// tags that have not been given a name. Defaults to `false`.
23+
macro_rules! print_state {
24+
($alloc_id:expr) => {
25+
crate::utils::macros::print_state!($alloc_id, false);
26+
};
27+
($alloc_id:expr, $show:expr) => {
28+
crate::utils::miri_extern::miri_print_borrow_state($alloc_id, $show);
29+
};
30+
}
31+
32+
/// `name!(ptr => nth_parent, name)`: associate `name` to the `nth_parent` of `ptr`.
33+
///
34+
/// `ptr` should be any pointer or reference that can be converted with `_ as *const u8`.
35+
///
36+
/// `nth_parent` is an optional `u8` that defaults to 0. The corresponding ancestor
37+
/// of the tag of `ptr` will be searched: 0 for `ptr` itself, 1 for the direct parent
38+
/// of `ptr`, 2 for the grandparent, etc. If `nth_parent` is not specified,
39+
/// then `=>` should also not be included.
40+
///
41+
/// `name` is an optional string that will be used as the name. Defaults to
42+
/// `stringify!($ptr)` the name of `ptr` in the source code.
43+
macro_rules! name {
44+
($ptr:expr, $name:expr) => {
45+
crate::utils::macros::name!($ptr => 0, $name);
46+
};
47+
($ptr:expr) => {
48+
crate::utils::macros::name!($ptr => 0, stringify!($ptr));
49+
};
50+
($ptr:expr => $nb:expr) => {
51+
crate::utils::macros::name!($ptr => $nb, stringify!($ptr));
52+
};
53+
($ptr:expr => $nb:expr, $name:expr) => {
54+
let name = $name.as_bytes();
55+
crate::utils::miri_extern::miri_pointer_name($ptr as *const u8 as *const (), $nb, name);
56+
};
57+
}
58+
59+
pub(crate) use alloc_id;
60+
pub(crate) use name;
61+
pub(crate) use print_state;
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#![allow(dead_code)]
2+
3+
#[repr(C)]
4+
/// Layout of the return value of `miri_resolve_frame`,
5+
/// with fields in the exact same order.
6+
pub struct MiriFrame {
7+
// The size of the name of the function being executed, encoded in UTF-8
8+
pub name_len: usize,
9+
// The size of filename of the function being executed, encoded in UTF-8
10+
pub filename_len: usize,
11+
// The line number currently being executed in `filename`, starting from '1'.
12+
pub lineno: u32,
13+
// The column number currently being executed in `filename`, starting from '1'.
14+
pub colno: u32,
15+
// The function pointer to the function currently being executed.
16+
// This can be compared against function pointers obtained by
17+
// casting a function (e.g. `my_fn as *mut ()`)
18+
pub fn_ptr: *mut (),
19+
}
20+
21+
#[cfg(miri)]
22+
extern "Rust" {
23+
/// Miri-provided extern function to mark the block `ptr` points to as a "root"
24+
/// for some static memory. This memory and everything reachable by it is not
25+
/// considered leaking even if it still exists when the program terminates.
26+
///
27+
/// `ptr` has to point to the beginning of an allocated block.
28+
pub fn miri_static_root(ptr: *const u8);
29+
30+
// Miri-provided extern function to get the amount of frames in the current backtrace.
31+
// The `flags` argument must be `0`.
32+
pub fn miri_backtrace_size(flags: u64) -> usize;
33+
34+
/// Miri-provided extern function to obtain a backtrace of the current call stack.
35+
/// This writes a slice of pointers into `buf` - each pointer is an opaque value
36+
/// that is only useful when passed to `miri_resolve_frame`.
37+
/// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space.
38+
/// The `flags` argument must be `1`.
39+
pub fn miri_get_backtrace(flags: u64, buf: *mut *mut ());
40+
41+
/// Miri-provided extern function to resolve a frame pointer obtained
42+
/// from `miri_get_backtrace`. The `flags` argument must be `1`.
43+
///
44+
/// This function can be called on any thread (not just the one which obtained `frame`).
45+
pub fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame;
46+
47+
/// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`.
48+
/// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`.
49+
/// The flags argument must be `0`.
50+
pub fn miri_resolve_frame_names(
51+
ptr: *mut (),
52+
flags: u64,
53+
name_buf: *mut u8,
54+
filename_buf: *mut u8,
55+
);
56+
57+
/// Miri-provided extern function to begin unwinding with the given payload.
58+
///
59+
/// This is internal and unstable and should not be used; we give it here
60+
/// just to be complete.
61+
pub fn miri_start_panic(payload: *mut u8) -> !;
62+
63+
/// Miri-provided extern function to get the internal unique identifier for the allocation that a pointer
64+
/// points to. If this pointer is invalid (not pointing to an allocation), interpretation will abort.
65+
///
66+
/// This is only useful as an input to `miri_print_borrow_stacks`, and it is a separate call because
67+
/// getting a pointer to an allocation at runtime can change the borrow stacks in the allocation.
68+
/// This function should be considered unstable. It exists only to support `miri_print_borrow_stacks` and so
69+
/// inherits all of its instability.
70+
pub fn miri_get_alloc_id(ptr: *const ()) -> u64;
71+
72+
/// Miri-provided extern function to print (from the interpreter, not the program) the contents of all
73+
/// borrows in an allocation.
74+
///
75+
/// If Stacked Borrows is running, this prints all the stacks. The leftmost tag is the bottom of the stack.
76+
///
77+
/// If Tree borrows is running, this prints on the left the permissions of each tag on each range,
78+
/// an on the right the tree structure of the tags. If some tags were named via `miri_pointer_name`,
79+
/// their names appear here.
80+
///
81+
/// If additionally `show_unnamed` is `false` then tags that did *not* receive a name will be hidden.
82+
/// Ensure that either the important tags have been named, or `show_unnamed = true`.
83+
/// Note: as Stacked Borrows does not have tag names at all, `show_unnamed` is ignored and all tags are shown.
84+
/// In general, unless you strongly want some tags to be hidden (as is the case in `tree-borrows` tests),
85+
/// `show_unnamed = true` should be the default.
86+
///
87+
/// The format of what this emits is unstable and may change at any time. In particular, users should be
88+
/// aware that Miri will periodically attempt to garbage collect the contents of all stacks. Callers of
89+
/// this function may wish to pass `-Zmiri-tag-gc=0` to disable the GC.
90+
///
91+
/// This function is extremely unstable. At any time the format of its output may change, its signature may
92+
/// change, or it may be removed entirely.
93+
pub fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool);
94+
95+
/// Miri-provided extern function to associate a name to the nth parent of a tag.
96+
/// Typically the name given would be the name of the program variable that holds the pointer.
97+
/// Unreachable tags can still be named by using nonzero `nth_parent` and a child tag.
98+
///
99+
/// This function does nothing under Stacked Borrows, since Stacked Borrows's implementation
100+
/// of `miri_print_borrow_state` does not show the names.
101+
///
102+
/// Under Tree Borrows, the names also appear in error messages.
103+
pub fn miri_pointer_name(ptr: *const (), nth_parent: u8, name: &[u8]);
104+
105+
/// Miri-provided extern function to print (from the interpreter, not the
106+
/// program) the contents of a section of program memory, as bytes. Bytes
107+
/// written using this function will emerge from the interpreter's stdout.
108+
pub fn miri_write_to_stdout(bytes: &[u8]);
109+
110+
/// Miri-provided extern function to print (from the interpreter, not the
111+
/// program) the contents of a section of program memory, as bytes. Bytes
112+
/// written using this function will emerge from the interpreter's stderr.
113+
pub fn miri_write_to_stderr(bytes: &[u8]);
114+
115+
/// Miri-provided extern function to allocate memory from the interpreter.
116+
///
117+
/// This is useful when no fundamental way of allocating memory is
118+
/// available, e.g. when using `no_std` + `alloc`.
119+
pub fn miri_alloc(size: usize, align: usize) -> *mut u8;
120+
121+
/// Miri-provided extern function to deallocate memory.
122+
pub fn miri_dealloc(ptr: *mut u8, size: usize, align: usize);
123+
124+
/// Convert a path from the host Miri runs on to the target Miri interprets.
125+
/// Performs conversion of path separators as needed.
126+
///
127+
/// Usually Miri performs this kind of conversion automatically. However, manual conversion
128+
/// might be necessary when reading an environment variable that was set on the host
129+
/// (such as TMPDIR) and using it as a target path.
130+
///
131+
/// Only works with isolation disabled.
132+
///
133+
/// `in` must point to a null-terminated string, and will be read as the input host path.
134+
/// `out` must point to at least `out_size` many bytes, and the result will be stored there
135+
/// with a null terminator.
136+
/// Returns 0 if the `out` buffer was large enough, and the required size otherwise.
137+
pub fn miri_host_to_target_path(
138+
path: *const std::ffi::c_char,
139+
out: *mut std::ffi::c_char,
140+
out_size: usize,
141+
) -> usize;
142+
}

src/tools/miri/tests/utils/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod macros;
2+
pub mod miri_extern;

0 commit comments

Comments
 (0)