News for hackers. Stuff that matters.
Re:Rust and C++ Interoperability in Chrome by rightbyte on Wednesday August 19, 2020 @01:46PM (#24213440)
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.

Re:Rust and C++ Interoperability in Chrome by coder543 on Wednesday August 19, 2020 @02:32PM (#24214191)
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.

Re:Rust and C++ Interoperability in Chrome by lalaithion on Wednesday August 19, 2020 @03:36PM (#24215179)
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".
Re:Rust and C++ Interoperability in Chrome by rkangel on Wednesday August 19, 2020 @06:55PM (#24217813)
This is the right way of viewing it. What unsafe means to a person is fairly irrelevant. What it means to the compiler is 'please insert this code where I have checked the guarantees rather than you'.

Doing this a lot in pure Rust is a bad smell because you usually have other options and you're opening yourself up to risk. In this case the code exists and you already own all that risk so it's perfectly reasonable.

Re:Rust and C++ Interoperability in Chrome by foota on Wednesday August 19, 2020 @04:13PM (#24215696)
I think the issue is that rust unsafe means "does something sketchy" whereas even perfectly safe C++ would have to be annotated unsafe.
Re:Rust and C++ Interoperability in Chrome by est31 on Wednesday August 19, 2020 @06:29PM (#24217539)
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.
Re:Rust and C++ Interoperability in Chrome by foota on Wednesday August 19, 2020 @08:52PM (#24218712)
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.
Re:Rust and C++ Interoperability in Chrome by est31 on Wednesday August 19, 2020 @10:18PM (#24219219)
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.

Re:Rust and C++ Interoperability in Chrome by foota on Thursday August 20, 2020 @02:37AM (#24220507)
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.
Re:Rust and C++ Interoperability in Chrome by coder543 on Wednesday August 19, 2020 @03:55PM (#24215450)
> All of the things you say about C++ code also apply to unsafe Rust code.

Which is why unsafe is considered a code smell, and why people in the Rust community get upset when unsafe is used unnecessarily. That's why some people might find it controversial to hide the unsafety of the C++ code being used here. I've used Rust professionally for years, and I don't remember ever having to write any unsafe code in a professional context apart from FFI, and even then... the glue code to wrap around that unsafe FFI was very strictly written to make things as comfortable as possible for the FFI code and minimize the chance of bad things happening on the other side of the FFI barrier.

However, even then, your statement is not entirely correct. Unsafe Rust is extremely similar to safe Rust, enforcing the vast majority of safety requirements automatically. Unsafe code is very limited in what bad things it can do compared to C++ code.

https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#unsa...

- Dereference a raw pointer

- Call an unsafe function or method

- Access or modify a mutable static variable

- Implement an unsafe trait

- Access fields of unions

Those are the only things unsafe Rust can do that safe Rust can't. It doesn't turn off the borrow checker or anything else. There are a lot of mistakes that can be made in normal C++ code that you can't make in regular, safe Rust.

> 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".

The problem is that C++ compilers are much less capable of enforcing safety (inherently, due to legacy design decisions and backwards compatibility), so you often want a layer of glue code that only allows you to use C++ code in ways that are known to be safe, not just any arbitrary way that the function might be callable.

I already said I agree Chromium's team seems to be making the right call for this specific situation. It's not the right call most of the time. C++ code isn't fungible as being "just as good" as safe Rust code. The unsafety needs to be obvious, just like it is with unsafe Rust, so that you can recognize that the external C++ code (or unsafe Rsut) is a loaded footgun, and to treat it with appropriate care.

To be clear: Rust isn't a perfect language, and you can get the vast majority of the safety benefits by using almost any garbage collected language. What makes Rust awesome is that you can bring the memory safety of garbage collected languages into the realm of consistent performance requirements that previously was inhabited mostly by C and C++. Rust is a nice language, but so are a lot of other languages.

Re:Rust and C++ Interoperability in Chrome by jcranmer on Wednesday August 19, 2020 @04:59PM (#24216360)
> Those are the only things unsafe Rust can do that safe Rust can't. It doesn't turn off the borrow checker or anything else.

You can do serious damage with those things though. One tactic I have done is to expand the lifetime of a reference by laundering it through a raw pointer, since the function to convert a raw pointer to a reference allows you to choose any lifetime you want.

Re:Rust and C++ Interoperability in Chrome by coder543 on Wednesday August 19, 2020 @06:29PM (#24217544)
Yes, but good luck getting that through any form of code review. The unsafe block and the raw pointers or the call to transmute make it pretty obvious that something fishy is going on that’s worth reading carefully. ¯\_/(ツ)\_/¯

Unlike C or C++, where it can sometimes be harder to tell what the lifetime of something should be, or whether you’re extending the lifetime of a reference beyond the point that it is safe.

Unsafe definitely gives you loaded footguns... which for the umpteenth time is why it is considered a code smell. Sometimes you have to write smelly code, but it’s something to be avoided.

Re:Rust and C++ Interoperability in Chrome by jcelerier on Thursday August 20, 2020 @03:09AM (#24220684)
> Yes, but good luck getting that through any form of code review.

do you think more than a few percent of the "foundational" OSS projects where we find all the classical CVEs have any code review process ?

Re:Rust and C++ Interoperability in Chrome by bluejekyll on Wednesday August 19, 2020 @03:02PM (#24214679)
> Ideally, you build an abstraction around the unsafe interop layer that rigorously enforces every requirement

I think that’s the reason that doc discusses using cxx, right?

> 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.

I agree with you, but at the same time, I think in this context, single codebase, abstractions built by the teams making the guarantees at the FFI boundaries... it feels like they would meet the requirements here? It definitely is less strict than Rust, but the way I interpret it is that they are saying they will guarantee the C++ is safe behind the abstractions (maybe they can mark the C++ In some way to state this), and that’s not all that different than what we say in general in Rust when we claim an unsafe call is in fact safe when we wrap it in unsafe.

What I mean by mark, is potentially use some annotation in C++ that cxx would only call into when that annotation is present.

Re:Rust and C++ Interoperability in Chrome by coder543 on Wednesday August 19, 2020 @03:06PM (#24214731)
> I think that’s the reason that doc discusses using cxx, right?

cxx can only really do as much as the C++ compiler can. It's certainly better than nothing. In my experience, a non-trivial amount of C++ code will have additional requirements on how and when you're allowed to call various functions; requirements that aren't enforced by the compiler.

>> It might be the right call for this specific case, though.

> I agree with you, but at the same time, I think in this context, single codebase, abstractions built by the teams making the guarantees at the FFI boundaries... it feels like they would meet the requirements here? It definitely is less strict than Rust, but the way I interpret it is that they are saying they will guarantee the C++ is safe behind the abstractions (maybe they can mark the C++ In some way to state this), and that’s not all that different than what we say in general in Rust when we claim an unsafe call is in fact safe when we wrap it in unsafe.

That's why I said it might be the right call in this specific situation. Normally, I don't think this is the right approach, but it's probably the sensible thing to do here, especially since it's likely the same team of people on both sides of the FFI boundary.

Re:Rust and C++ Interoperability in Chrome by rightbyte on Wednesday August 19, 2020 @03:04PM (#24214706)
My point was that if you annotate code that's without the proper Rust guarantees because of cpp calls with a macro, you still can use the literal keyword "unsafe" and have it easily searchable for places where you use it because you have a good Rust internal reason. I.e. not to hide "unsafe" but to make it more clear where it is and because of what.

But they want "No C++ annotations". I believe they should have annotations in the Rust code to make it clear that the Rust/C/Cpp borders are crossed.

Re:Rust and C++ Interoperability in Chrome by steveklabnik on Wednesday August 19, 2020 @01:57PM (#24213621)
Rust does not have a textual substitution pre-processor, so like, you can do this sorta kinda but it would be way more involved.
Re:Rust and C++ Interoperability in Chrome by roblabla on Wednesday August 19, 2020 @02:19PM (#24213943)

    macro_rules! cpp_call {
        ($($tt:tt)*) => {
            unsafe { $($tt)* }
        }
    }
Yeah, not pretty, but it works :P
Re:Rust and C++ Interoperability in Chrome by rightbyte on Wednesday August 19, 2020 @04:59PM (#24216368)
Nature finds its ways.

Seriously though, maybe comment annotation would be better than abusing the macros like that. I though there was a more direct cpp way. (Edit: As in the c preprocessor, not C++.)

Re:Rust and C++ Interoperability in Chrome by luizfelberti on Wednesday August 19, 2020 @02:22PM (#24214010)
> Rust does not have a textual substitution pre-processor

Is that not pretty much what Rust's procedural macros are? [0]

Except for the fact that they do not allow emitting invalid token streams (which is something you don't want anyways), it can do any arbitrary manipulation of source code, but in a way that is integrated with the compiler and less prone to breaking the program.

[0] https://doc.rust-lang.org/reference/procedural-macros.html

Re:Rust and C++ Interoperability in Chrome by Arnavion on Wednesday August 19, 2020 @02:56PM (#24214578)
A proc macro would still need to be invoked as either

    cpp_call! { fn foo() { ... } }
or

   #[cpp_call] fn foo() { ... }
The former can be written even with a macro_rules macro. Regardless, both macros have to work by parsing the whole input tokentree `fn foo ( ) { ... }` and emitting it back with an `unsafe` prepended. The macro invocation cannot expand to just `unsafe`.
Re:Rust and C++ Interoperability in Chrome by steveklabnik on Wednesday August 19, 2020 @04:35PM (#24216039)
Yes, this is what I was meaning, thank you.
Re:Rust and C++ Interoperability in Chrome by qppo on Wednesday August 19, 2020 @02:47PM (#24214439)
its splitting hairs but not really. Rust's proc macros need to be explicitly invoked using special syntax at the usage site, either by annotating a statement or enclosing a block of tokens. On top of that, they do token replacement (or addition, with derive macros) which means they can only take valid input tokens as an argument (compared to macro_rules which can take arbitrary strings).

Textual substitution is less rigorous. It tells the compiler to replace a string with another, wherever it is seen. There's no restriction that it must be valid token input to be replaced or that it needs to be an explicit usage of the macro.

Re:Rust and C++ Interoperability in Chrome by ComputerGuru on Thursday August 20, 2020 @04:31AM (#24221155)
> Except for the fact that they do not allow emitting invalid token streams (which is something you don't want anyways)

Reminds me of some of stringification abused in the Linux kernel. What looks like a function call passing the literal text param1## as an argument, where it would then trigger a different stringification in a subsequent preprocessor pass that prepended ##foo to the passed argument.

Re:Rust and C++ Interoperability in Chrome by fullstop on Wednesday August 19, 2020 @02:30PM (#24214148)
I keep meaning to dive into Rust, but it feels like they've removed so many useful things in the name of safety.

I mean, I get it, these are all things which can be used to very easily cause chaos and shoot yourself in the foot. I look at code that I've written, though, and see so many challenges to writing the same thing in Rust.

I spend 99% of my time in embedded Linux or bare metal, though, so maybe my view point is a bit skewed.

There seem to be very few GUI libraries which can be used in Rust as well. I'll keep checking https://areweguiyet.com/

Re:Rust and C++ Interoperability in Chrome by ChrisSD on Wednesday August 19, 2020 @02:37PM (#24214273)
If you want to use a tool that pastes code fragments in arbitrary places you can. However, I'm not clear on the benefit over something that's aware of its context, or at the very least AST aware.
Re:Rust and C++ Interoperability in Chrome by qppo on Wednesday August 19, 2020 @03:04PM (#24214712)
Even modern C++ has eschewed macros for virtually every use case, the only reason I've had to use them (legitimately) has been conditional compilation and some compiler/platform specific issues.

Like if you're doing #define PI 3.14159 you're asking to get chirped in code review.

Re:Rust and C++ Interoperability in Chrome by rightbyte on Wednesday August 19, 2020 @04:49PM (#24216223)
Ye, everyone know it is:

    #define PI 3.1415927410125732421875
that is the float closest to pi or that there is the GNU extension USE_FUNKY_DEFINES-something with M_PI for cmath. (I know you meant constexpr:ions).
Re:Rust and C++ Interoperability in Chrome by Const-me on Thursday August 20, 2020 @07:12AM (#24222017)
Long time ago when computers were 32-bit I used to write something like this in C++:

    inline double pi()
    {
        __asm fldpi;
    }
On old enough compilers, this will get you 80-bit version of pi, more precision than even double. Completely useless now, modern compilers no longer emit x87 code.
Re:Rust and C++ Interoperability in Chrome by asveikau on Thursday August 20, 2020 @12:19AM (#24219845)
math.h has M_PI in posix.
Re:Rust and C++ Interoperability in Chrome by qppo on Thursday August 20, 2020 @12:31AM (#24219911)
The point is that using macros for constants is frowned upon in modern codebases, just like all other use cases for macros that break type safety and the one definition rule.
Re:Rust and C++ Interoperability in Chrome by asveikau on Thursday August 20, 2020 @02:04AM (#24220367)
Yes, I understand the point. But to your comment in a literal sense, if I were doing code review I would probably suggest using M_PI. Which happens to be a macro.

Which actually highlights that many things you want to use for practical purposes are C rather than C++, predate innovations such as const or namespaces, etc. It's possible and common to understand the downsides and still reach for the macro.

Re:Rust and C++ Interoperability in Chrome by steveklabnik on Wednesday August 19, 2020 @04:35PM (#24216037)
Just because we don't have textual substitution doesn't mean we don't have macros. We have a lot of macros!

(It took me a while to write back to you because I am busy writing bare-metal embedded Rust, btw. Including using some macros!)