Skip to content

Canvas unsafe code in the wild #146

Closed

Description

@nikomatsakis

I think we should organize a kind of "canvas" to find examples of how unsafe code is used in the wild. To start, it'd be great to enumerate a list of interesting places to look.

Here is my start at a list. Further nominations welcome. I'll try to keep the list up to date. Moreover, if you feel you've examined the source, open any relate issues and we can check it off.

Other thoughts for packages? Is this a fruitful thing to examine?

Activity

  1. changed the title [-]Unsafe code in the wild[/-] [+]Canvas unsafe code in the wild[/+] on Sep 1, 2016
  2. strega-nil commented on Sep 2, 2016

    @strega-nil

    Well, I think pcb would be a nice place to start, it's very simple and has some unsafe code that would be seen as UB by the "correct lifetime" style. (example)

  3. nikomatsakis commented on Sep 3, 2016

    @nikomatsakis
    ContributorAuthor

    @ubsan do you think that the "interesting patterns" in pcb are thus summarized by #12? If not, maybe you can write-up an issue that covers them?

  4. strega-nil commented on Sep 3, 2016

    @strega-nil

    I think they're well enough summarized. (see here) referencing pcb

  5. eternaleye commented on Sep 8, 2016

    @eternaleye

    Another use of unsafe code, this one more type-focused than lifetime-focused: https://github.com/Diggsey/query_interface

  6. Ericson2314 commented on Sep 8, 2016

    @Ericson2314
  7. nikomatsakis commented on Sep 8, 2016

    @nikomatsakis
    ContributorAuthor

    This discussion of how coroutines and scoped threads interact seems relevant, probably more as a negative case (i.e., enumerate where the coroutine abstractions goes wrong):

    https://www.reddit.com/r/rust/comments/508pkb/unleakable_crate_safetysanityrefocus/d72703d

  8. arielb1 commented on Sep 8, 2016

    @arielb1

    This discussion of how coroutines and scoped threads interact seems relevant, probably more as a negative case (i.e., enumerate where the coroutine abstractions goes wrong):

    That is more of a soundness issue than a memory model issue. scoped assumes that stack frames never leak - that a lifetime parameter passed to a function must live until the function exits (through a return or resume), while coroutines flat out violates that assumption.

  9. RalfJung commented on Sep 12, 2016

    @RalfJung
    Member

    I don't entirely understand what is the criterion for listing pieces of the standard library. Certainly RefCell is a very interesting bit of unsafe code, showing how far interior mutability can go and playing games with lifetimes that I have not yet seen in any other piece of unsafe code.

  10. mystor commented on Sep 12, 2016

    @mystor

    The problem with RefCell is that we aren't sure that its implementation won't invoke Undefined Behavior in a future model for what defines undefined behavior in unsafe rust. The fact that it holds a &'a reference which isn't actually valid for all of &'a, but only for either the lifetime of the Ref or RefMut, or 'a, whichever is shorter. This could be considered UB under some models as the lifetimes are "incorrect".

    We aren't suggesting removing RefCell, it's just a question of whether its current implementation should be UB.

  11. RalfJung commented on Sep 12, 2016

    @RalfJung
    Member

    What I am asking is why RefCell is not listed above as "how unsafe code is used in the wild".

  12. nikomatsakis commented on Sep 12, 2016

    @nikomatsakis
    ContributorAuthor

    @mystor @RalfJung I think the only reason I did not list RefCell is that we have #5 already. My goal with this issue is not for it to exist permanently, just to serve as a clearing house of work to be done in terms of researching and then opening issues.

  13. RalfJung commented on Sep 12, 2016

    @RalfJung
    Member

    I see, that makes sense.

    Notice that the trouble I am having with RefCell in my semantic model is entirely unrelated to #5. However, I am not sure if the memory model would be affected by that...

  14. arielb1 commented on Sep 12, 2016

    @arielb1

    Notice that the trouble I am having with RefCell in my semantic model is entirely unrelated to #5.

    What's the trouble again?

  15. nikomatsakis commented on Sep 12, 2016

    @nikomatsakis
    ContributorAuthor

    @RalfJung if you see some other aspect of ref-cell that's not documented, please do open another issue...

  16. 14 remaining items

  17. mystor commented on Oct 5, 2016

    @mystor

    @ubsan Yup, that's actually almost exactly what I'm doing.

    And yes, I agree that it's a hack to get around () not being C compatible. I think we should probably fix that.

  18. burdges commented on Oct 5, 2016

    @burdges

    Just stating the obvious : There are going to be many situations where the only unsafe code consists of calls to std::mem::transmute<X,Y> where X is a packed C struct and Y is [u8; std::mem::size_of<X>] or vice versa. It sounds unfortunate to disable optimizations for that if X does not contain pointers.

  19. arielb1 commented on Oct 5, 2016

    @arielb1

    The get_unchecked examples at rust-lang/rust#36976 are convincing me that we do not want to UB on just creating a reference to an invalid value, or even returning such a reference from a function. This would naturally make references to Void be well-defined too (through horribly unsafe).

  20. arielb1 commented on Oct 5, 2016

    @arielb1

    BTW, even if invalid values are ignored, my aliasing memory models could end up with the result of an out-of-range [T]::get_unchecked not having a capability to access the out-of-range memory (because they are limited to the capability of the &[T] - i.e. only to the length of it).

  21. bluss commented on Jan 21, 2017

    @bluss

    I implement struct RevSlice<T>([T]) which is a reversed view of a slice. I'm unsure what's needed to put it on sound ground, specifically the conversions:

    • &[T] -> &RevSlice<T>
    • &mut [T] -> &mut RevSlice<T>
    • Box<[T]> -> Box<RevSlice<T>>
  22. Amanieu commented on Jan 21, 2017

    @Amanieu
    Member

    @bluss I think this is a good case for #[repr(transparent)]

  23. bluss commented on Jan 22, 2017

    @bluss

    Another crate:

  24. llogiq commented on Mar 16, 2017

    @llogiq

    bytecount (used by ripgrep&xi) has one line of unsafe to transmute aligned byte slices to usize/SIMD slices. This pattern might perhaps be factored out into its own crate, or perhaps even find a place in libstd.

  25. Manishearth commented on Mar 16, 2017

    @Manishearth
    Member

    Can't byteorder do that?

  26. bluss commented on Mar 17, 2017

    @bluss

    byteorder does not deal with slice conversions.

    I imagine that's something like split_aligned_for but even that formulation leaves much to be desired, slice iteratorish formulation seems to codegen much better (hence the other experiments there in the same junkyard and in rawslice).

  27. Shnatsel commented on Jun 23, 2019

    @Shnatsel
    Member

    I'm not sure what this issue is supposed to achieve that downloading and grepping crates.io or searching for "unsafe" in Rust code on Github would not. But here are some bugs in unsafe code found in the wild, w/ short analysis. More of them here: https://rustsec.org/advisories/

    Interesting or Rust-specific bugs:

    1. SmallVec::insert_many is unsound smallvec/smallvec#96 - double free if iterator over non-Copy type panics. Fixed via "set length on drop" trick.
    2. inflate crate: unsafe code due to missing safe abstraction (no way to append contents of vector to itself), I've opened an RFC to provide one. Vulnerable, simplified example here. This is actually a recurring bug in DEFLATE decoders, another one with a different implementation also has this exact bug (pending disclosure atm).
    3. Contents of uninitialized memory are leaked into the output on malformed inputs ruuda/claxon#10 exposure of uninitialized memory because of missing abstraction for an output buffer. The missing abstraction actually exists as a crate but nobody uses it because getting rid of 1-2 unsafe blocks per crate doesn't seem to be worth adding another dependency with unsafe code in it. In this case could be patched without regressing performance by requesting zeroed memory from the OS. This vuln triggered documentation improvements. I had to write a custom tool to find this bug!

    Boring but serious bugs:

    1. CVE in str::repeat, also victim of appending vector to itself unsafely, didn't check for overflow in capacity calculation.
    2. use-after-free when growing to the same size smallvec/smallvec#148 - use-after-free due to logic bug, boring all the way
    3. Fix buffer overflow bug in deflate::core::BitBuffer::flush Frommi/miniz_oxide#47 - out-of-bounds write due to missing check. Now that u64::to_le_bytes is stabilized the unsafe is no longer needed. There is also precedent for the reverse pattern with from_le_bytes and TryInto. Safe versions are exactly as fast as the unsafe ones.
  28. added
    C-listCategory: A list/collection of some sort. Please help maintain it!
    on Aug 14, 2019
  29. JakobDegen commented on Apr 25, 2023

    @JakobDegen
    Contributor

    Discussed in backlog bonanza: Not so sure this issue is providing much value and the discussion here is quite old. Closing

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

    C-listCategory: A list/collection of some sort. Please help maintain it!

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions