Skip to content

request: lint when raw pointer slicing implicitly creates a temporary reference #99437

Open
@RalfJung

Description

@RalfJung

So let's say you know about aliasing models and have learned that to avoid all aliasing rules of Rust you need to use raw pointers throughout, no references. So for example you write:

use std::ptr::addr_of_mut;

pub fn test(ptr: *mut [u8]) -> *mut [u8] {
    let layout_size = 24;
    unsafe { addr_of_mut!((*(ptr))[..layout_size]) }
}

Looks good, doesn't it?
Well sadly the MIR for this code looks as follows:

fn test(_1: *mut [u8]) -> *mut [u8] {
    debug ptr => _1;                     // in scope 0 at [src/lib.rs:3:13: 3:16](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _0: *mut [u8];               // return place in scope 0 at [src/lib.rs:3:32: 3:41](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let _2: usize;                       // in scope 0 at [src/lib.rs:4:9: 4:20](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _3: &mut [u8];               // in scope 0 at [src/lib.rs:5:27: 5:50](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _4: &mut [u8];               // in scope 0 at [src/lib.rs:5:27: 5:35](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    let mut _5: std::ops::RangeTo<usize>; // in scope 0 at [src/lib.rs:5:36: 5:49](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    scope 1 {
        debug layout_size => _2;         // in scope 1 at [src/lib.rs:4:9: 4:20](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        scope 2 {
        }
    }

    bb0: {
        _2 = const 24_usize;             // scope 0 at [src/lib.rs:4:23: 4:25](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _4 = &mut (*_1);                 // scope 2 at [src/lib.rs:5:27: 5:35](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        Deinit(_5);                      // scope 2 at [src/lib.rs:5:36: 5:49](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        (_5.0: usize) = const 24_usize;  // scope 2 at [src/lib.rs:5:36: 5:49](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
        _3 = <[u8] as IndexMut<RangeTo<usize>>>::index_mut(move _4, move _5) -> bb1; // scope 2 at [src/lib.rs:5:27: 5:50](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // mir::Constant
                                         // + span: [src/lib.rs:5:27: 5:50](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
                                         // + literal: Const { ty: for<'r> fn(&'r mut [u8], RangeTo<usize>) -> &'r mut <[u8] as Index<RangeTo<usize>>>::Output {<[u8] as IndexMut<RangeTo<usize>>>::index_mut}, val: Value(<ZST>) }
    }

    bb1: {
        _0 = &raw mut (*_3);             // scope 2 at /rustc/263edd43c5255084292329423c61a9d69715ebfa/library/core/src/ptr/mod.rs:2005:5: 2005:20
        return;                          // scope 0 at [src/lib.rs:6:2: 6:2](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021#)
    }
}

Note the _4 = &mut (*_1): Rust "helpfully" created a reference for us to subslice into!
This is terrible, because it introduces UB.

This code should either be rejected, or use raw pointers throughout.
Related to #73987.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-raw-pointersArea: raw pointers, MaybeUninit, NonNullA-sliceArea: `[T]`C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-opsemRelevant to the opsem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions