Skip to content

Stacked Borrows: raw pointer usable only for T too strict? #134

@RalfJung

Description

@RalfJung
Member

Currently, the following is illegal according to Stacked Borrows:

let val = [1u8, 2];
let ptr = &val[0] as *const u8;
let _val = unsafe { *ptr.add(1) };

The problem is that the cast to *const u8 creates a raw pointer that may only be used for the u8 it points to, not anything else. The most common case is to do &slice[0] as *const _ instead of slice.as_ptr().

This has lead to problems:

Maybe this is too restrictive and raw pointers should be allowed to access their "surroundings"? I am not sure what exactly that would look like though. It would probably require having the raw pointer fully inherit all permissions from the reference it is created from.

I'll use this issue to collect such cases.

Activity

added
A-aliasing-modelTopic: Related to the aliasing model (e.g. Stacked/Tree Borrows)
on May 28, 2019
RalfJung

RalfJung commented on May 28, 2019

@RalfJung
MemberAuthor

This is also a problem in Rc::into_raw/Rc::from_raw:

    pub fn into_raw(this: Self) -> *const T {
        let ptr: *const T = &*this;
        mem::forget(this);
        ptr
    }

ptr may only be used to access the T part of the RcBox<T>, but if later used with from_raw it is used for the entire Rc. Fixing this is not even possible without rust-lang/rfcs#2582.

added a commit that references this issue on May 28, 2019
RalfJung

RalfJung commented on Aug 16, 2019

@RalfJung
MemberAuthor

This also came up in Gilnaa/memoffset#21, where @Amanieu proposed an container_of! macro that computes the address of a struct given the address of one of its fields.

RalfJung

RalfJung commented on Aug 17, 2019

@RalfJung
MemberAuthor

@Amanieu the problem with code like this

struct Pair { f1: u16, f2: u16 };

let p = Pair { f1: 2, f2: 3 };
let c = container_of!(&p.f1, Pair, f1);
let _val = c.f2;

arises when you imagine splitting it across several functions:

struct Pair { f1: u16, f2: u16 };

let p = Pair { f1: 2, f2: 3 };
foo(&p.f1);
p.f2 = 4;

We want the compiler to be able to move the assignment to f2 up across the call to foo. But if foo is allowed to use container_of! and then read f2, that is no longer possible.

So, I think there is a real conflict here between being able to bound the effects of a call like foo(&p.f1), and allowing container_of!.

Lokathor

Lokathor commented on Aug 19, 2019

@Lokathor
Contributor

How does this work with [T]::as_ptr? Does that pointer let you use "the whole slice" when offsetting?

RalfJung

RalfJung commented on Aug 20, 2019

@RalfJung
MemberAuthor

@Lokathor yes. Those methods do the right thing. They cast the wide reference to a wide raw pointer, and only then go to thin -- so the ref-to-raw cast has the right "span" in memory.

ecstatic-morse

ecstatic-morse commented on Oct 5, 2019

@ecstatic-morse

rust-lang/rust#64980 gives a minor reason to maintain the status quo here. It includes a test-case for a dataflow analysis that computes whether a given Local is mutable through a reference. This test would show the analysis to be unsound if it were legal to offset a reference to one field into a pointer to another, disjoint field.

It is possible to relax the analysis so that it remains sound if this behavior became defined (see rust-lang/rust#65030).

78 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-SB-vs-TBTopic: Design questions where SB and TB are opposite sides of the design axisA-aliasing-modelTopic: Related to the aliasing model (e.g. Stacked/Tree Borrows)C-open-questionCategory: An open question that we should revisitS-pending-designStatus: Resolving this issue requires addressing some open design questions

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @briansmith@comex@RalfJung@retep998@safinaskar

        Issue actions

          Stacked Borrows: raw pointer usable only for `T` too strict? · Issue #134 · rust-lang/unsafe-code-guidelines