Skip to content

Ref parameter incorrectly decorated with noalias attribute #63787

Closed

Description

@RalfJung

The following library:

use std::cell::*;

pub fn break_it(rc: &RefCell<i32>, r: Ref<'_, i32>) {
    // `r` has a shared reference, it is passed in as argument and hence
    // a barrier is added that marks this memory as read-only for the entire
    // duration of this function.
    drop(r);
    // *oops* here we can mutate that memory.
    *rc.borrow_mut() = 2;
}

generates IR for break_it that starts like

; playground::break_it
; Function Attrs: noinline nonlazybind uwtable
define void @_ZN10playground8break_it17hb8a9beeb2affda19E(
  { i64, i32 }* align 8 dereferenceable(16) %rc,
  i32* noalias nocapture readonly align 4 dereferenceable(4) %r.0,
  i64* nocapture align 8 dereferenceable(8) %r.1)
unnamed_addr #1 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {

Note the noalias. That is incorrect, this function violates the noalias assumptions by mutating the data r points to through a pointer (rc) not derived from c. Here's a caller causing bad aliasing:

pub fn main() {
    let rc = RefCell::new(0);
    break_it(&rc, rc.borrow())
}

RefMut has the same problem when -Zmutable-noalias is set.

Cc @rkruppe @comex

Activity

  1. gnzlbg commented on Aug 21, 2019

    @gnzlbg
    Contributor
  2. bjorn3 commented on Aug 21, 2019

    @bjorn3
    Member

    Maybe pour an UnsafeCell into Ref instead of &T?

  3. RalfJung commented on Aug 21, 2019

    @RalfJung
    MemberAuthor

    It should probably use a raw pointer (something I have been arguing for for years now ;). For RefMut, UnsafeCell wouldn't even help.

  4. gnzlbg commented on Aug 21, 2019

    @gnzlbg
    Contributor

    Changing Ref value field to value: &'b std::cell::UnsafeCell<T> fixes this.

  5. RalfJung commented on Aug 21, 2019

    @RalfJung
    MemberAuthor

    Also see #60076: vec_deque::Drain has a similar problem.

    Changing Ref value field to value: &'b std::cell::UnsafeCell fixes this.

    It does, but I think a raw pointer is the better fix.

  6. gnzlbg commented on Aug 21, 2019

    @gnzlbg
    Contributor

    It does, but I think a raw pointer is the better fix.

    Why?

    The value field inside RefCell is of type UnsafeCell<T>, not T, so IMO Ref has a bug by using &T instead of &UnsafeCell<T>. Using a raw pointer (e.g. NonNull<T>) would mean that we lose the dereferenceable annotation.

  7. added
    A-codegenArea: Code generation
    C-bugCategory: This is a bug.
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    T-libs-api[DEPRECATED; DO NOT USE]
    and removed
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Aug 21, 2019
  8. comex commented on Aug 21, 2019

    @comex
    Contributor

    Proof of concept miscompilation: playground link

    Edit: To be fair, it works based on the “a == b implies the compiler can replace b with a” optimization, which can be unsound all by itself in some cases involving pointer arithmetic or allocation/deallocation... but eh, this code does neither.

  9. eddyb commented on Aug 22, 2019

    @eddyb
    Contributor

    In rust-lang/unsafe-code-guidelines#125 (comment) I asked:

    Is Ref having noalias readonly on the data reference a problem because, unlike a regular reference, it can be invalidated by Drop?

    Could we then rely on the presence of a Drop impl to disable noalias readonly, or should Ref itself use a raw pointer or &UnsafeCell?

    But it seems like the preferred solution is to change Ref to not contain a reference.

    For RefMut, UnsafeCell wouldn't even help.

    @RalfJung Why not? It would have to be &UnsafeCell, not &mut UnsafeCell, but I expect it to work.

  10. 38 remaining items

  11. RalfJung commented on Jul 30, 2021

    @RalfJung
    MemberAuthor

    Yes I think that would be the best fix (and I've argued for that change even before we knew about this problem^^)

  12. BurntSushi commented on May 13, 2022

    @BurntSushi
    Member

    cc @rust-lang/libs What's stopping us from fixing this? It looks like a low hanging unsound bug. :)

  13. RalfJung commented on May 13, 2022

    @RalfJung
    MemberAuthor

    One problem is deciding whether this should be fixed on the lang level or libs level...

  14. BurntSushi commented on May 13, 2022

    @BurntSushi
    Member

    It looks like we could at least fix this at the libs level without much difficulty, right? Then the lang team can decide whether they want to fix this on their end or not. If they do, I assume we could then revert the library fix.

    Although I will say that I don't quite grok the lang side fix for this.

  15. RalfJung commented on May 13, 2022

    @RalfJung
    MemberAuthor

    Yeah, I think there are several good reasons to use raw pointers (or rather, NonNull) rather than references here.

    On the lang side, we could not add noalias to newtyped references... but that might also be a bad idea since it makes newtypes less powerful.

  16. cuviper commented on May 13, 2022

    @cuviper
    Member

    I can work on the lib side.
    @rfcbot claim

  17. self-assigned this
    on May 13, 2022
  18. cuviper commented on May 13, 2022

    @cuviper
    Member

    Please see #97027.

  19. added a commit that references this issue on May 14, 2022
  20. added a commit that references this issue on May 15, 2022
  21. cuviper commented on Jul 30, 2022

    @cuviper
    Member

    Now that the library fix has landed, are we still considering lang changes, or can we close this?

  22. RalfJung commented on Jul 30, 2022

    @RalfJung
    MemberAuthor

    I think the lang side of this is not final yet, but this is not the right issue to track that. We have rust-lang/unsafe-code-guidelines#125 and this will have to be part of the discussion of the aliasing model, once we get there.

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

Metadata

Metadata

Assignees

Labels

A-codegenArea: Code generationC-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-langRelevant to the language teamT-libs-api[DEPRECATED; DO NOT USE]

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions