Code Monkey home page Code Monkey logo

Comments (6)

dtolnay avatar dtolnay commented on July 29, 2024

Arbitrary unsafe functions are not exposed to Rust. The FFI has a list of the C++ functions that need to be reviewed, like this:

cxx/demo/src/main.rs

Lines 18 to 25 in 1822e22

include!("demo/include/blobstore.h");
type BlobstoreClient;
fn new_blobstore_client() -> UniquePtr<BlobstoreClient>;
fn put(&self, parts: &mut MultiBuf) -> u64;
fn tag(&self, blobid: u64, tag: &str);
fn metadata(&self, blobid: u64) -> BlobMetadata;

and I can examine just those 4 C++ functions to confirm that they are indeed safe to call from Rust (i.e. a Rust function with the same signature and behavior would be a safe function, not an unsafe one). After that, it's guaranteed that if any source of undefined behavior appears in the program, it's either from (1) a Rust unsafe block unrelated to the FFI (if any), or (2) C++ code unrelated to the FFI. I can audit the Rust unsafe blocks in my program as if C++ wasn't involved, and I can audit all my C++ code the same as if Rust wasn't involved, and convince myself that the program is free of UB.

This is in contrast with traditional C–Rust FFI using bindgen, which always involves unsafe code on the Rust side of the FFI, like this: https://github.com/rust-lang/git2-rs/blob/git2-0.19.0/src/repo.rs#L395-L401.

from cxx.

dabrahams avatar dabrahams commented on July 29, 2024

OK, sure, but only a subset of C++ functions can be exposed to Rust as safe. Are you saying CXX doesn't allow other C++ functions (e.g. vector<int>::pop_back()) to be exposed to Rust? How could it possibly prevent that?

(I don't know Rust very well; I assumed unsafe extern "C++ {...}" meant that the Rust declarations within {...} were treated as unsafe by Rust. Was that wrong?)

from cxx.

dtolnay avatar dtolnay commented on July 29, 2024

Whether a function is safe to call from Rust is determined by whether the fn is unsafe, not the surrounding block. This function would be unsafe to call from Rust:

extern "C++" {
    unsafe fn pop_back(self: Pin<&mut CxxVector<c_int>>);
}

See https://cxx.rs/extern-c++.html#functions-and-member-functions.

from cxx.

dabrahams avatar dabrahams commented on July 29, 2024

Ok thanks. But what about the other questions?

from cxx.

dtolnay avatar dtolnay commented on July 29, 2024

Are you saying CXX doesn't allow other C++ functions (e.g. vector<int>::pop_back()) to be exposed to Rust? How could it possibly prevent that?

CXX does allow other C++ functions to be exposed to Rust, by writing unsafe fn in the list of functions in the FFI module as in #1364 (comment). unsafe fn C++ functions can only be called from unsafe Rust code. Safe C++ functions can be called from safe Rust code. CXX does not prevent FFIs from being expressed in terms of unsafe functions. It does prevent the need to do so, by making it possible for real-world elaborate FFIs to be expressed using safe functions.

In general, if you have some arbitrary C++ function to call whose behavior is not safe, you're not going to call it without writing either unsafe Rust code or (unsafe) C++ code. In your example of pop_front the unsafety can go either on the C++ side:

// C++
template <typename T>
bool checked_pop_back(std::vector<T>& vec) {
  if (vec.empty()) {
    return false;
  } else {
    vec.pop_back();
    return true;
  }
}

// Rust
unsafe extern "C++" {
    #[cxx_name = "checked_pop_back"]
    fn checked_pop_back_int(vec: Pin<&mut CxxVector<c_int>>) -> bool;
}

assert!(ffi::checked_pop_back_int(vec));

or the Rust side:

// Rust
extern "C++" {
    unsafe fn pop_back(vec: Pin<&mut CxxVector<c_int>>);
}

fn checked_pop_back(vec: Pin<&mut CxxVector<c_int>>) {
    assert(!vec.is_empty());
    unsafe { ffi::pop_back(vec) }
}

(From experience with >300 CXX-based libraries at Meta, the bindings tend to consist overwhelmingly of safe functions, like this. This makes them accessible to engineers with limited Rust experience. We've had engineers in their first and second week with Rust successfully write bindings that would have been challenging for me to produce without CXX as a Rust expert and C++ "knowledgeable".)

I assumed unsafe extern "C++" {...} meant that the Rust declarations within {...} were treated as unsafe by Rust. Was that wrong?

The assumption is wrong -- unsafe extern "C++" { fn ... } is a function that is safe to call. This is an unsafe thing to claim about a function, hence the unsafe keyword. Inversely extern "C++" { unsafe fn ... } is a function that is unsafe to call, and isn't unsafe to claim that.

from cxx.

dabrahams avatar dabrahams commented on July 29, 2024

It does prevent the need to do so, by making it possible for real-world elaborate FFIs to be expressed using safe functions.

s/real-world/some real-world/ or even s/real-world/many real-world/ if you want to make that claim.

(From experience with >300 CXX-based libraries at Meta, the bindings tend to consist overwhelmingly of safe functions, like this.

Yes, any API using pure value semantics in C++ (to the degree C++ can express it) will always be like that. It's great that so much of Meta's C++ code is written that way.

This makes them accessible to engineers with limited Rust experience. We've had engineers in their first and second week with Rust successfully write bindings that would have been challenging for me to produce without CXX as a Rust expert and C++ "knowledgeable".)

Not AT ALL questioning the usefulness of this work. I think it's absolutely fantastic. However, you do yourself a disservice by not being precise about the safety claims. It would be easy, for example, for one of those beginning engineers to read your README and reach the wrong conclusions about which things are safe. Also, someone more experienced like me but with less patience will look at your claim, realize it's impossible as stated, and dismiss CXX prematurely.

Of course some of the Rust code (the code that declares certain things to be safe at the very least!) needs to be vetted. It would be better to make the claims more accurate, and it would be helpful to characterize the properties of a C++ API that can be declared safe in Rust. FWIW.

from cxx.

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.