Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,9 @@ fn add_sanitizer_libraries(
if sanitizer.contains(SanitizerSet::SAFESTACK) {
link_sanitizer_runtime(sess, flavor, linker, "safestack");
}
if sanitizer.contains(SanitizerSet::REALTIME) {
link_sanitizer_runtime(sess, flavor, linker, "rtsan");
}
}

fn link_sanitizer_runtime(
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ mod desc {
pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub(crate) const parse_oom_strategy: &str = "either `panic` or `abort`";
pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `realtime`, `safestack`, `shadow-call-stack` or `thread`";
pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub(crate) const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
Expand Down Expand Up @@ -1185,6 +1185,7 @@ pub mod parse {
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
"safestack" => SanitizerSet::SAFESTACK,
"realtime" => SanitizerSet::REALTIME,
_ => return false,
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,7 @@ bitflags::bitflags! {
const KERNELADDRESS = 1 << 9;
const SAFESTACK = 1 << 10;
const DATAFLOW = 1 << 11;
const REALTIME = 1 << 12;
}
}
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
Expand Down Expand Up @@ -1510,6 +1511,7 @@ impl SanitizerSet {
SanitizerSet::SHADOWCALLSTACK => "shadow-call-stack",
SanitizerSet::THREAD => "thread",
SanitizerSet::HWADDRESS => "hwaddress",
SanitizerSet::REALTIME => "realtime",
_ => return None,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ pub(crate) fn target() -> Target {
cpu: "apple-m1".into(),
max_atomic_width: Some(128),
// FIXME: The leak sanitizer currently fails the tests, see #88132.
supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD,
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::THREAD
| SanitizerSet::REALTIME,
supports_xray: true,
..opts
},
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".into(),
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::THREAD
| SanitizerSet::REALTIME,
..opts
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
features: "+neon,+fp-armv8,+apple-a7".into(),
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::THREAD,
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::THREAD
| SanitizerSet::REALTIME,
..opts
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pub(crate) fn target() -> Target {
| SanitizerSet::MEMORY
| SanitizerSet::MEMTAG
| SanitizerSet::THREAD
| SanitizerSet::HWADDRESS,
| SanitizerSet::HWADDRESS
| SanitizerSet::REALTIME,
supports_xray: true,
..base::linux_gnu::opts()
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pub(crate) fn target() -> Target {
supported_sanitizers: SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::THREAD,
| SanitizerSet::THREAD
| SanitizerSet::REALTIME,
supports_xray: true,
..opts
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ pub(crate) fn target() -> Target {
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::SAFESTACK
| SanitizerSet::THREAD;
| SanitizerSet::THREAD
| SanitizerSet::REALTIME;
base.supports_xray = true;

// When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using
Expand Down
18 changes: 10 additions & 8 deletions src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,21 +1257,21 @@ fn supported_sanitizers(
};

match &*target.triple {
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
"aarch64-apple-ios" => darwin_libs("ios", &["asan", "tsan"]),
"aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan"]),
"aarch64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan", "rtsan"]),
"aarch64-apple-ios" => darwin_libs("ios", &["asan", "tsan", "rtsan"]),
"aarch64-apple-ios-sim" => darwin_libs("iossim", &["asan", "tsan", "rtsan"]),
"aarch64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
"aarch64-unknown-fuchsia" => common_libs("fuchsia", "aarch64", &["asan"]),
"aarch64-unknown-linux-gnu" => {
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan", "rtsan"])
}
"aarch64-unknown-linux-ohos" => {
common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
}
"loongarch64-unknown-linux-gnu" | "loongarch64-unknown-linux-musl" => {
common_libs("linux", "loongarch64", &["asan", "lsan", "msan", "tsan"])
}
"x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
"x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan", "rtsan"]),
"x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
"x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be supported as well, we create an ios library when we build

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is x86_64 ios, I don't even know how that is used. Regular arm ios i already have added. But just making sure, if it is supported i will of course add it.

"x86_64-apple-ios-macabi" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
Expand All @@ -1281,9 +1281,11 @@ fn supported_sanitizers(
}
"x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
"x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
"x86_64-unknown-linux-gnu" => {
common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"])
}
"x86_64-unknown-linux-gnu" => common_libs(
"linux",
"x86_64",
&["asan", "dfsan", "lsan", "msan", "safestack", "tsan", "rtsan"],
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these were in in alpha order

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. "hwsan" in aarch linux gnu was at the end before. So not really ordered.

),
"x86_64-unknown-linux-musl" => {
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])
}
Expand Down
89 changes: 84 additions & 5 deletions src/doc/unstable-book/src/compiler-flags/sanitizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ This feature allows for use of one of following sanitizers:
AddressSanitizer, but based on partial hardware assistance.
* [LeakSanitizer](#leaksanitizer) a run-time memory leak detector.
* [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
* [RealtimeSanitizer](#realtimesanitizer) a detector of functions with
non-deterministic execution time in realtime contexts.
* [ThreadSanitizer](#threadsanitizer) a fast data race detector.

* Those that apart from testing, may be used in production:
Expand All @@ -43,11 +45,11 @@ This feature allows for use of one of following sanitizers:

To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
`-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
`-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
If you're working with other languages that are also instrumented with sanitizers,
you might need the `external-clangrt` flag. See the section on
[working with other languages](#working-with-other-languages).
`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=realtime`,
`-Zsanitizer=shadow-call-stack` or `-Zsanitizer=thread`. You might also need the
`--target` and `build-std` flags. If you're working with other languages that are also
instrumented with sanitizers, you might need the `external-clangrt` flag. See
the section on [working with other languages](#working-with-other-languages).

Example:
```shell
Expand Down Expand Up @@ -865,6 +867,81 @@ WARNING: ThreadSanitizer: data race (pid=10574)
Location is global 'example::A::h43ac149ddf992709' of size 8 at 0x5632dfe3d030 (example+0x000000bd9030)
```

# RealtimeSanitizer
RealtimeSanitizer detects non-deterministic execution time calls in realtime contexts.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"real-time contexts"

Usafe of RTSan is on a function-by-function basis. The sanitizer only inspects code that
is marked as being real-time sensitive. Currently this is done with the functions
`__rtsan_realtime_enter()` and `__rtsan_realtime_exit()`. Any function that is subject to
real-time contraints must call `__rtsan_realtime_enter()` at its entry point and
`__rtsan_realtime_exit()` at every exit point. To not miss any exit points, it is
recommended to use a guard object that exits the real-time context on drop

Controlling this sanitizer using attributes isn't yet supported in Rust. The
sanitizer exports the following functions that allow using it. These functions
are not stable. When the attributes are added to rust, using them over these
functions is recommended.

```rust
/// Each call to `__rtsan_realtime_enter()` must be matched with exactly one call to `__rtsan_realtime_exit()`.
/// The same goes for `__rtsan_disable()` with `__rtsan_enable()`
extern "C" {
/// Enters a realtime context. Can be nested. Must be matched with one later call to `__rtsan_realtime_exit()`.
pub fn __rtsan_realtime_enter();
/// Exits a realtime context. Must be matched to a preceding call to `__rtsan_realtime_enter()`.
/// After calling this the program could still be in a realtime context, as they can be nested.
pub fn __rtsan_realtime_exit();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible addition around these first two "Each call to enter must be matched with exactly one call to exit. Anything else leads to undefined behavior in the sanitizer."

I believe we have a similar note in our official docs if you want to check out that wording.

/// Disables the sanitizer. Must be matched to a later call to `__rtsan_enable()`.
/// Useful for situations where you know the systemcall you do has a deterministic execution time.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

system call

pub fn __rtsan_disable();
/// Enables the sanitizer again. Must be matched to a preceding call to `__rtsan_disable()`.
/// Useful when you know that a systemcall you do has a deterministic execution time in that situation.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

system call

pub fn __rtsan_enable();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"These two calls allow you to disable the sanitizer for a given scope. Useful for situations where you know some system call has deterministic execution time under the hood"

/// Must be called before any other sanitizer calls are made. You should place this at the entry point of
/// your program.
pub fn __rtsan_ensure_initialized();
/// To mark your function as one with a non-deterministic execution time, place this call as the first line
/// in the function. If rtsan hits this call while in a real-time context it will about in the same way that
/// calling an illegal system call does.
pub fn __rtsan_notify_blocking_call(blocking_function_name: *const core::ffi::c_char);
}
```

See the [Clang RealtimeSanitizer documentation][clang-rtsan] for more details.

## Example

```rust
fn main() {
unsafe {
__rtsan_ensure_initialized();
__rtsan_realtime_enter();
}
let vec = vec![0, 1, 2];
unsafe {
__rtsan_realtime_exit();
}
println!("alloc not detected")
}
```

```shell
==8670==ERROR: RealtimeSanitizer: unsafe-library-call
Intercepted call to real-time unsafe function `malloc` in real-time context!
#0 0x00010107b0d8 in malloc rtsan_interceptors_posix.cpp:792
#1 0x000100d94e70 in alloc::alloc::Global::alloc_impl::h9e1fc3206c868eea+0xa0 (realtime_vec:arm64+0x100000e70)
#2 0x000100d94d90 in alloc::alloc::exchange_malloc::hd45b5788339eb5c8+0x48 (realtime_vec:arm64+0x100000d90)
#3 0x000100d95020 in realtime_vec::main::hea6bd69b03eb9ca1+0x24 (realtime_vec:arm64+0x100001020)
#4 0x000100d94a28 in core::ops::function::FnOnce::call_once::h493b6cb9dd87d87c+0xc (realtime_vec:arm64+0x100000a28)
#5 0x000100d949b8 in std::sys::backtrace::__rust_begin_short_backtrace::hfcddb06c73c19eea+0x8 (realtime_vec:arm64+0x1000009b8)
#6 0x000100d9499c in std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h202288c05a2064f0+0xc (realtime_vec:arm64+0x10000099c)
#7 0x000100d9fa34 in std::rt::lang_start_internal::h6c763158a05ac05f+0x6c (realtime_vec:arm64+0x10000ba34)
#8 0x000100d94980 in std::rt::lang_start::h1c29cc56df0598b4+0x38 (realtime_vec:arm64+0x100000980)
#9 0x000100d95118 in main+0x20 (realtime_vec:arm64+0x100001118)
#10 0x000183a46b94 in start+0x17b8 (dyld:arm64+0xfffffffffff3ab94)

SUMMARY: RealtimeSanitizer: unsafe-library-call rtsan_interceptors_posix.cpp:792 in malloc
```

# Instrumentation of external dependencies and std

The sanitizers to varying degrees work correctly with partially instrumented
Expand Down Expand Up @@ -918,6 +995,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
* [MemorySanitizer in Clang][clang-msan]
* [MemTagSanitizer in LLVM][llvm-memtag]
* [ThreadSanitizer in Clang][clang-tsan]
* [RealtimeSanitizer in Clang][clang-rtsan]

[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
Expand All @@ -926,6 +1004,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
[clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
[clan-rtsan]: https://clang.llvm.org/docs/RealtimeSanitizer.html
[clang-safestack]: https://clang.llvm.org/docs/SafeStack.html
[clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html
[clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ pub enum Sanitizer {
ShadowCallStack,
Thread,
Hwaddress,
Realtime,
}

/// Configuration for compiletest
Expand Down
1 change: 1 addition & 0 deletions src/tools/compiletest/src/directive-list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
"needs-sanitizer-shadow-call-stack",
"needs-sanitizer-support",
"needs-sanitizer-thread",
"needs-sanitizer-realtime",
"needs-std-debug-assertions",
"needs-subprocess",
"needs-symlink",
Expand Down
7 changes: 7 additions & 0 deletions src/tools/compiletest/src/header/needs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ pub(super) fn handle_needs(
condition: cache.sanitizer_safestack,
ignore_reason: "ignored on targets without SafeStack support",
},
Need {
name: "needs-sanitizer-realtime",
condition: cache.sanitizer_realtime,
ignore_reason: "ignored on targets without RealtimeSanitizer support",
},
Need {
name: "needs-enzyme",
condition: config.has_enzyme,
Expand Down Expand Up @@ -327,6 +332,7 @@ pub(super) struct CachedNeedsConditions {
sanitizer_memtag: bool,
sanitizer_shadow_call_stack: bool,
sanitizer_safestack: bool,
sanitizer_realtime: bool,
xray: bool,
rust_lld: bool,
dlltool: bool,
Expand All @@ -353,6 +359,7 @@ impl CachedNeedsConditions {
sanitizer_memtag: sanitizers.contains(&Sanitizer::Memtag),
sanitizer_shadow_call_stack: sanitizers.contains(&Sanitizer::ShadowCallStack),
sanitizer_safestack: sanitizers.contains(&Sanitizer::Safestack),
sanitizer_realtime: sanitizers.contains(&Sanitizer::Realtime),
xray: config.target_cfg().xray,

// For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`),
Expand Down
28 changes: 28 additions & 0 deletions tests/ui/sanitizer/realtime_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//@ needs-sanitizer-support
//@ needs-sanitizer-realtime
//
//@ compile-flags: -Z sanitizer=realtime
//
//@ run-fail
//@ error-pattern: Intercepted call to real-time unsafe function `malloc` in real-time context!

extern "C" {
pub fn __rtsan_realtime_enter();
pub fn __rtsan_realtime_exit();
pub fn __rtsan_disable();
pub fn __rtsan_enable();
pub fn __rtsan_ensure_initialized();
pub fn __rtsan_notify_blocking_call(blocking_function_name: *const core::ffi::c_char);
}

fn main() {
unsafe {
__rtsan_ensure_initialized();
__rtsan_realtime_enter();
}
let vec = vec![0, 1, 2];
unsafe {
__rtsan_realtime_exit();
}
println!("alloc not detected")
}