GithubHelp home page GithubHelp logo

Comments (9)

dtolnay avatar dtolnay commented on May 25, 2024 2

BorshSerialize and BorshDeserialize are safe traits -- by language semantics that means it is unsound for the memory safety / thread safety of the program to hinge on either of them being implemented "correctly". This is 100% orthogonal to whether an individual trait method is safe or unsafe to call (which is what unsafe fn means). A trait that is unsafe to implement can contain methods that are safe to call, and a trait that is safe to implement can contain methods that are unsafe to call.

Reference:

https://doc.rust-lang.org/1.50.0/reference/items/traits.html#unsafe-traits
https://doc.rust-lang.org/1.50.0/nomicon/safe-unsafe-meaning.html
https://doc.rust-lang.org/1.50.0/book/ch19-01-unsafe-rust.html
https://doc.rust-lang.org/1.50.0/std/keyword.unsafe.html

from borsh-rs.

dtolnay avatar dtolnay commented on May 25, 2024

In other words the UB repros in #17 and #18 both continue to be an issue.

from borsh-rs.

evgenykuzyakov avatar evgenykuzyakov commented on May 25, 2024

@dtolnay

What do you mean it's safe to implement? Does Rust allows to implement a trait method that is marked unsafe without unsafe?

Also if you have suggestion how to the handle it better, I'd prefer to do this. The issue is we want to implement Borsh serialization and deserialization of Vec<u8> and &[u8] differently from default implementation of Vec<T> and &[T] where T: BorshSerialize or T: BorshDeserialize

from borsh-rs.

matklad avatar matklad commented on May 25, 2024

Yeah, that's all true. I believe there's no clean way to express this in Rust (what we ideally want is an unsafe super-trait, but that requires specialization, bringing us back to the square 1).

#25 implements a simpler solution of just hiding the method from crate's public API.

from borsh-rs.

RalfJung avatar RalfJung commented on May 25, 2024

I believe there's no clean way to express this in Rust

unsafe trait sounds like a clean way to express "the user must be careful when implementing this trait (e.g., by not overwriting a certain method)".

from borsh-rs.

cramertj avatar cramertj commented on May 25, 2024

One pattern that can be used in order to have a safe trait rely on guarantees is the following:

struct Guarantee { _private: () }

impl Guarantee {
   // Safety: only call if ...
   pub unsafe fn promise() -> Self { Guarantee { _private: () } }
}

trait RequiresGuarantee {
   fn check_guarantee(&self) -> Guarantee;
}

Then users can call check_guarantee, which, if it returns without diverging, must have internally called promise using an unsafe block, so the requirements on promise must be satisfied.

from borsh-rs.

matklad avatar matklad commented on May 25, 2024

To be clear, the underlying issue was solved way nicer by dtolnay here by just not using is_u8 at all.

@RalfJung there's a twist here, in that we want to (unsafely) override this for u8, and, for all other types, use default (safe) impl. Or, as I've said, we could use unsafe trait, but that needs specialization.

@cramertj that won't work exactly as spelled -- the user user can get Guarantee without unsafe by calling RequiresGuarantee::check_guarantee on some other type that implements it. You need to make check_guarantee unsafe to call as well:

// You write code like
struct CramertjType;

impl RequiresGuarantee for CramertjType {
    fn check_guarantee(&self) -> Guarantee { 
      // Carefully verify invariants
      unsafe { Guarantee::promise() } 
    } 
}

// I write code like
struct MatkladType;

impl RequiresGuarantee for MatkladType {
    fn check_guarantee(&self) -> Guarantee { 
      // Life's too short for verifying invariants, lets use someone else's promise
      CramertjType::check_guarantee()
    } 
}

from borsh-rs.

cramertj avatar cramertj commented on May 25, 2024

from borsh-rs.

RalfJung avatar RalfJung commented on May 25, 2024

there's a twist here, in that we want to (unsafely) override this for u8, and, for all other types, use default (safe) impl. Or, as I've said, we could use unsafe trait, but that needs specialization.

You could use unsafe trait without specialization, but I guess that's not as ergonomic as you'd like it to be?

from borsh-rs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.