
Rust and C++ Interoperability in Chrome - ytausky
https://www.chromium.org/Home/chromium-security/memory-safety/rust-and-c-interoperability
======
kbenson
> No need for the “unsafe” keyword unless something is known to be less safe
> than normal C++.

> For a Rustacean, this is controversial - all C++ is unsafe!

Isn't this just a fundamental misunderstanding of what unsafe really means,
and as such a nonsense goal that doesn't gain anything?

Unsafe is a Rust language definition, and defines whether the _rust compiler_
can vouch for the safety of some code. As such, calling to a library in some
other language will always be unsafe, by definition, because the Rust language
cannot vouch for it.

If it makes you feel better, replace "unsafe" in your head (or with a macro)
with "rustc_cannot_vouch_for" and carry on with your day. It means the same
thing, and isn't really telling you that your C++ code sucks even if it looks
like it at first glance, so who cares?

If you really want to reduce the unsafe keyword from being seen in most
regular code, you create and interface that maps the C++ function and exposes
it as a rust function, and you've hidden away your unsafe usage to one spot
per function. If you have enough confidence in your C++ code, there's no
downside to this (and if you don't, then maybe you shouldn't be complaining
that unsafe is unneeded).

~~~
arcticbull
> ... known to be less safe than normal C++.

Oh... no, no, that's... very unsafe lol.

Jokes aside, making that their #1 goal was very strange. Agreed it appears to
be a fundamental misunderstanding of what "unsafe" means. It doesn't mean that
it's literally not safe to call that function, just that it's unchecked.
"unchecked" might be a better annotation come to think of it.

~~~
kbenson
> "unchecked" might be a better annotation come to think of it.

Yeah, it's come up before in discussions here. Depending on the context you're
coming from/working in, unchecked either makes more sense, or less sense than
unsafe. When working within Rust, unsafe makes sense, it maps to how people
think about what they are doing, because rustc is checking everything. When
working between Rust and other languages/libraries, it's a bit less accurate,
and "unchecked" makes more sense.

------
bluejekyll
> This seems to present some C++/Rust interoperability challenges which nobody
> else has faced.

Is this different from the Firefox integration with Rust in some meaningful
way?

It looks like the cxx library is going to be critical for this. I’m curious
how helpful others have found cxx for interop with C++?

> For a Rustacean, this is controversial - all C++ is unsafe! But “unsafe”
> should be a really bad code smell. If “unsafe” is needed for all C++ calls,
> there will be thousands of them, and the “unsafe” keyword will lose its
> meaning.

I don’t think the attitude about unsafe usage differs from the general Rust
community. If there’s a lot of it, then it definitely is a code smell.

~~~
rightbyte
Can't you just do a:

    
    
          #define CPP_CALL unsafe
    

in the Rust equivalent to annotate "unsafe" cpp calls from Rust?

"No boilerplate or redeclarations. No C++ annotations. Ideally, no allowlist."

This seems like an unpractical approach. How do you even call C++ code from
Rust without extern "C" linkage.

~~~
coder543
Really, your text macro substitution is missing the broader point.

Hiding the word "unsafe" doesn't make it any less unsafe.

The Rust compiler can't guarantee that the C++ code being called doesn't have
use-after-free bugs or buffer overflows.

The Rust compiler can't guarantee that pointers being returned from C++ code
aren't just wild pointers that point in the middle of nowhere.

The Rust compiler can't guarantee that the C++ code isn't mutating into an
immutable reference.

The Rust compiler can't guarantee that the C++ code isn't holding onto a
reference to an object that it will later mutate when Rust thinks it is now
the sole owner of that object.

The Rust compiler can't guarantee that the C++ code isn't sending un-Send
objects across threads, or that it isn't deallocating objects that it isn't
supposed to deallocate.

Rust makes _a lot_ of guarantees about code written in Rust, which is why
people are so passionate about it. The Rust compiler _feels_ like having the
world's best static code analyzer at your fingertips. It's really nice.

C and C++, on the other hand, are each full of an assortment of powerful
footguns. _Well-written_ C or C++ code interops very nicely with Rust, but the
problem is that programmers are only human, and humans have been repeatedly
shown to make mistakes.

So, calling C++ code is unsafe, and unsafe is a code smell because it is an
opportunity for guarantees to be violated, which is undefined behavior.

Ideally, you build an abstraction around the unsafe interop layer that
rigorously enforces every requirement that the C or C++ code expects (but that
the C and C++ compilers cannot enforce), so that the external code will behave
as well as it can.

The Chromium document is right to call their idea controversial. Hiding the
unsafety of the C++ code without actually doing anything to protect against
malformed calls to that C++ code is a loaded footgun. It might be the right
call for this specific case, though.

~~~
lalaithion
I disagree; All of the things you say about C++ code also apply to unsafe Rust
code. There's an unsafe keyword that allows using that unsafe code, and when
you use it, you are asserting to the compiler that "I promise this code is
actually being used in a safe way". All this document says is that the
C++/Rust boundary should be considered another place where you are asserting
"I promise this code is actually being used in a safe way".

~~~
foota
I think the issue is that rust unsafe means "does something sketchy" whereas
even perfectly safe C++ would have to be annotated unsafe.

~~~
est31
Rust unsafe doesn't mean "does something sketchy". It means "compiler I know
what I'm doing". It's equivalent to casting raw C pointers. You are supposed
to know what you are doing when doing that, but you will be on your own. It
might still be perfectly safe, but the compiler can't tell.

~~~
foota
Sure, but it does indicate something likely to be wrong, relative to normal
rust code. If every C++ function is unsafe then it becomes less clear where
the actually unsafe rust bits are.

~~~
est31
C++ has made it very painless to upgrade from C, by being (mostly) a superset.
It's so painless that many codebases haven't really upgraded and it's common
to see C-isms sprinkled around larger code bases. Some classes written decades
ago can survive the years written in horrible outdated style. For some that
might be a feature, but for the quality (or safety) of the code it isn't.

Yes, when there is too much unsafe in a Rust codebase then the unsafe label
inflates and the safety guarantees aren't as good. But the conclusion of that
shouldn't involve changing definitions of what's unsafe and what isn't, but
using less unsafe overall.

Rust can interface with C++, but it isn't well suited for too intimate
interfacing. That's not where its strengths lie.

~~~
foota
I think that's a different goal from what chrome is looking for. It sounds
like they want to be able to use their utilities and other code written in C++
from within rust, not integrated on a macro level.

------
Paul-ish
Back when I was an intern at Mozilla it was a real pain (in my opinion) to
call between C++ and Rust. This was before bindgen and cbindgen, and certainly
CXX.

Eg if you have a heap allocated thing that is passed between Rust and C++, who
frees it? I ended up hacking something together, but it didn't feel right.

~~~
xxpor
>if you have a heap allocated thing that is passed between Rust and C++, who
frees it?

Isn't this an issue regardless? Forget crossing the rust/c++ boundary, lets
say you pass something to another class in c++, you need to have a contract of
who frees what when, right? Maybe I'm not understanding the issue.

~~~
Paul-ish
Inside both Rust and C++ there are very well developed tools (eg smart
pointers) for dealing with memory allocations. These tools were never written
to be compatible with each other, so you lose them at the language boundary.

~~~
xxpor
That makes sense. I do 99% C, so any time I even have to think about C++ it
unfortunately turns into C with classes rather than C++, so I'm really not as
familiar with the smart pointer options.

------
cmrdporcupine
Hm, I'm a Googler working on the chromecast platform and a Chromium committer
who thinks Rust Is Pretty Neat. I'll look internally as well, but who can I
talk to about helping out with Rust adoption in the context of the chromium
codebase?

------
da39a3ee
Question about the organizational context here. My understanding is that
Chromium is an open source project. In practice though, when the document says
"we" is it talking about mostly Google engineers? I read the document as
indicating that there's a serious possibility of more widespread Rust usage,
especially that last sentence

 _If we become convinced this sort of interoperability is possible, we’ll
revisit widespread use of Rust in Chrome, and at that point we plan to work
hard to achieve this with robust production-quality solutions._

Would it be wrong to take away from this that in some teams within Google,
using Rust in places where C++ would have been used, is something that is
being considered seriously?

------
Rochus
So building Chromium becomes even more complex. Understanding the build system
alone is a major achievement; I even had to build a tool for that:
[https://github.com/rochus-keller/gntools/](https://github.com/rochus-
keller/gntools/). Unfortunately that's only half of the rent; it also needs
hundereds of Python scripts; and now also crates will be added.

~~~
staticassertion
The post is how they are _not using rust_ , how could you possibly have come
to the conclusion that the builds are going to get more complicated?

~~~
ComputerGuru
Because they’re clearly interested in possibly doing so in the future?

------
hamaluik
I integrated some basic CEF stuff (enough get to get a basic browser working)
into a Rust codebase ([https://github.com/hamaluik/cef-
simple](https://github.com/hamaluik/cef-simple)). It was a massive pain at
first, but much easier once you give up on the safety and "idiomacy" of Rust
and accept that you have to write in more of C/C++ style. For the parts that
can't be written purely in Rust, it ends up being not really any more painful
than writing it in C++ anyway.

------
onebot
I hope someday maybe we have a browser completely written in Rust.

What's the point of using Rust in a C++ code base if C++ is the 800lb gorilla
as the article implies. If C++ is so important, then just stick to that?!

~~~
fgdfgddfg
That was the goal with Servo, but Mozilla axed them
[https://twitter.com/directhex/status/1293352458308198401](https://twitter.com/directhex/status/1293352458308198401)

~~~
M2Ys4U
Servo was always a research project around writing a _rendering engine_ and
not an attempt to create a whole new _browser_ product.

~~~
mitchtbaum
Webrender would work better as the complete OS interface than as an engine for
one browser/app.

------
ncmncm
This is all very clever, but it has certain really, really fundamental
problems.

1\. The main program will remain C++ (or anyway Google's hobbled subset). New
code you choose to get done in Rust will be lower-level code, implementing
specific new features, or re-implementing low-level stuff too toxic to fix.
So, the main task is _not_ Rust calling into C++ code, but C++ calling Rust.
That doesn't mean the Rust code won't ever need to call out to utility code,
but: You are coding in Rust for an actual, you know, _reason_ , right? Maybe
that utility stuff should be RIIR, first? Otherwise what was the point, again?

2\. It is all very well to talk about Rust calling C-like functions and
virtual functions, but that only takes us up to 1985. We all know (I hope)
that the overwhelming majority of useful power in C++ code is in features
wholly inaccessible to Rust, even in principle. How will Rust do overload
resolution? Inlines? (Also 1985.) Template instantiation? Exception handling?
(That takes us to 1992.) Template function overloading and partial
specialization? (1998). I could go on, right up to 2020.

There are other fundamental problems, but this seems like enough for now. No
sense piling on. At least point 1 makes point 2 less a problem.

------
brian_herman__
I wonder how this compares to Mozilla's approach when they did something
similar with Rust, Firefox and servo.

~~~
muizelaar
Mozilla's uses a combination of
[https://github.com/eqrion/cbindgen](https://github.com/eqrion/cbindgen) and
[https://github.com/rust-lang/rust-bindgen](https://github.com/rust-lang/rust-
bindgen) depending on the direction of interop. These tools don't provide the
safety guarantees of
[https://github.com/dtolnay/cxx](https://github.com/dtolnay/cxx) but the also
both predate cxx and C++ doesn't have much in terms of safety guarantees to
begin with so the bar is pretty low.

~~~
jcranmer
It's also worth mentioning that Mozilla tends not to use a lot of standard C++
types, using nsTArray instead of std::vector or nsA?C?String instead of
std::string. This makes the porting of APIs using arrays or structs easier,
since Mozilla owns the ABI rather than needing to worry about different
standard libraries having different ABIs.

~~~
ChrisSD
C++ interop with C++ can be a pain. E.g. even with the same version of the
same compiler, GCC can have different options enabled that affect the layout
of some types.

~~~
ncmncm
That is the same in _all_ languages mature enough to have variant options.
Rust included.

Therefore, a tendentious distraction from the topic. Chris, I shall expect
better from you in the future.

------
eggsnbacon1
Do they really need to access thousands of C++ API calls from Rust? Doesn't
this defeat the purpose of writing safe code in Rust? This smells of "not
invented here" which applies to Google projects pretty often.

They should focus on integrating Rust in portions of the API instead of
exposing a gigantic unsafe API surface, essentially making all their code
unsafe. Unless the Chrome codebase is really such a mess that they can't do
anything without exposing this giant API surface. In that case they should
rewrite it to... not do that.

"We can't use Rust unless it allows us to write all our code in C++ without
showing unsafe warnings"

~~~
outworlder
> Do they really need to access thousands of C++ API calls from Rust?

Yes. It's turtles all the way down. Applying this line of thought to its
logical conclusion, it wouldn't be worth it until we have written the OS
itself and all firmware in Rust.

~~~
Ericson2314
Just within the process. Between processes or process and kernel, there are
already runtime checks, so Rust isn't contributing safety so much quality.

------
adamnemecek
They should probably look at how mozilla does it. From experience doing
something similar, things get simpler when you write your code using handles
rather than pointers but that's not how chrome is written.

[https://floooh.github.io/2018/06/17/handles-vs-
pointers.html](https://floooh.github.io/2018/06/17/handles-vs-pointers.html)

------
oscargrouch
As someone that deals with a chromium-based codebase everyday, i dont think
this is a good idea at all.

Unnecessary overcomplication on the codebase, making it more difficult to
understand. (Rust and C++ are complex beasts)

The only thing i could think of, is to replace the tools that are mostly in
Python.. But this will be a lot of work.

I guess maybe Google wants to employ good Rust enginneers and need to have
some "playground" for them.

Swift on the other way, will have native C++ interop, and soon will give the
ability to manage the memory ownership the same way C++ and Rust does (not
just defaulting to ref-count)..

Once Swift have those properties we will have one more good contender in the
same arena as C++, Rust and Zig.

~~~
nilkn
I doubt the point is to offer people a playground but rather to find a way to
write new code in a language that is memory safe by default. Browsers are
notoriously plagued by bugs related to memory safety so there’s quite a lot of
motivation for at least considering this path.

~~~
oscargrouch
That is the problem with default narratives, they dont adapt well to every
case.

Chromium codebase is a massive codebase. It works, its efficient and fast, its
sophisticated and complex, its well tested, had all sort of bugs that was
taken out of them. Its really well written C++ code with modern ownership
semantics. So a lot of mistakes that are used as boogeyman to convince people
to use Rust are barely problems you really face.

And no matter what wonders Rust promisses, a lot of bugs would get back there
in case of rewriting things.

Rust can make a very good point when the thing to be rewritten is in C (if is
not a billion dollar codebase like Linux). But with big codebases, well
written and modern C++ it doesnt make sense at all.

I get it why someone would start a new project in Rust though.. but the things
dont add up when we talk about big codebases already coded with good C++
practices.

~~~
kllrnohj
> So a lot of mistakes that are used as boogeyman to convince people to use
> Rust are barely problems you really face.

[https://bugs.chromium.org/p/project-
zero/issues/list?q=produ...](https://bugs.chromium.org/p/project-
zero/issues/list?q=product%3Achrome&can=1)

This year alone saw 2 issues from Project Zero in Chrome that would have been
prevented by Rust - both OOB accesses, one with a helping of data racing.

Chromium is an incredibly security-sensitive piece of software, and that
really is an excellent fit for Rust. It's not a boogeyman argument and the
Chromium team themselves are the ones pursuing it, it's not being forced on
them.

~~~
oscargrouch
I have no doubt that Rust could save some sort of bugs. If you read all the
comment i´ve made, you will see that we are talking about a massive codebase
already coded in C++.

Giving the time it is alive, all the engineering hours, investiments, tools,
etc.. most of the bugs that Rust could have prevented right on the beggining
are already covered (Chrome also uses fuzzers and static analysis tools to
automate C++ code)

> This year alone saw 2 issues from Project Zero in Chrome that would have
> been prevented by Rust

Thanks for making my point even clearer. If you really knew the size of the
codebase, having only 2 issues on Project Zero is kind of a compliment to
Chrome.

By the way, it was yesterday, that i´ve saw a research with fuzzers applied in
C, C++ and Rust codebases.

In that research, Rust had the same overall count of bugs and even some 'zero
day' sort of ones not any different from C++ and C codebases (maybe just
better than the C one).

Its a pitty i can find where it is (I´ve saw it on Twitter, but its pretty
recent).

> Chromium is an incredibly security-sensitive piece of software, and that
> really is an excellent fit for Rust. It's not a boogeyman argument and the
> Chromium team themselves are the ones pursuing it, it's not being forced on
> them.

A Chrome started from zero in 2020? probably.. but thats not the reality here.
Millions of lines of C++ code, and its not just a matter of language, but the
knowledge and people with the know-how to write those pieces..

Thats why im saying is not worth it..

~~~
mrich
You also have to consider the huge investment that testing takes. Not only
person days spent writing tests, but also infrastructure costs for running
fuzzers, huge test suites and so on. And although the code base is already
there and tested, it constantly changes, so there is no way to just
incrementally test it. At some point you have to make some advances in the way
you approach software development, not everything can be handled by brute
force.

~~~
oscargrouch
It would cost much more to rewrite in Rust.

Again thats why im saying that if the project would start now in 2020, all of
those would be pretty good points. Right now is too late for that.

As another example, you can get just the V8 VM for instance. For start, with
the ammount of solid code out there it would be nuts to talk over a rewrite..

Now imagine if we add to that, that the knowledge on JIT compilers is so
difficult to grasp, that you would also need to have those same great
engineers in the new language/platform you are planning the rewrite.

Giving the age of Rust, and giving you already have a bad time of finding
those in the much older C++, imagine the time it takes to have the same
quality people in Rust.

I know a lot of people are bully about Rust, but in reality things are not
that simple.

(On the bright side, is not that hard to taught a C++ engineer to code in
Rust)

~~~
roca
If you care about security, it is much easier to write non-exploitable code in
Rust than in C++, and you can hire accordingly.

Actually, the people who are really experienced at writing secure code in C++
understand that they can't do it reliably, and an increasing number of them
(like me) would much rather write Rust code instead for that reason. So for
secure code the hiring advantage is tilting away from C++ towards Rust.

~~~
rvz
Yet once the Chromium team goes down that Rust to C++ FFI route, they will
encounter the same old bugs outlined in this paper. [0] They might as well
fork Servo and create their own engine from that, but even that is still a
prototype worked on for years with zero C++ at least.

It's too early to see how the Chromium team will begin to work on this given
it's only a plan, but maybe the unsafety and security issues are enough
motivation to actually use Rust to C++ interop or a rewrite. But once again,
this has been tried by some other projects and by just looking at the effort
of a rewrite, they later concluded that it is not worth it. [1] [2]

Even better, just improve Servo instead. But I guess they would rather create
their own fork, just like they did with WebKit.

[0]
[https://arxiv.org/pdf/2003.03296.pdf](https://arxiv.org/pdf/2003.03296.pdf)

[1] [https://blogs.dust3d.org/2019/03/13/why-i-rewrote-the-
mesh-g...](https://blogs.dust3d.org/2019/03/13/why-i-rewrote-the-mesh-
generator-of-dust3d-from-rust-to-cplusplus/)

[2] [http://way-cooler.org/blog/2019/04/29/rewriting-way-
cooler-i...](http://way-cooler.org/blog/2019/04/29/rewriting-way-cooler-
in-c.html)

~~~
roca
None of this logic follows. Paper [0] categorizes bugs in unsafe Rust code.
"There will be some bugs in FFI code" does not imply "no benefit to using Rust
if there is C++ FFI". Many projects, including Firefox, have found Rust is
really helpful even if you have C++ FFI.

------
hoseja
TIL Rust doesn't have function overloading. But actually not sure whether this
is a good or bad thing.

~~~
ComputerGuru
I’ve been using it since pre 1.0 and I couldn’t tell you either. (Traits get
you most of the way there but you’d see them exist for no other purpose which
is just boilerplate imho.)

------
Const-me
Looks way too complicated. I think the reason is rust is not good at OOP.
Compare with my C# to C++ interop library, it can easily pass arbitrary
complicated types both ways: [https://github.com/Const-
me/ComLightInterop](https://github.com/Const-me/ComLightInterop)

~~~
kazagistar
The problems listed aren't the oop, they are the memory and thread safety
rules of rust, that prevent all the null pointer dereferencing and leaky
memory that a "dumb" C++ wrapper allows.

~~~
Const-me
Here's a quote from the article:

> We think the hardest part of this is imagining a safe way to pass types
> between Rust and C++. That requires auto-generated shim code on both the
> Rust and C++ side.

I'll be very surprised if they'll be able to make a production-quality
solution. The languages are just too different, and Rust's OOP support is one
of these issues.

