Skip to content

Conversation

@manhatsu
Copy link
Contributor

@manhatsu manhatsu commented Dec 4, 2025

Closes #235.

@netlify
Copy link

netlify bot commented Dec 4, 2025

Deploy Preview for scrc-coding-guidelines ready!

Name Link
🔨 Latest commit 808e965
🔍 Latest deploy log https://app.netlify.com/projects/scrc-coding-guidelines/deploys/69393964e2e0220008659413
😎 Deploy Preview https://deploy-preview-240--scrc-coding-guidelines.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@rcseacord
Copy link
Contributor

I've made some improvement suggestions in a PR here: manhatsu#1

@manhatsu
Copy link
Contributor Author

manhatsu commented Dec 4, 2025

I've made some improvement suggestions in a PR here: manhatsu#1

Thank you very much. Merged to this branch

@PLeVasseur
Copy link
Collaborator

Hey @manhatsu 👋 it looks like from the CI that a new tag needs to be added.

Could you follow what @rcseacord did in this PR to add the unsafe tag with an appropriate description? Ideally you would do that as a separate PR, as that's easy to review and merge.

Copy link
Collaborator

@PLeVasseur PLeVasseur left a comment

Choose a reason for hiding this comment

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

Hi @manhatsu -- thank you for contributing. Please see the comment I left on how to generate a template.

Copy link

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

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

What @inkreasing says is correct. This description is insufficient to reflect the restrictions imposed by MIRI here:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=abb9da1c391902b21c03ed1d21767b58

Note this is not UB before line 15.

Bytes remain uninit until written. You may not read uninitialized bytes as any initialized type, period, not even if "all" bitpatterns are considered valid, because uninit is the 257th bitpattern for a byte, effectively: 0xUU. By contrast, u8 is 0x00 through 0xFF, inclusive. We use MaybeUninit<u8> to indicate the final state is possible, and it is valid to read that value (well, from any allocation that has a byte in it, at least).

Comment on lines 19 to 23
A program shall not create a value of any type from uninitialized memory,
except when accessing a field of a union type,
where such reads are explicitly defined to be permitted even if the bytes of that field are uninitialized.
It is prohibited to interpret uninitialized memory as a value of any Rust type such as a
primitive, aggregate, reference, pointer, struct, enum, array, or tuple.
Copy link

@workingjubilee workingjubilee Dec 5, 2025

Choose a reason for hiding this comment

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

This definition does not consider composition of types:

use std::mem::MaybeUninit;

union Uninit32 {
    u: u32,
    i: i32,
    f: f32,
    void: (),
}

struct Newtype32(Uninit32);

fn main() {
    let x: Newtype32 = unsafe { MaybeUninit::uninit().assume_init() };
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=feae8c987fa0b2703533ce0ebf8b23ba

This passes miri because all the bytes in Newtype32 are defined by Uninit32, which is allowed to be uninitialized.

When bytes are read as a type (e.g. by using ptr.read(), *ptr, or mem::transmute), a "typed read" occurs. This asserts the bytes are valid as that type. Uninit32 and MaybeUninit are the same thing here: unions with () as a possibility, which means they must be valid to read from a blob of uninitialized bytes within a valid allocation1. Because Newtype32 is entirely defined by Uninit32, it is also valid to read from uninitialized bytes: the struct wrapper does not impose a novel validity requirement. If this is a mandatory guideline, it should be more exacting about why.

Footnotes

  1. Note that this is likely a stronger requirement than the actual rules will be regarding union validity once final details of those are hashed out. I'm just giving an example that is very "in the clear".

Comment on lines 50 to 61
.. non_compliant_example::
:id: non_compl_ex_Qb5GqYTP6db1
:status: draft

This noncompliant example creates a value of type ``u32`` from uninitialized memory via
`assume_init <https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init>`_:

.. code-block:: rust
use std::mem::MaybeUninit;
let x: u32 = unsafe { MaybeUninit::uninit().assume_init() }; // UB

Choose a reason for hiding this comment

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

You got this right, but the lesson needs to be extended elsewhere: assume_init and the read of a union field at its type are not really different operations in the semantics, so why would u32 be valid to read from a union field?

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it!

manhatsu and others added 5 commits December 8, 2025 09:41
Updated guidelines on uninitialized memory usage and added examples of compliant and non-compliant code.
Added noncompliant and compliant examples demonstrating safe /unsafe memory initialization in Rust.
@manhatsu manhatsu force-pushed the doc/no-uninit-value branch from 9b81ff4 to 0e2776c Compare December 8, 2025 00:44
manhatsu and others added 2 commits December 8, 2025 16:06
Updated examples to clarify compliant and non-compliant behavior with uninitialized padding in Rust.
Clarify conditions for accessing union fields and update non-compliant examples.
Copy link
Collaborator

@felix91gr felix91gr left a comment

Choose a reason for hiding this comment

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

I hope this helps

Comment on lines +37 to +38
- may violate niche or discriminant validity,
- may create invalid pointer values, or
Copy link
Collaborator

Choose a reason for hiding this comment

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

I believe that these two would benefit of being further developed with their own examples. Going in-depth in the Rationale is fine: your goal is to make it obvious why this guideline is required. Explain as much as you find is needed.

- creates undefined behavior for most types,
- may violate niche or discriminant validity,
- may create invalid pointer values, or
- may produce values that violate type invariants.
Copy link
Collaborator

@felix91gr felix91gr Dec 8, 2025

Choose a reason for hiding this comment

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

Like the first bullet point, I believe the last one needs to point to an official reference or documentation of some kind that explains in full why this is the case.

:scope: system
:tags: undefined-behavior, unsafe

Do not create a typed value from uninitialized memory.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would perhaps divide this guideline into two.

There is a very good guideline in this PR that deals with the creation of typed values from uninitialized memory by using functions like assume_init on memory that has not been fully initialized on the relevant bytes. That transition, from MaybeUninit<T> to T, &mut T and others, is Undefined Behavior.

But there is also another guideline in this PR that deals with how and when it's valid to access fields of unions. I think it's best for the two to be separate, since one of them deals with the creation of typed values and the other deals with the reading of typed values from unions.


Sidenote:

Keep in mind that MaybeUninit<T> is itself a union, so however the guideline that deals with access to fields of unions ends up being written, you will want to make sure you consider it among the exceptions ;)

Copy link
Collaborator

Choose a reason for hiding this comment

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

You might also want to take a look at these pages:

  1. The Rustonomicon on working with uninitialized memory from unsafe https://doc.rust-lang.org/nomicon/unchecked-uninit.html
  2. The explanation of Initialization Invariant, examples and such, from the docs of MaybeUninit.
  3. The Language Reference on unions: https://doc.rust-lang.org/reference/items/unions.html

The first two contain most of what I think you'll need to complete this / these Guideline(s). I hope they help.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll have to think on this a bit, as splitting guidelines is a lot of work.

Copy link

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

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

Much better.

rcseacord and others added 2 commits December 9, 2025 19:00
Co-authored-by: Félix Fischer <felix91gr@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chapter: values coding guideline An issue related to a suggestion for a coding guideline

Development

Successfully merging this pull request may close these issues.

[Coding Guideline]: Do not create values from uninitialized memory

6 participants