Skip to content

Commit 7504415

Browse files
committed
Propose a 2025H2 goal for comprehensive niche checks
1 parent 0d0f95d commit 7504415

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Comprehensive niche checks for Rust
2+
3+
| Metadata | |
4+
| :------------------| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
5+
| Point of contact | [@1c3t3a](https://github.com/1c3t3a) |
6+
| Teams | opsem, compiler |
7+
| Status | Proposed |
8+
| Task owners | [@1c3t3a](https://github.com/1c3t3a, [@jakos-sec](https://github.com/jakos-sec) |
9+
| Tracking issue | [rust-lang/rust-project-goals#262] |
10+
| Zulip channel | https://rust-lang.zulipchat.com/#narrow/channel/435869-project-goals/topic/Null.20and.20enum-discriminant.20runtime.20checks.20in.20.28goals.23262.29/with/508256920 |
11+
12+
## Summary
13+
14+
Add runtime checks to rustc that check for valid niche values. This is an
15+
extension of a [previous project goal](https://rust-lang.github.io/rust-project-goals/2025h1/null-enum-discriminant-debug-checks.html)
16+
that added null pointer and enum checks and generally works towards checking for
17+
Undefined behavior at runtime (in debug builds / behind compiler flags).
18+
19+
The check should fire for invalid values that are already created by inserting
20+
a check at load-time / on function entry.
21+
22+
## Motivation
23+
24+
Rust has a few types that specify "invalid values" for themselves, which means
25+
values that can never be occupied by an instance of this type. An example of
26+
that would be `0` for `std::num::NonZeroUsize`, or `null` for
27+
`std::ptr::NonNull`. These so called *niches* are used for optimizations, for
28+
example when being used together with `Option`, where `Option<NonNull<T>>` has
29+
the same size as `*mut T`.
30+
31+
In safe Rust it is never possible to construct such values, but that is
32+
different for unsafe Rust or FFI. E.g. with Rusts growing interop with C (e.g.
33+
in the Linux Kernel) and C++ it makes sense to expose such types over the
34+
language boundary. That can make for situations where a valid C or C++ value
35+
becomes an invalid Rust value.
36+
37+
### The status quo
38+
39+
While [Miri](google.com/search?q=miri+rust&oq=miri+rust&gs_lcrp=EgZjaHJvbWUqDQgAEAAYkQIYgAQYigUyDQgAEAAYkQIYgAQYigUyCAgBEAAYFhgeMggIAhCAMQABgWGB4yBggEEEUYPDIGCAUQRRg8MgYIBhBFGDwyBggHEEUYQNIBCDI1MzJqMGo3qAIAsAIA&sourceid=chrome&ie=UTF-8)
40+
exists and does a great job at catching various types of UB in unsafe Rust code,
41+
it has the downside of only working on pure Rust code. Extern functions can not
42+
be called and a mixed language binary is unable to be executed in Miri.
43+
44+
We already added support for checking enum discriminants which is somewhat related,
45+
but this does not cover general niches.
46+
47+
At the same time we struggle with when to inject the enum discriminant check. If
48+
we e.g. inject the check for every use of an invalid enum, we already observe UB,
49+
and the compiler may insert a `trunc` of the discriminant value when trying to
50+
get the value. The UB may already have happened. Similar, any check for an
51+
argument marked `nonnull` will be optimized out by the compiler.
52+
53+
### The next 6 months
54+
55+
Within the next six months we would like to do the following things:
56+
57+
1. Develop a comprehensive niche value check for all niches.
58+
2. Insert it ideally when values are loaded from memory (e.g. a "checked-load") or on function entry.
59+
3. Migrate the enum check to the same system mentioned in 2.
60+
61+
### The "shiny future" we are working towards
62+
63+
Similar to how [UBSan](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html)
64+
exists in Clang, we would like to see an option in Rust to detect undefined
65+
behavior at runtime. As mentioned above, this is critical for cross-language
66+
interoperability and can help catch UB before it reaches production.
67+
68+
The extension of these checks can be done step-by-step, keeping in mind the
69+
runtime overhead. Different checks can be enabled by separate flags (like in UBSan).
70+
Eventually we would like to check (sanitize) most items listed as
71+
[UB in Rust](https://doc.rust-lang.org/reference/behavior-considered-undefined.html).
72+
73+
## Ownership and team asks
74+
75+
**Owner:** [@1c3t3a](https://github.com/1c3t3a), [@jakos-sec](https://github.com/jakos-sec)
76+
77+
| Task | Owner(s) or team(s) | Notes |
78+
|------------------------------|------------------------------------------------------------------------------------|------------------------------------------|
79+
| Discussion and moral support | ![Team][], [compiler], [opsem] | |
80+
| Implementation | [@1c3t3a](https://github.com/1c3t3a), [@jakos-sec](https://github.com/jakos-sec) | |
81+
| MCP decision | ![Team][], [compiler] | Where to insert the check / checked load |
82+
| Dedicated reviewer | ![Team][] [compiler], [opsem] | @saethlin |
83+
84+
### Definitions
85+
86+
For definitions for terms used above, see the [About > Team Asks](https://rust-lang.github.io/rust-project-goals/about/team_asks.html) page.
87+
88+
* *Discussion and moral support* is the lowest level offering, basically committing the team to nothing but good vibes and general support for this endeavor.
89+
* *Author RFC* and *Implementation* means actually writing the code, document, whatever.
90+
* *Design meeting* means holding a synchronous meeting to review a proposal and provide feedback (no decision expected).
91+
* *RFC decisions* means reviewing an RFC and deciding whether to accept.
92+
* *Org decisions* means reaching a decision on an organizational or policy matter.
93+
* *Secondary review* of an RFC means that the team is "tangentially" involved in the RFC and should be expected to briefly review.
94+
* *Stabilizations* means reviewing a stabilization and report and deciding whether to stabilize.
95+
* *Standard reviews* refers to reviews for PRs against the repository; these PRs are not expected to be unduly large or complicated.
96+
* *Prioritized nominations* refers to prioritized lang-team response to nominated issues, with the expectation that there will be *some* response from the next weekly triage meeting.
97+
* *Dedicated review* means identifying an individual (or group of individuals) who will review the changes, as they're expected to require significant context.
98+
* Other kinds of decisions:
99+
* [Lang team experiments](https://lang-team.rust-lang.org/how_to/experiment.html) are used to add nightly features that do not yet have an RFC. They are limited to trusted contributors and are used to resolve design details such that an RFC can be written.
100+
* Compiler [Major Change Proposal (MCP)](https://forge.rust-lang.org/compiler/mcp.html) is used to propose a 'larger than average' change and get feedback from the compiler team.
101+
* Library [API Change Proposal (ACP)](https://std-dev-guide.rust-lang.org/development/feature-lifecycle.html) describes a change to the standard library.
102+
103+
## Frequently asked questions
104+
105+
None yet.

0 commit comments

Comments
 (0)