Comments (6)
Arbitrary unsafe functions are not exposed to Rust. The FFI has a list of the C++ functions that need to be reviewed, like this:
Lines 18 to 25 in 1822e22
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.
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.
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.
Ok thanks. But what about the other questions?
from cxx.
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.
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)
- Question: estimate workload to call functions from geogram HOT 1
- Returning `CxxString` from Rust to C++ HOT 5
- Extern C++ Enums HOT 5
- Advice/example on docs.rs strategy HOT 2
- Feature Request: Add support for nested Vector types HOT 1
- Building two CXX C++ bindings with the same symbols but in different namespaces. HOT 2
- Including bridge from another crate
- Error in configuring crates_universe when included as a Bazel module
- Error compiling `cxx.cc` on Windows HOT 1
- Proposal: implementing native C++ std::error_code
- Link failure when using CXX-backed function from another crate HOT 1
- Unsupported element type of Vec<[u64; 3]>
- How to include C++ files whose directory is given by an environment variable? HOT 1
- Error compiling demo to wasm on macOS HOT 5
- Is there a way to expose a C++ class that is itself a wrapper on `std::shared_ptr`?
- How can I `include!` a file in OUT_DIR
- How can I return a vector of non-trivial type of C++ to Rust?
- LNK2019 unresolved symbol for Vec<SharedStruct> using MSVC
- Using CXX in multiple DLLs always results in undefined behavior?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cxx.