|
|
Subscribe / Log in / New account

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

The Tor project, which provides tools for internet privacy and anonymity, has announced a rewrite of the Tor protocols in Rust, called Arti. It is not ready for prime time, yet, but based on a grant from Zcash Open Major Grants (ZOMG), significant work is ongoing; the plan is "to try bring Arti to a production-quality client implementation over the next year and a half". The C implementation is not going away anytime soon, but the idea is that Arti will eventually supplant it. The project sees a number of benefits from using Rust, including:
For years now, we've wanted to split Tor's relay cryptography across multiple CPU cores, but we've run into trouble. C's support for thread-safety is quite fragile, and it is very easy to write a program that looks safe to run across multiple threads, but which introduces subtle bugs or security holes. If one thread accesses a piece of state at the same time that another thread is changing it, then your whole program can exhibit some truly confusing and bizarre bugs.

But in Rust, this kind of bug is easy to avoid: the same type system that keeps us from writing memory unsafety prevents us from writing dangerous concurrent access patterns. Because of that, Arti's circuit cryptography has been multicore from day 1, at very little additional programming effort.



to post comments

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 9, 2021 20:46 UTC (Fri) by mss (subscriber, #138799) [Link] (19 responses)

Rust is a really good fit for this application.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 12:31 UTC (Tue) by sandsmark (guest, #62172) [Link] (18 responses)

Except for the problem with supply-chain attacks that now becomes a very serious concern and effort for Tor since Rust has decided that it should implement its own package manager.

Has anyone mapped and counted all the transitive dependencies that are now a direct concern for Tor?

And they trade a new, unproven code base in a language with relatively less understood concerns (except the growing supply chain attacks to my understanding) and tooling for a relatively battle-hardened codebase.

As always I'm grumpy and conservative but think gradually rewriting in modern and memory-safe (and thread-safe, you could even implement your own typesystem replicating the native rust approach) C++ is more sane.

That way you don't need to throw out all the tested and verified code you have, but can gradually modernize the code with more safe primitives.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 16:26 UTC (Tue) by mathstuf (subscriber, #69389) [Link]

There are efforts to help with that. Namely cargo-crev[1]. There are also efforts to use it in other package manager repositories. One can certainly set up a root of trust in the Tor repository and verify that the dependency tree contains only packages which are sufficiently reviewed and vetted by a trusted set of people. If you find a new one, you can decide whether to add it to the review pile or postpone the update to have a discussion with the library that is now bringing it in.

[1] https://github.com/crev-dev/cargo-crev

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 23:11 UTC (Tue) by roc (subscriber, #30627) [Link] (9 responses)

You cannot replicate the memory safety and thread safety checks of Rust with C++ types.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 14, 2021 6:06 UTC (Wed) by ncm (guest, #165) [Link] (8 responses)

But you can get equivalent safety by other means.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 14, 2021 11:06 UTC (Wed) by roc (subscriber, #30627) [Link]

Google, Microsoft, Mozilla have all decided they can't.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 14, 2021 15:28 UTC (Wed) by peter-b (subscriber, #66996) [Link] (6 responses)

> But you can get equivalent safety by other means.

Hi, C++ standards committee member here.

You can't get "equivalent safety" in C++ to Rust "by other means", because the Rust programming language can express abstractions that C++ cannot, and because Rust has different and irreconcilable semantics with respect to references which are necessary for the compile time checks that the Rust compiler performs.

If the type of "correct by construction" programming model that Rust provides is appealing, then I recommend adopting Rust. Insisting that C++ has equivalent safety is silly, because it does not.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 5:41 UTC (Thu) by ncm (guest, #165) [Link] (5 responses)

Yet, you can. The propaganda machine loves an underdog, but the great bulk of real work, by several orders of magnitude, is still done in C++, and will be for a long time to come.

C++ can express abstractions that Rust (still) cannot. But both languages are evolving rapidly.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 6:21 UTC (Thu) by roc (subscriber, #30627) [Link] (1 responses)

If you're going to contradict a C++ standards committee member when making a claim about the capabilities of C++, you'd better have some evidence to back it up. So, how do you achieve equivalence to Rust memory and thread safety with C++? (Don't say ASAN or TSAN, because those tell you nothing about untested paths.)

ncm

Posted Jul 18, 2021 21:53 UTC (Sun) by tialaramex (subscriber, #21167) [Link]

It seems plausible that ncm is Nathan Myers, who was, and perhaps still is, an active JTC1/SC22/WG21 (ie C++ Standards Committee) participant. In which case what you've got there is two experts disagreeing.

But we are on the Internet, and so it is of course also possible ncm is a dog (I have verified that the committee member was not a dog).

In the former case, maybe we can say Nathan is trying to get C++ to a better place. After all, I think implicit constructors were a bad idea, they're the wrong default, but they're only a default at all because of the "explicit" keyword, which is apparently Nathan's idea. So once the situation was "C++ constructors are inexplicably dangerous" and Nathan improved it to "C++ constructors are inexplicably dangerous by default". The correct fix (an "implicit" keyword) violates C++ backwards compatibility promises and (which of more practical upshot) breaks a bunch of working code. So "explicit" means as long as every C++ programmer is conscientious and never makes a mistake they avoid this particular footgun. "Hooray".

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 13:42 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

> C++ can express abstractions that Rust (still) cannot.

The one I know of is "template template" parameters (basically higher kinded types). I suspect concepts can get one higher-ranked trait bounds as well, but I'm not sure about that. FWIW, both of these are being worked on.

On the other hand, C++ lacks useful destructuring (pattern matching is being worked on, but I don't see it being anywhere near as ergonomic), is stuck with terrible macro expansion rules, bad move semantics, and a blissful unawareness of lifetime analysis at the language (as opposed to the documentation/review) level.

I know which set *I* find more useful, but that's obviously not all that universal since there are many niches in the programming space.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 17:11 UTC (Thu) by rgmoore (✭ supporter ✭, #75) [Link] (1 responses)

C++ can express abstractions that Rust (still) cannot.

This is trivially true, since one of the goals of Rust is to make it difficult or impossible to express some kinds of bugs. Greater expressivity is desirable only to the extent the things you're expressing are themselves desirable. Adding lots of foot guns makes the language more expressive, but in a way that's likely to make the final output worse rather than better.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 16, 2021 22:30 UTC (Fri) by marcH (subscriber, #57642) [Link]

Exactly.

C++ is safe, you're just "holding it wrong". Well, too bad a couple lines of code "held wrong" are enough for a vulnerability or elusive concurrency crash.

Standard committee-level discussions matter, but how that translates into what happens in the trenches matters even more.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 23:36 UTC (Tue) by tialaramex (subscriber, #21167) [Link]

Today, Tor is a bunch of C code. You'd have them rewrite it as "modern C++" rather than Rust.

That's a completely different set of skills. But wait, their core goal is they'd like a concurrent Tor. "Modern C++" still isn't very suitable for that. So, you propose they should "implement your own typesystem replicating the native rust approach" in order to have thread safety. So now it's an architecture astronaut project "Somehow replicate Rust in C++" when all they actually wanted was to write concurrent software, something Rust is famously good for.

You're right to be at least a little concerned about supply-chain attacks, but there Rust actually shrinks your window of concern. An apparently harmless C library can sneak in a backdoor pretty easily almost anywhere, but in Rust you'd have your work cut out. The biggest opportunity is procedural macros. Rust's declarative or "by example" hygienic macros aren't very dangerous, but procedural macros are powerful. Today arti uses a LOT of little crates and I agree it would be beneficial if it used fewer, better known, big crates that solve big problems and chose to copy-paste small useful ideas rather than pull in a whole crate for each one. And then sure, you would need to audit proc macros and some types of unsafe code in the crates used before you could trust the whole product.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 14, 2021 23:40 UTC (Wed) by mss (subscriber, #138799) [Link] (5 responses)

The issue that each new programming language seems to be coming with its own package manager is certainly real.
Python with pip, Node.js with NPM, Rust with Cargo...

These all try to re-implement the distro package repository with something which is often much less curated and supervised - clearly these are optimized much more for ease of use rather than quality or security.

But this is mostly a different issue from whether the code itself is C, C++ or Rust.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 6:10 UTC (Thu) by roc (subscriber, #30627) [Link] (4 responses)

Rust "cargo" definitely is not trying to "reimplement the distro package repository". Distro-packaged libraries come nowhere near cargo's capabilities --- e.g. feature selection, library version selection, the ability to substitute patched versions of libraries, the ability to run multiple versions side by side, the ability to publish libraries whenever you want and use them in any project immediately regardless of what Linux distro your users are running --- or, of course, if they're not running Linux at all.

When I'm writing software I'll decide what libraries and what versions of libraries I want to depend on. I'm not going to ask the Ubuntu maintainers to decide which libraries are OK for my project.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 23:14 UTC (Thu) by mss (subscriber, #138799) [Link]

For many people it's far easier to trust (and occasionally randomly verify) just one distro package repository rather than the distro one plus all the programming-language-related ones.
Especially that there were already some backdoored packages found in, for example, NPM and PyPI, so the threat is very real.

> When I'm writing software I'll decide what libraries and what versions of libraries I want to depend on.

Distros sometimes (often?) need to build and run a package against different library versions than its upstream supports (for various reasons).

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 15, 2021 23:46 UTC (Thu) by pizza (subscriber, #46) [Link] (2 responses)

> When I'm writing software I'll decide what libraries and what versions of libraries I want to depend on. I'm not going to ask the Ubuntu maintainers to decide which libraries are OK for my project.

Sure, you need pyFoo == 1.33.1 (or whatever)

Meanwhile, pyFoo includes a big pile of native C (or Rust, or whatever) code that itself has other dependencies.

How are those dependencies and sub-dependencies handled? (The answer: Quite badly, as in "It only works on a specific Ubuntu point release." Go ahead, ask me how I know this)

These language-specific repositories are great, until they inevitably have to reach outside the language ecosystem. Then it's hack upon hack until suddenly the distro system library/dependency model doesn't look so bad after all.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 16, 2021 0:20 UTC (Fri) by roc (subscriber, #30627) [Link] (1 responses)

Python is a mess.

Rust libraries that wrap a C library usually come with a "build script" (build.rs) that is capable of downloading, configuring, building and linking the C library. This works very well in practice, and is not a hack at all. The cc library (https://crates.io/crates/cc) gives you a nice API to help with this. A lot of these Rust libraries also give you the option of using the system version of the library if you want.

If the C code itself has dependencies that aren't available on the system then that would get complicated. I haven't encountered this problem in my Rust work. If I did, I guess I'd probably choose a different library.

> suddenly the distro system library/dependency model doesn't look so bad after all.

No, the model where distros package all libraries simply doesn't work at all for me, and lots of other developers, for the reasons I mentioned.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 22, 2021 10:42 UTC (Thu) by immibis (subscriber, #105511) [Link]

This sounds like it has exactly the same problem as Python. Does the build script work on every Linux distribution?

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 11, 2021 6:17 UTC (Sun) by ncm (guest, #165) [Link] (83 responses)

> But in Rust, this kind of bug is easy to avoid:

Another way to say this is that coding any sort of shared access in Rust is made artificially very hard, so that among all the myriad ways to code it that would work correctly and the other ways that would not, the compiler rejects all but one, and your task is to puzzle out exactly what that one is.

It is not accidental that the one way *does* work. But "easy" is in no wise a scrupulously accurate way to describe the process.

The satisfaction one gains in having solved the artificial puzzles the language imposes on top of each programming task can be easily mistaken for actual pleasure in using the language. This quirk of human psychology may be seen in many other activities, wherever unnecessary difficulty is treated as a virtue. The fanaticism that tends to result is the same in all cases.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 11, 2021 8:51 UTC (Sun) by ibukanov (subscriber, #3942) [Link] (17 responses)

Is it the same as suggesting that people stick with Rust due to Stockholm syndrome after being victims of the compiler strictness?

Given that all popular programming languages have own idiosyncrasies like a pleasure of debugging rare memory safety bugs in C++ or backporting Python code from older deprecated versions or refactoring huge JS code base without type annotations, the same can be said about all of them. The pleasure comes from the feeling of winning on the compiler/debugger/runtime, not from the language itself.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 11, 2021 10:47 UTC (Sun) by khim (subscriber, #9252) [Link] (13 responses)

> The pleasure comes from the feeling of winning on the compiler/debugger/runtime, not from the language itself.

Situation with Rust is different. Cases where compiler just doesn't know enough about your code to understand that it's valid are numerous, but after few months you just fix them automatically by adding lifetime annotations without even thinking much.

But cases where you don't know how to easily silence the borrow-checker… and need to “fight” it for real… 9 times out of 10 it's cases where compiler discovers some hidden problem in your design! Which would stay as source of hidden bugs for months or maybe years in most other languages! And for the remaining one case there are always unsafe.

That is why it's most loved language. Yes, it's hard to write code in it — especially for newbie.

But when you realize that it's because it does a lot to make sure your would spend minutes or hours fighting the compiler instead of weeks or months sitting in debugger… your attitude changes. Significantly.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 2:47 UTC (Mon) by ncm (guest, #165) [Link] (8 responses)

The time that Rust use can save programmers in debugging time varies enormously.

In my case, in the past decade I have spent strictly more time preparing compiler bug reports than in debugging memory usage errors. Rust, thus, could not possibly have saved me more than exactly that amount of time. Had I been coding Rust, instead, besides probably reporting many more bugs in its (then) immature compiler, I would have spent hundreds or thousands of times that long waiting on its (still today) very, very slow compiler. Much of that time would be in waiting to see, again, whether the compiler was yet satisfied with my lifetime annotations.

Thus, while it is easy to believe that using Rust reliably saves *some* programmers the time they would otherwise have spent on bugs they would have coded in another language, it is nowhere near correct to say it offers any such benefit to all.

The language's chief benefit might be, instead, for people using code written in it, reducing their worries about the quality of code they must run that is written by programmers whose diligence and care they have no good reason to trust, or have good reason to distrust. Those programmers, then, are in effect donating all the extra time they spend waiting on the Rust compiler for the peace of mind of that user. I am often that user, and I do not mind running programs coded in Rust, howsoever glad I am that I was not obliged to code them in it myself.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 5:44 UTC (Mon) by xophos (subscriber, #75267) [Link] (5 responses)

So you are either one of the very rare programmers whose mental capacity is sufficient to write C/C++ code without introducing soubtle memory errors.
In that case: good for you!
Or, nobody has tried to break your code yet.
But either way, most of us are not so gifted/lucky and are very greatful indeed for any help the compiler can give us.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 16:56 UTC (Mon) by ncm (guest, #165) [Link] (4 responses)

There is, in fact, no such language as C/C++.

I am also very grateful for help the compiler gives you.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 7:23 UTC (Tue) by immibis (subscriber, #105511) [Link] (3 responses)

In this case, the slash means "or"

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 14, 2021 6:15 UTC (Wed) by ncm (guest, #165) [Link] (2 responses)

No, it conceals a falsehood.

The practice of writing code in C++ is wholly different from writing C code. In particular, writing C++ code without introducing subtle memory errors is orders of magnitude easier, and mistakes in C++ are orders of magnitude easier to spot (i.e., just look for code that looks like C), and not at all tempting.

Saying "C/C++" is meant to mislead by implying a false equivalence.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 14, 2021 11:08 UTC (Wed) by roc (subscriber, #30627) [Link]

Thanks to features like references, lambdas, and various unfortunate standard library features, "modern C++" actually makes it very easy to introduce dangling references and other memory safety issues. See https://github.com/isocpp/CppCoreGuidelines/issues/1038 for an example.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 22, 2021 10:43 UTC (Thu) by immibis (subscriber, #105511) [Link]

No, it simply means "or". As in:

> So you are either one of the very rare programmers whose mental capacity is sufficient to write C or C++ code without introducing subtle memory errors.

These are both languages where it's possible to introduce subtle memory errors, and the statement suggests that the person in question is capable of understanding their program's memory management well enough to not introduce them.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 9:02 UTC (Mon) by khim (subscriber, #9252) [Link]

> In my case, in the past decade I have spent strictly more time preparing compiler bug reports than in debugging memory usage errors.

Were these bug reports accepted and fixed? Or were they closed because, apparently, you have triggered some kind of “undefined behavior” and thus compiler writers closed these bug reports as “invalid”?

In my experience it's not that hard to write correct code in C, C++, Python or any other sane language (not Barinfuck) as long as you are working alone (except where your idea of “undefined behavior” doesn't match the idea of “undefined behavior” of compiler writers).

But when you start changing code whose design is not yours… you start breaking it. Simply because you don't know it by heart. And that is when you start spending more debugging things than writing them.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 15:22 UTC (Mon) by Hattifnattar (subscriber, #93737) [Link]

> I have spent strictly more time preparing compiler bug reports than in debugging memory usage errors.
But is this because your code does not have memory usage errors, or because you just don't know about them (perhaps they are hard to trigger in normal usage)?
Do you know?
*How* can you be sure?

Also, do yo parallelize your code (a) never, (b) as the last resort, or (c) every time there is even a chance it will benefit the performance?..

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 9:19 UTC (Mon) by NAR (subscriber, #1313) [Link] (1 responses)

need to “fight” it for real… 9 times out of 10 it's cases where compiler discovers some hidden problem in your design! Which would stay as source of hidden bugs for months or maybe years in most other languages!

It sounds similar to dialyzer results on Erlang code. Dialyzer is always right, so when the programmer doesn't understand its complaints, it's usually a real bug. On the other hand, in my experience these bugs are 95% on (not tested) error handler code paths or simply unused/unreachable code, because most of the real bugs are found by tests.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 11:19 UTC (Mon) by khim (subscriber, #9252) [Link]

> On the other hand, in my experience these bugs are 95% on (not tested) error handler code paths or simply unused/unreachable code, because most of the real bugs are found by tests.

But error handling is precisely where such things are important. Precisely because these are rarely tested yet often are lucrative targets for attackers.

Rust developers have tendency to just plug these with panic!… but that's still a step forward from what happens in C/C++ programs.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 11:34 UTC (Mon) by ballombe (subscriber, #9523) [Link] (1 responses)

By that measure, I am quite sure Haskell is more loved than rust!

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 14:12 UTC (Mon) by khim (subscriber, #9252) [Link]

Nope. Haskell is ahead of C/C++ or Java, of course, but significantly behind C#, Go, Python or Swift. Look for yourself.

In case of C or C++ one can explain that it's because people are forced to use the language they hate, but I don't think anyone is forced to use Haskell (at least I haven't heard about such cases).

Rust have become “most loved” after it's developers proposed stability without stagnation course. And while “after” doesn't mean “because” I suspect it's one very important thing which distinguishes Rust from Haskell.

While modern GHC-Haskell is immensely power language… it has no good tutorials and when you try to learn it and find out that you couldn't even type examples from existing “recommended” books and run them without modifications… it's frustrating… compare it with The Book which says, right now, This version of the text assumes you’re using Rust 1.50 or later with edition="2018" in Cargo.toml of all projects to use Rust 2018 Edition idioms.

Although everyone admits that Haskell is more powerful language at the moment (heck, even Haskell 98 includes higher-kinded types, which Rust lacks today) but from practical POV good async story is more important than higher-kinded types — that's why Rust tries to build solid async story while higher-kinded types remain an experiment…

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 1:02 UTC (Mon) by ncm (guest, #165) [Link] (2 responses)

"Stockholm syndrome", if there really is such a thing (there is disagreement), seems more like a personal connection that grows naturally between people, even if practical enemies, sharing emotionally charged circumstances.

The essential difference from the other examples cited is that the difficulty overcome in those cases is not artificially imposed by the design of the language. The craft of programming is filled with abundantly multifarious technical challenges; it could almost be defined by them. But most usually, challenges are imposed by the problem domain; and we like a language best for how it keeps out of our way, not for its imposing extra difficulties on top of what the problem provides.

The other place in programming where we see the particular flavor of enthusiasm seen (in some) for Rust is around Forth, described as "the first Programming Religion". In Forth, the built-in hurdle to be repeatedly overcome (IIUC) is arranging that the values to be operated upon are on top of the evaluation stack exactly when they are needed, and so need not be named. Forth's affinity to the native primitives of computation make elegantly expressed Forth also approach the most efficient possible sequence of operations, and thus approach a sort of Platonic ideal.

We might thus call Rust "the Second Programming Religion". In saying so, we should be careful to distinguish enthusiasm for the many good qualities of the language design (typically enabled by leaving behind old mistakes) from the fanaticism of the Convert. The latter can be perceived most readily in its adherents' need to disparage other languages, to exaggerate the practical value of specific details and the practical importance of the language, and to minimize emergent flaws perforce retained for backward compatibility.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 22:50 UTC (Mon) by notriddle (subscriber, #130608) [Link]

> We might thus call Rust "the Second Programming Religion".

Fourth. The first is Forth, the second is LISP, and the third is Smalltalk.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 20, 2021 8:55 UTC (Tue) by anton (subscriber, #25547) [Link]

Yes, religion is a more appropriate analogue for the attachment that programmers feel to programming languages than Stockholm syndrome. Another phenomenon that may explain the attachment is choice-supportive bias (and that may also be related to religion).

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 11, 2021 8:52 UTC (Sun) by Sesse (subscriber, #53779) [Link] (12 responses)

I usually split languages and APIs into “makes the easy things easy” versus “makes the hard things easy” (it's surprisingly difficult to placate both). The greatest APIs also have the ability “makes the right things easy, makes the wrong things hard” (and PHP is “makes the wrong things easy”), so I guess maybe Rust is “makes the wrong things very hard” :-) There's a value in it, though.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 3:57 UTC (Mon) by ncm (guest, #165) [Link] (11 responses)

The quality we most value in APIs is to make simple things easy, and complicated things possible. Too often, instead, simple things are made complicated, and complicated things impossible.

Making wrong things hard to express is valuable where we are tempted to wrong things. Thus, we would like for people tempted to wrong things to learn Rust. Our problem is that people tempted to wrong things are typically not tempted to learn Rust.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 16:51 UTC (Tue) by NYKevin (subscriber, #129325) [Link] (10 responses)

> Our problem is that people tempted to wrong things are typically not tempted to learn Rust.

That's not a bug, that's a feature. If you write your app in Rust, you will filter out those people automatically.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 18:22 UTC (Tue) by rgmoore (✭ supporter ✭, #75) [Link] (9 responses)

This depends on how you look at it. If you are only interested in one project, filtering out bad programmers seems like a good idea-- so long as you can still get enough good programmers to do the job. But if the goal is to improve programming as a whole, having the people who most need the benefits of a new approach be unwilling to use it is unfortunate.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 17, 2021 20:52 UTC (Sat) by marcH (subscriber, #57642) [Link] (8 responses)

It depends how programmers are "filtered out". For free time projects you're right. But when all businesses tired of ramsomware and other malware finally connect 70% of security incidents with the language of memory corruption and finally ask their providers "Wait, what language did you code this in?", then it won't be up for programmers themselves to decide. Money will talk. Very few programmers get to decide what language is used in $DAYJOB.

BTW Rust is of course not the only memory safe language and this "no memory corruption" trend has started already, after all Java/Kotlin, Javascript, Swift and golang are already very popular. What's new with Rust is filling the last gap where C and C++ had no serious competition. That's why its zealots feel threatened.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 17, 2021 21:31 UTC (Sat) by pizza (subscriber, #46) [Link] (7 responses)

> For free time projects you're right. But when all businesses tired of ramsomware and other malware finally connect 70% of security incidents with the language of memory corruption and finally ask their providers "Wait, what language did you code this in?", then it won't be up for programmers themselves to decide. Money will talk. Very few programmers get to decide what language is used in $DAYJOB.

I'd love to see an actual citation for that "70% of all security incidents" thing.

For example. The largest data breach in history (Equifax) was due to an unpatched Apache Struts deployment, written in "no memory corruption" Java.

Phishing and general credential theft? Social engineering, not memory corruption.
Ransomware? Social engineering and MS Windows treating "opening documents" the same as "executing a binary" (along with awful UI design so the user genuinely can't tell the difference most of the time), not memory corruption.
SQL injection & XSS vulnerabilities? Improper validating/escaping inputs, not memory corruption
SSH/SSL downgrade attacks? Protocol misdesign, not memory corruption
IoT botnets? Hard-coded passwords/backdoors, not memory corruption

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 17, 2021 22:34 UTC (Sat) by ms-tg (subscriber, #89231) [Link] (6 responses)

Hi pizza,

> I'd love to see an actual citation for that "70% of all security incidents" thing.

Here's the citation I am aware of:

* Matt Miller, an engineer at Microsoft, presented the following talk at the conference Bluehat 2019 in Israel:
- VIDEO: https://www.youtube.com/watch?v=PjbGojjnBZQ
- SLIDES: https://github.com/Microsoft/MSRC-Security-Research/blob/...

As an aside: this appears to be the same conference at which Andrew "bunnie" Huang delivered the talk "Supply Chain Security: If I were a Nation State…", which I think I also read about here at LWN.

It appears that the citation for the 70% statistic starts at 14:05 into the talk, which corresponds to Slide 11.

Graph shows a period of 12 years, 2006-2018, showing that around 70% of "security vulnerabilities addressed by a security update" each year correspond to a memory safety issue. Subsequent slides break those down further into classes of memory safety issues.

Hope this helps!

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 17, 2021 22:43 UTC (Sat) by ms-tg (subscriber, #89231) [Link]

Further googling also reminds us of the following additional citations that may be of interest:

* Microsoft Security Response Center: A proactive approach to more secure code
https://msrc-blog.microsoft.com/2019/07/16/a-proactive-approach-to-more-secure-code/
(repeats same graph and statistic, introduces the case for Rust in that context)

The connection between the cited statistic, and Microsoft's exploration of the Rust language, appear to have been widely covered in all sorts of media, for example:

* https://www.zdnet.com/article/microsoft-to-explore-using-...

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 18, 2021 1:39 UTC (Sun) by pizza (subscriber, #46) [Link] (3 responses)

> Graph shows a period of 12 years, 2006-2018, showing that around 70% of "security vulnerabilities addressed by a security update"

Ah, okay, so that's "70% of security vulnerabilities" -- which is *not* the same as "security incidents".

(As the 7th & 8th slide in that deck demonstrates, there is a considerable gap between "vulnerabilities" and "exploits", and the 9th slide says the "market" has moved predominantly to social engineering-based attacks instead)

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 18, 2021 16:48 UTC (Sun) by marcH (subscriber, #57642) [Link] (2 responses)

> Ah, okay, so that's "70% of security vulnerabilities" -- which is *not* the same as "security incidents".

Is the former acceptable?

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 21, 2021 17:27 UTC (Wed) by pizza (subscriber, #46) [Link] (1 responses)

> Is the former acceptable?

"Acceptable" is just a point on the cost/benefit curve.

Clearly it has been acceptable. And, to be blunt, it will continue to be, for the same reason that the financial industry still runs on COBOL -- Rewriting the billions of lines of existing "inherently unsafe" code into "memory-safe" languages will cost a *lot* more money (and introduce far more new bugs along the way) than the current practice of (semi-proactively) plugging holes and cleaning up messes after the fact.

The costs of "security vulnerabilities" are nearly always external (ie someone else's problem). That vulnerability only becomes an "incident" is when an organization directly incurs some cost. Until then, it will be ignored unless an external entity (eg government regulation or payment card or insurance carrier requirement) forces an organization to proactively care.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 21, 2021 22:25 UTC (Wed) by marcH (subscriber, #57642) [Link]

> > Is the former acceptable?

> "Acceptable" is just a point on the cost/benefit curve.

Sure, what I meant was: should anything at all be done about memory corruption? The answer is yes of course - and it is being done in some places and not just with Rust. Exciting times.

> Until then, it will be ignored unless an external entity (eg government regulation or payment card or insurance carrier requirement) forces an organization to proactively care.

In general yes of course but there a few exceptions like Microsoft, Google and a few other "SmallTech". Check the Microsoft slides linked above.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 19, 2021 2:36 UTC (Mon) by marcH (subscriber, #57642) [Link]

This is a very interesting presentation, thanks for sharing it! I enjoyed it because you really don't need to be a security expert to make the most of it, you "only" need to be a software engineer.

Among others it explains why attacks rely less often on vulnerabilities and more on other techniques like social engineering. It's not because there was much coding and quality progress, in fact it rather depressingly states that developers keep making the same mistakes as before. The main reason is because Microsoft fixes them much faster than ever and made it very difficult to turn off auto updates. This gives a very strong incentive to minimize usage of vulnerabilities and reserve them for discrete, targeted attacks. Auto-updates have basically changed the market of vulnerabilities, their value has increased to the point where only nation states or very rich actors can afford them. I'm over simplifying of course, open the PDF if you're interested in the actual numbers.

So I stand corrected: the connection between ransomware and memory safety is probably tenuous... _if_ you use aggressively auto-updated software exclusively!

https://www.theverge.com/2021/1/6/22217052/microsoft-wind...
(Windows 7 is still running on at least 100 million PCs)

As long as you're not a high profile target or you don't mind getting spied on by any government or other powerful actor, keep using software written in a memory corruption language. Just make sure there's a billion dollars company constantly racing to keep it up to date.

Also keep in mind this analysis is based on Microsoft's data only.

Another interesting point is how effective but still limited mitigations like CFG, CET,... are and how the only way to make them 100% effective "decomposes to needing to solve memory safety".

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 11, 2021 10:33 UTC (Sun) by khim (subscriber, #9252) [Link]

> The satisfaction one gains in having solved the artificial puzzles the language imposes on top of each programming task… has nothing do with Rust.

Shared access is hard. Intrinsically. It's hard in C, Java or even if you just directly write the machine code. Simply because when one variable have two owners than none of them can ever be sure they know what value is stored in that variable at any given time. You have to have some kind of protocol which ensures synchronization (there are bazillion articles on LWN alone which explain how you can do that in different cases).

Language which makes that notion explicit and makes the compiler do the verification for you in 99% of cases is boon, not trouble.

And for cases where you really need shared access there are always unsafe.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 11, 2021 13:33 UTC (Sun) by flussence (guest, #85566) [Link]

It's easy in the same sense constructing a skyscraper is easy, because the regulations written in blood have already been done for you.

Ownership and lifetimes

Posted Jul 12, 2021 1:02 UTC (Mon) by tialaramex (subscriber, #21167) [Link] (47 responses)

After a few weeks writing some Rust, I have been puzzled about this sort of response because it came easily to me.

Was I just much better at programming than I realised all this time? Were the (numerous) people expressing such opinions outliers who are amplified beyond their true numbers?

For a while I read material suggesting that these takes are inspired by earlier Rust versions where the compiler is much less able to infer your intent. If you learned Rust a few years ago there were a lot of places where you must spoon feed the compiler, spelling out very obvious things about your program that today's compiler just gets right. So perhaps people with these takes are just responding to an infelicity which has since been eased, and similar improvements continue today (e.g. arrays got nicer in 1.53). But I don't think that's it.

I think it's a little of that first thing I mentioned but in a very narrow way. All this time I've had this concept of ownership for non-trivial objects, in languages like C that didn't really express it. So, to me this behaviour in Rust matches the mental model I already had. Of _course_ it matters whether this QuadResourceAnswer owns the Quads or just refers to them, and now that my programming language actually cares as much as I did that's actually reassuring. Of _course_ it matters whether the thing we matched in the String lives as long as the String or the Regular Expression doing the matching and again it's reassuring that now my programming language cares too.

If you're the sort of programmer who was excited about Owner<> (which doesn't actually _do_ anything on its own) in the C++ support library, and who has strong opinions (whatever they are) about whether raw pointers are owning, or not owning, you're more likely to think Rust just makes sense, and these responses are crazy.

Whereas I suspect that for ncm and many of those who see Rust this way, it's a bicycle for fish. They've never worried about ownership before, how could that have been the secret ingredient all along, surely they'd have realised and incorporated it into their thinking?

Ownership and lifetimes

Posted Jul 12, 2021 1:52 UTC (Mon) by rodgerd (guest, #58896) [Link]

> I have been puzzled about this sort of response because it came easily to me.

When a practitioner has mastered solving problems in particular ways with particular tools, it can be almost impossible to unpick how they do things to relearn them another way - particularly because it's psychologically difficult to simply discard knowledge that may no longer be necessary. The more tinkering is required, the more attached one becomes to the thing, because one's expertise has become the work-arounds, rather than solving the nominal problem.

I've had a similar visceral skepticism to (for example) moving away from sysv init, or challenges to "everything's a text" ways of thinking. If you've adjusted your mental model to think that parsing the different output of *ix tools way of describing the same thing is normal and natural and good, a competing model is heresy!

Expertise can be a trap, because sometimes it's misplaced.

Ownership and lifetimes

Posted Jul 12, 2021 3:28 UTC (Mon) by ncm (guest, #165) [Link] (45 responses)

It is not hard to understand enthusiasm in someone coming to Rust from C, where the mental load one must carry to prevent errors, or (failing that) the time spent detecting and fixing them, is necessarily very large. I spent years coding C; while I spent little time on bugs, the burden of preventing most of them was one I was happy to to hand over to my (C++) compiler and libraries.

Ownership is something everybody who deals with pointers learns to understand and deal with very early; the notion that anybody experienced does not is beyond absurd. If you already thought about ownership in precisely Rust's way, you will have found its convention easy to adopt. But there are other ways that also work, sometimes better than is permitted in Rust.

Not having the problems that Rust prevents makes time the Rust compiler takes, to gnaw its slow, ponderous way through your code, into time wasted.

Ownership and lifetimes

Posted Jul 12, 2021 7:39 UTC (Mon) by Sesse (subscriber, #53779) [Link] (4 responses)

FWIW, the concept of ownership was entirely new to me when I was introduced to it at work, and I had coded C and C++ for ten years or so before that. It made _sense_, sure, and it didn't feel like a huge revelation at the time (it was largely an extension of what was already going on in C++ for non-pointers), but I had always thought of freeing as something that was done by code, not by data.

Ownership and lifetimes

Posted Jul 12, 2021 9:40 UTC (Mon) by khim (subscriber, #9252) [Link] (2 responses)

It goes back to Linus saying (old one, predates Rust):

> I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.

Which is version of that one from The Mythical Man Month (that one is half-century old, as you know):

> Show me your flowchart and conceal your tables, and I shall continue to be mystified. Show me your tables, and I won't usually need your flowchart; it'll be obvious

Also: most ideas which Rust enforces mirror what so-called “modern C++” (with owners and ownership passing) and, surprisingly enough, “modern kernel C” proposes with it's sparse tool, ownership trees and other such things.

Also: very small, very limited “fuzzing with coverage” finds so many violations of these rules in most large codebases (like Chromium or Linux kernel) that Linux kernel developers just started “la-la-la don't see anything” game (till people started using them to create actual working exploits at which point they have started taking notice).

IOW with Rust I had the exact opposite experience from what @rodgerd talks about: I already was familiar with concepts and their importance… just hated Rust syntax (still do, BTW).

And this makes me wonder about what exactly are you doing with C and C++ that “concept of ownership was entirely new to you”… and how you ensure that proper cleanup is done in case of failures.

Ownership and lifetimes

Posted Jul 12, 2021 10:54 UTC (Mon) by Sesse (subscriber, #53779) [Link]

I can't recall what code I wrote around 2005 or so :-) I'm just saying that this isn't a concept everyone working with pointers “learns to understand and deal with very early”. My code certainly passed leak checkers in the cases that I cared about it, but I will not claim it was without bugs. The notion of ownership is a good one, and I'm glad Rust embraced it—but obvious, it is not. Even C++ didn't really bake it into the standard library before C++11 and unique_ptr; auto_ptr was the only real attempt at RAII before that, and it was deeply flawed and generally shunned.

Ownership and lifetimes

Posted Jul 18, 2021 18:44 UTC (Sun) by marcH (subscriber, #57642) [Link]

> > I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.

I think this is because when you read a piece of code, the difficult and error-prone part is the "stateful" part. A child can understand a one page-long function as long it's "pure" with only explicit inputs and outputs and no side-effect; it's "just maths"!
https://en.wikipedia.org/wiki/Referential_transparency

But good luck when that one page-long is updating some complex data structure that persists before and after the code is run. Then you need to keep in your head a lot more context and information that is not directly visible on the screen. If on top of that you also need to remember what other pieces code could be performing on the same data _at the same time_ then it's game over for most people and even for the smartest is much more cognitive strain. See excors's comment about locks etc. at https://lwn.net/Articles/862591/

This is also why writing hardware code is IMHO "harder" than software: hardware design is all about managing a huge number of concurrent states.

It's about time low-level software takes some elevation and safe (!) distance from hardware design and stops mimicking it because unlike hardware, software has no reason to burden developers with so much micro-management of data states and side effects. Instead, tell the compiler or static analyser who owns or borrows what data and when and let it find the bugs. Yes, that makes compilation much longer but that time is nothing compared to error-prone code reviews that often don't happen because no time has been planned for them. Let the machines do the tedious work, they're so much better at it.

Ownership and lifetimes

Posted Jul 14, 2021 6:23 UTC (Wed) by ncm (guest, #165) [Link]

> "the concept of ownership was entirely new to me"

This is a transparently false statement.

Either you routinely leaked, double-freed, and/or used memory after freeing it, OR you (or somebody directing you) exercised a rigorous ownership policy. It is not surprising that you have forgotten all about it all since moving to more automated tooling.

Ownership and lifetimes

Posted Jul 12, 2021 10:02 UTC (Mon) by tialaramex (subscriber, #21167) [Link] (39 responses)

So, since it was closest, I consulted Bjarne Stroustrup's "The C++ Programming Language" in its Second Edition from 1991

Stroustrup's long tedious book has no section about ownership. Its awful - presumably machine-generated - index lacks entries for ownership, owning, or related words. Stroustrup's periodic rants about style or philosophy of programming did not seem to (in the time I had to re-read them for this comment) mention the idea. It was, I will thus claim, "Not top of mind". Multiple inheritance was important to Stroustrup. Overloading the pointer reference operator was important. Ownership? Never warrants a mention.

Years later the eventual standard C++ has a smart pointer, auto_ptr. But, auto_ptr doesn't reflect the idea of ownership. If anything it muddies the water, a program with auto_ptrs is confusing, or worse, confused, about what is owned and who by.

So in 2011 (ten years ago) C++ gets unique_ptr, shared_ptr, weak_ptr and so on. These, at last, reflect ownership. The unique_ptr owns the thing to which it is a unique pointer, a weak_ptr explicitly doesn't own anything. But C++ 11 still also has and uses raw pointers, and by this point C++ programmers are also using a lot of references, some of them believe references imply ownership, others the exact opposite. Worse, programs are entitled in C++ to just extract the raw pointer from all these smart pointers except weak_ptr (where for obvious reasons there might sometimes not be a raw pointer) and they do.

Only when you look at work proposed for future C++ do you see the sort of enlightenment about Ownership that Rust has.

And that's only half the story. I titled my comment "Ownership and lifetimes". While C++ grew some ideas about Ownership ten years ago, it still doesn't have Lifetimes. Bjarne has proposals, with straw man implementations for the basic idea, but I'd be astonished if (modulo ongoing concerns that Rust is eating their lunch) his feature makes it into C++ 23 because C++ is today a very Conservative programming language, much more ready to find reasons to do nothing than to change and grow.

Finally, you are concerned that Rust compilation is too slow. One of the reasons C++ in particular is able to be fast is a reckless, almost outright negligent approach to basic engineering. The One Definition Rule. To enable the compiler to process as many translation units as it likes, simultaneously and without communicating, C++ has a rule which says that a C++ program must only have One Definition for symbols visible from multiple translation units. This doesn't feel so bad right? Surely you will get an error from the compiler if you violate this rule? Nope. The compiler can't be sure it will ever notice, and if it doesn't the resulting binary is nonsense. That's why the ODR exists. As a result, C++ has "False positives for the question: Is This A Program?". This is clearly awful software engineering. But it _is_ faster for whatever that was worth.

Ownership and lifetimes

Posted Jul 12, 2021 15:30 UTC (Mon) by khim (subscriber, #9252) [Link] (13 responses)

I think ownership is similar to zero and negative numbers. Romans have built very powerful and engineering-savvy (by ancient standards) civilization. Without knowing zero. It took centuries for it to travel from India to the West. Negative numbers took even longer.

Yet today these are something we learn in school or even preschool.

Similar, but more recent, example: two's complement numbers. They were used by EDSAC ¾ century ago. Today they are “no brainer”, everyone uses them.

Yet when in 1989 C standard was written they were not established enough for the C standard to define signed overflow result! It was declared an “undefined behavior” and it was opinions about them started that long feud between C compiler developers and C developers…

In the other post ncm talks about backward compatibility as the reason why Rust feels much safer than C or C++. But what kind of backward compatibility can be affected if you just say “it's no longer an undefined behavior to add MAX_INT and 1”?

On the contrary: the whole reason switch from C/C++ to Rust is contemplated (although not guaranteed, obviously) is because C/C++ compilers treated it's users as “captive audience” for so long: while they retained “theoretical backward-compatibility” (as in: nonexistent code which never triggers obscure “undefined behaviors” which hardware and OS define precisely — should work after compiler update) they broke “practical backward-compatibility” (as in: code which was tested and ironed-out by decades of development was suddenly declared “non-compliant” and was broken).

Rust was never intended as actual C++ replacement (although today a lot of people are actually contemplating if that may be possible or not) but it follows Linus rules to the backward compatibility: The rule is not "we don't break non-buggy user space" or "we don't break reasonable user-space". The rule is simply "we don't break user-space". Even if the breakage is totally incidental, that doesn't help the _user_. It's still breakage. With addon breaking user space is a bit like trees falling in the forest. If there's nobody around to see it, did it really break?

Yes, before they can adopt such a stance they needed to spend almost a decade ironing out problems in the basics of Rust and making sure actual programs which are built against stable Rust features wouldn't contain too many crazy things. C and C++ always allowed crazy programs thus declaring exactly this principle is, probably, not possible.

But complete and utter disregard to expectations and use of C and C++ by real programmers definitely triggered the crisis. Ultimately, after enough breakages, which were dismissed with “hey, standard allows us to do what we do, go fix your 20-years old code” it painted C/C++ compiler developers not as C/C++ developer friends, but as adversaries.

The end result: after long, hard, really arduous process C/C++ compiler developers have finally brought C and C++ to the point where collection of artificial puzzles the language imposes on top of each programming task (all these “don't ever rely on two's complement arithmetic even if it's guaranteed by standard”, “never do arithmetic on nullptr”, “never pass null as reference”, “never use std::move to return value from function… but don't forget it in other places”… and so on) for C++ have become larger than what Rust demands.

Also: when you are doing “bad things” in C/C++ your punishment is often much harsher: instead of getting clear and simple compiler errors you observe how your program turns into pile of goo.

But it's 100% truth: if Rust would ever replace C/C++ then it would be shared effort where achievements of C/C++ compiler developers at making C/C++ insanely, unaffordably, dangerous would be regarded as critical step.

Ownership and lifetimes

Posted Jul 12, 2021 17:51 UTC (Mon) by ncm (guest, #165) [Link] (1 responses)

What a rich fantasy world khim lives in. It hardly makes any contact with objective reality, but clearly has no need to.

It is clever to add links to other postings, and wholly invent remarks to pretend to quote from them. It is even more clever to invent things that must surely have happened before he was born. But it is not clear why anyone should try to tease out the few, lonely correct statements that accidentally appear in the roiling cloud of phantasms presented.

Speaking of lifetimes

Posted Jul 12, 2021 18:05 UTC (Mon) by corbet (editor, #1) [Link]

...perhaps the lifetime of this particular thread has run its course. I don't see anything good coming from this kind of discussion; let's stop here.

Thank you.

Ownership and lifetimes

Posted Jul 12, 2021 18:52 UTC (Mon) by JanC_ (guest, #34940) [Link] (9 responses)

The reason why signed overflow results are “undefined behavior” in C is that it was implemented differently in various hardware, and the C language didn’t want to force compiler makers to have to introduce slow workarounds on any of that hardware.

Ownership and lifetimes

Posted Jul 13, 2021 10:34 UTC (Tue) by khim (subscriber, #9252) [Link] (8 responses)

This was logical back 1989. Today only two's complement representation is supported and all relevant CPUs handle overflow just fine.

And if compiler developers worry about benchmarks then they can always use an appropriate switch to restore obsolete behavior.

The problem with C/C++ is not certain peculiarities with misunderstandings about some complex corner-cases (it's inevitable when complex systems are involved) but absolute conviction of compiler developers in the fact that “mere users” don't even deserve a discussion.

“It's my way or the highway” attitude permeates the discussion. Well… Rust looks like a nice place on the highway, so maybe it's time to pick 2nd option.

Ownership and lifetimes

Posted Jul 13, 2021 20:51 UTC (Tue) by mrugiero (guest, #153040) [Link] (7 responses)

No, it was not 100% logical in 1989 and it is not 100% logical in 2021. C doesn't just have defined and undefined as categories for behavior. There's also implementation defined. That was really the best choice in this case, I think. This is because implementation defined still means the platform+compiler must make a promise about it. What the promise is is up to them, but they have to be consistent about it. They can also have some extra guarantees, just like `int` size and representation is implementation defined but is guaranteed to be able to represent the range [-2^31,2^31). So, if I know I'm building for ARM64 on Linux with GCC I could have *some* guarantees about integer overflow, even if they are not the same as MSVC on x86 for Windows. This would suffice to avoid these slow workarounds, while not making programmers bend backwards to avoid it altogether.

Ownership and lifetimes

Posted Jul 14, 2021 9:24 UTC (Wed) by khim (subscriber, #9252) [Link] (6 responses)

If I understand correctly they wanted to support systems where signed overflow causes a trap without introducing a ways to intercept that trap. But declaring it “undefined behavior” they achieved that goal: system which don't cause overflow have no need to intercept that trap while systems which cause it are not valid C.

Not sure how much sense that did even back in 1989, but in 2020 it doesn't make any sense at all: there are few CPUs which may still generate signals on overflow, but I don't know any where that's not optional.

And now, when two's complement is mandatory, workaround is, actually, “very simple”. Instead of if (x + 100 < x) you just have to write something like the following: if (std::std::is_signed_v<decltype(x)> ? static_cast<decltype(x)>(static_cast<std::make_unsigned_t<decltype(x)>>)(x) + 100U) < x : x + 100U < x)

And yes, of course you stuff that into a simple templated function. Except since there are no standard modules, no central repo and so on… everyone who wants/needs it would probably need to implement it separately. Which would, most likely, lead to bugs like an uncaught attempts to use that function to check overflow of float or double… or it would be miscomplied because someone used -std=c++20 instead of proper -std=gnu++20… as one of members of pilot Rust program for Android said: I don't feel as satisfied when reviewing Rust code: I always find something to comment on in C++ changes, usually some kind of C++ quirk or a memory management problem. When reviewing Rust changes it makes me uncomfortable if I don't find anything to comment on ("Am I being thorough?").

And these guys are talking about artificial puzzles the language imposes on top of each programming task? Really?

Ownership and lifetimes

Posted Jul 15, 2021 2:16 UTC (Thu) by mrugiero (guest, #153040) [Link] (5 responses)

I find your post very educational, however, it doesn't address my point: all the problems in making signed integer overflow defined behavior could have been fixed by making it implementation defined rather than undefined. Implementation defined means it's still hard to write *portable* code, but that when you do know where it'll run, you know there exists one behavior that is appropriate. That is, if it's implementation defined the compiler you use needs to define a given behavior for the platform it'll run and never violate it. So, gcc would be mandated to tell you what value will result from overflowing, even if such a value is one for SPARC and a different one for x86. I fail to see why it UB made more sense to them than that at the time.

But yeah, talking about artificial puzzles when you have all those kinds of behavior and you don't even mandate warnings when you hit them is a bit hypocritical.

Ownership and lifetimes

Posted Jul 15, 2021 14:12 UTC (Thu) by mathstuf (subscriber, #69389) [Link] (3 responses)

> That is, if it's implementation defined the compiler you use needs to define a given behavior for the platform it'll run and never violate it. So, gcc would be mandated to tell you what value will result from overflowing, even if such a value is one for SPARC and a different one for x86. I fail to see why it UB made more sense to them than that at the time.

I may be misremembering, but didn't some platforms not provide a way to tell? That would require the compiler to emit manual checks for every possible overflowing operation in order to guarantee *a* behavior. This would also mean that optimizing to, e.g., FMA instructions is basically impossible because if the intermediate ops overflow, that needs to be handled as well.

But if there are no platforms that lack an "overflow happened" flag…meh.

Ownership and lifetimes

Posted Jul 15, 2021 15:56 UTC (Thu) by matthias (subscriber, #94967) [Link]

Even if there is a platform that lacks an overflow happens flag. Then on this platform the implementation defined behavior is overflow with the semantics of what overflow means on this platform. Implementation defined means you can choose different semantics for very combination of compiler/platform.

If you do not know which platform your code will run on, you can still be not sure what the result of x+100 is in case of overflow, but you can at least be sure what (x+100)&0 is. And you can be sure that if you do an assertion x+100>x to test for an overflow that the assertion is not optimized away. Ok, it can be optimized away of the compiler can prove that there is not overflow, but this is no problem.

Ownership and lifetimes

Posted Jul 15, 2021 16:26 UTC (Thu) by farnz (subscriber, #17727) [Link] (1 responses)

If such platforms exist and need to be cared about (like you, I'm not sure if they did, or did not), an easy solution would be to make the behaviour of signed integer overflow unspecified, rather than undefined.

In the C language spec, there are four groups of behaviour (from strongest definition to weakest):

  1. Defined. To be a confirming implementation, you must behave in the way the Standard says you should, and there are no choices here. For example, the behaviour of the free(void * ptr) standard library function in C is defined if ptr is NULL or a pointer returned by malloc.
  2. Implementation defined. The Standard sets out restrictions on what this can be defined as, but the implementation gets to choose one concrete behaviour and stick to it. For example, the number of bits in int is implementation defined in C - any value greater than or equal to 16 is permissible, and the implementation must document which value it has cchosen.
  3. Unspecified. The Standard sets out restrictions on what behaviour is acceptable (e.g. "abc" == "abc" must be either 1 for true or 0 for false depending on whether the compiler merges identical string literals, but it cannot be 42 under any circumstances). The compiler can choose any behaviour it likes from the set the standard allows, and can choose different behaviour every time it sees the unspecified construct (e.g. printf("%d %d\n", "abc" == "abc", "abc" == "abc"); can print "0 0", "0 1", "1 0", or "1 1", and can print a different one each time the program is run); it does not have to stick to one choice, as it does for implementation-defined behaviour.
  4. Undefined. If a program run would follow a path with undefined behaviour, the meaning of the program as a whole is not set out by the Standard; it can do anything the compiler implementer wishes, even if the user of the compiler thinks that's a crazy stupid outcome.

If signed integer overflow became unspecified, such that the result of a signed integer overflow could be any integer value, then we're in a much better place. The compiler can just use the machine instruction (assuming it doesn't trap), and we don't have the pain where the compiler goes "well, if this is signed overflow, then behaviour is undefined, ergo I can assume it's not, ergo I can optimise out a check"; instead, signed overflow has to produce an integer, but which integer is not known by the code author.

Ownership and lifetimes

Posted Jul 15, 2021 16:42 UTC (Thu) by khim (subscriber, #9252) [Link]

This is all well and good, but this requires some form of consensus.

And in C/C++ world discussions are just not happening. Why have the coveted “pointer provenance” proposals were not incorporated into standard in 15 years (and counting)?

Because not even C/C++ compiler writers can agree with each other. -std=friendly-c proposal had the exact some fate.

And when someone tries to resolve the issue by “starting from scratch”… the end result is D, Java, C# or Rust… never a “friendly C”…

Rust is just the first such “new C” language which is low-level enough to actually be usable for all kinds of usages. Starting from lowest-level just above assembler.

Ownership and lifetimes

Posted Jul 20, 2021 10:25 UTC (Tue) by anton (subscriber, #25547) [Link]

Concerning integer overflow, the result with a given bit-width is the same for twos-complement arithmetic across all hardware (they all can perform modulo arithmetic, aka wrapping on overflow). And all architectures introduced since 1970 use twos-complement arithmetic exclusively (while, e.g., . So for integer overflow, the behaviour could be just standarized, no need for cop-outs like implementation-defined or implementation-specified. As an example modulo arithmetic has been standardized in Java from the start.

Ownership and lifetimes

Posted Jul 20, 2021 9:58 UTC (Tue) by anton (subscriber, #25547) [Link]

Backwards-compatible C compilers in the relaxed Linus Torvals sense (if no one notices, it's not breakage) are possible and desirable.

Ownership and lifetimes

Posted Jul 13, 2021 16:15 UTC (Tue) by plugwash (subscriber, #29694) [Link] (9 responses)

> Worse, programs are entitled in C++ to just extract the raw pointer from all these smart pointers except weak_ptr (where for obvious reasons there might sometimes not be a raw pointer) and they do.

To actually use the object owned by a C++ smart pointer, you are pretty much forced to explicitly (e.g. "get") or implicitly (e.g. operator* or operator->) extract a raw pointer or reference.

Which ties into your point about lifetimes, once that raw pointer or reference is extracted (again either explicitly or implicitly) there is nothing to ensure that the smart pointer outlives the raw pointer or reference that was extracted from it.

Ownership and lifetimes

Posted Jul 13, 2021 20:56 UTC (Tue) by mrugiero (guest, #153040) [Link] (8 responses)

Is that true? The `->` and `*` operators won't allow creating a copy of the pointer into an lvalue. The object is guaranteed to live until the end of the scope where those operators were called or the next assignment to it, which necessarily happens after the next sequence point, and since you don't get a copy of the pointer to operate with, the lifetime of the referenced object is guaranteed to be correct here. Explicit access is a problem, but I can't think of any scenario where the operators are.

Ownership and lifetimes

Posted Jul 13, 2021 23:16 UTC (Tue) by roc (subscriber, #30627) [Link] (7 responses)

unique_ptr<int> p = make_unique(3);
int& pp = *p;
p = nullptr;
cout << pp;

Ownership and lifetimes

Posted Jul 13, 2021 23:18 UTC (Tue) by roc (subscriber, #30627) [Link] (5 responses)

Yes, this example is contrived and "obvious", but you can achieve similar results in more interesting ways using function calls and temporaries.

Ownership and lifetimes

Posted Jul 14, 2021 9:32 UTC (Wed) by khim (subscriber, #9252) [Link] (4 responses)

You forgot to add std::move to the mix. The fact that after calling foo(std::move(p)); you can have so many possibilities (p may be destroyed or not destroyed, usable or unusable, etc… and compiler wouldn't ever reveal to you what happened… static analyzers sometimes might) opens up another nice room with so many nice footguns of different sizes…

Ownership and lifetimes

Posted Jul 14, 2021 12:06 UTC (Wed) by mathstuf (subscriber, #69389) [Link] (3 responses)

In that example, `p` cannot be destroyed. The destructor is still expected to be called at the end of `p`'s scope, so it must not be destroyed. Instead, it has to turn itself into some empty husk of an object that is safe to:

- destroy
- copy
- assign into (via move or copy)
- call methods on (though many APIs suck and don't provide ways of saying "this makes no sense anymore")

Rust can end `p`'s lifetime at the `foo` call, but C++ has lifetimes go to the end of the scope no matter what because there's no mechanism to say "`p` no longer exists and is now `foo`'s problem".

Ownership and lifetimes

Posted Jul 14, 2021 12:44 UTC (Wed) by khim (subscriber, #9252) [Link] (2 responses)

> In that example, `p` cannot be destroyed.

True, sorry I wasn't clear. Object owned by p may be destroyed or not destroyed, p may be usable or unusable, etc (I hope `p` just means p in your message and not some new footgun C++ gained while I wasn't looking).

> Rust can end `p`'s lifetime at the `foo` call, but C++ has lifetimes go to the end of the scope no matter what because there's no mechanism to say "`p` no longer exists and is now `foo`'s problem".

It's actually even worse than that: p have a destructor (and said destructor is, of course, the whole reason std::unique_ptr exists) thus it's non-trivial for the purposes of call which, in turn, means, that destruction of the object pointed by p still happens in the caller, not callee and, maybe even more importantly, std::unique_ptr can not be passed in register.

Clang have attribute which solves that issue, but libstdc++ doesn't use it (and I'm not even sure if libc++ actually uses that attribute already).

That's why I know some companies which demand that std::unique_ptr shouldn't be used to pass arguments to function and return results from it. Instead you have to use owner<T> syntax and turn it into std::unique_ptr in your function and back when you call anything.

As I have said: “modern C++” is just a huge collection of footguns of different sizes and shapes thus it sounds really funny when it's proponent start talking about artificial puzzles the language imposes on top of each programming task.

At least these rules exist in some kind of central location and compiler actually verifies them! Much better than when their violation turns your program into pile of goo without any complains from the compiler.

Ownership and lifetimes

Posted Jul 14, 2021 13:04 UTC (Wed) by mathstuf (subscriber, #69389) [Link] (1 responses)

> (I hope `p` just means p in your message and not some new footgun C++ gained while I wasn't looking)

I tend to just use "Plain text" here because HTML is a pain to write by hand and seem to wish that Markdown of some kind worked :) . That said, I cannot guarantee that it isn't a footgun you weren't aware of ;) .

> std::unique_ptr can not be passed in register.

True. There's discussion about breaking the ABI for this (and other things), but ABI breaking is a *huge* topic and you have the monorepo-using "we rebuild everything ourselves so what even is ABI stability" on one side and the "we have critical libraries we cannot recompile anymore because we lost the source 10 years ago" on the other. I have no idea if that discussion will go anywhere other than heat generation, but I hope something *useful* comes out of it at least even if it is just "let's design in some escape hatches for ourselves in the future".

Ownership and lifetimes

Posted Jul 17, 2021 16:06 UTC (Sat) by mrugiero (guest, #153040) [Link]

Then you use an older system I guess. If you were fine with no updating your software you're probably fine with that too.

Ownership and lifetimes

Posted Jul 15, 2021 2:10 UTC (Thu) by mrugiero (guest, #153040) [Link]

Stupidly enough, I didn't think of references. It shows how much time passed since the last time I wrote C++ :)

Ownership and lifetimes

Posted Jul 14, 2021 7:28 UTC (Wed) by ncm (guest, #165) [Link] (14 responses)

You reveal perhaps more than you intended.

Stroustrup never, ever rants. When he writes, every word counts. To perceive ranting only demonstrates confusion.

Your confusion about the One Definition Rule is revealing. In fact, the only requirement to spend an entire career coding C++ never once troubled by violations of the ODR is simply to obtain declarations via headers, rather than copy-pasting them. C has always been subject to undetected failures resulting from identical malpractice; what is new is that C++ gives the rule a formal name. C's linkage model, inherited by C++ for backward compatibility, brought with it C's weaknesses, but C++ now provides module support..

To believe that object ownership and lifetimes have not always been understood and actively managed as a matter of course by all C++ (and C) coders demonstrates further confusion.

To believe that C++ is not rapidly growing and changing is to believe a fantasy that C++20 is hardly different from C++17, from C++14, from C++11, from C++03, from C++98. In fact no language defined by a Standard has evolved more over that time, and few of the rest have. As more people adopt C++ anew in any given week than have ever heard of Rust, there is no worry about lunch. "There are only two kinds of languages: the ones people complain about, and the ones nobody uses." When we see more complaints about Rust than marveling over its ability to do what has been done before, it will merit more attention.

Writing fantastic falsehoods about a language and its users reveals nothing about them, but much about the writer.

Ownership and lifetimes

Posted Jul 14, 2021 8:25 UTC (Wed) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

> In fact, the only requirement to spend an entire career coding C++ never once troubled by violations of the ODR is simply to obtain declarations via headers, rather than copy-pasting them.

That's incorrect. You can get ODR violations by having multiple clashing template specializations, that can be in different parts of the application (for the added fun).

Back in MSVS 2006 days, I also spent several days debugging an issue where two inline functions (exempt from ODR) had different padding due to different compilation options.

Ownership and lifetimes

Posted Jul 14, 2021 9:40 UTC (Wed) by khim (subscriber, #9252) [Link]

> You can get ODR violations by having multiple clashing template specializations, that can be in different parts of the application (for the added fun).

No need for even that. Compile your header once with -mavx512f and once without it and you may have nice and long investigation where you would try to understand why minor changes to totally unrelated code creates something that explodes on Ryzen cluster and where clean build either always produces working binaries but incremental builds sometimes lead to crashes.

Have fun.

> Back in MSVS 2006 days, I also spent several days debugging an issue where two inline functions (exempt from ODR) had different padding due to different compilation options.

This story just never dies.

Ownership and lifetimes

Posted Jul 14, 2021 8:33 UTC (Wed) by Cyberax (✭ supporter ✭, #52523) [Link] (3 responses)

> To believe that C++ is not rapidly growing and changing is to believe a fantasy that C++20 is hardly different from C++17

Honestly, C++ is not growing rapidly. C++20 improvements were mostly in libraries and infrastructure around them.

The major language-level feature in C++20 are concepts, but they had to be cut down quite a bit. Coroutine support is at the barest minimum possible. Modules haven't made it either.

Ownership and lifetimes

Posted Jul 15, 2021 5:52 UTC (Thu) by ncm (guest, #165) [Link] (2 responses)

You have failed to keep up with events, so you embarrass yourself by publishing falsehoods.

Ownership and lifetimes

Posted Jul 15, 2021 13:43 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

These snipe-y comments sound awfully embarrassing by themselves to me too. If the post is so embarrassing, why not just leave them to stand on their own if you're not going to contribute anything to the discussion in your reply?

Ownership and lifetimes

Posted Jul 18, 2021 13:13 UTC (Sun) by flussence (guest, #85566) [Link]

Congratulations on becoming the new IBM OpenOffice Guy.

Ownership and lifetimes

Posted Jul 14, 2021 9:28 UTC (Wed) by jezuch (subscriber, #52988) [Link] (1 responses)

> In fact, the only requirement to spend an entire career coding C++ never once troubled by violations of the ODR is simply to obtain declarations via headers, rather than copy-pasting them.

Newer compilers actually warn about ODR violations. Previously is was completely silent, so nobody knew how much they were violating it. I once compiled some random C++ program with such a compiler and I just sat and watched as the ODR violation warnings just scrolled by, on and on, endlessly.

So. "The difference between practice and theory is bigger in practice than in theory." (I think it's an old engineering saying.)

Ownership and lifetimes

Posted Jul 14, 2021 12:26 UTC (Wed) by tialaramex (subscriber, #21167) [Link]

As with the Java ConcurrentModificationException, these are Best Efforts Only. You might get warnings, but you might not. There are no false positives for these diagnostics (if you get the diagnostic, you do have the problem) but there are false negatives, and you can't know how many.

Ownership and lifetimes

Posted Jul 14, 2021 15:20 UTC (Wed) by tialaramex (subscriber, #21167) [Link]

Another, but longer-lived, surprise for me has been how many people are bad at debugging because they can't let go of a Truth they believe in, despite it being contradicted by Facts now made evident to them. I don't know how people who can't get this right ever debug anything, it must be very difficult.

So, the Fact is that Stroustrup doesn't talk about ownership in that book. The much later (less than ten years old as I write this) Fourth Edition does talk extensively about ownership. Can't shut up about it actually. In some places, nearby text survives, or has been transplanted from earlier editions, but the talk of ownership is new. Why? Because of shared_ptr and unique_ptr which did not exist when the Second Edition was written. This inspires Stroustrup to explain even before introducing any C++ syntax at all, that programmers must "represent ... Ownership relationships" in their code. Which, in C++ 11 they now can try to do.

Throughout the Fourth Edition's "Tour" of C++, there are opportunities, taken or at least pointed out to the reader for their own benefit, to express Ownership. The Desk Calculator example explicitly tracks whether it owns the Input Stream it is using, offering methods to give it a reference (which it doesn't own) or a raw pointer (which it does) and clean up appropriately. Second Edition makes no mention of this, it too has a Desk Calculator example, but it doesn't bother with Input Streams, it just reaches inside the system's standard input and mangles that directly.

So, you're wrong, factually even if you firmly believe now that ownership has "always been understood and actively managed" it seems to have escaped mention by the language's father in their text intended to introduce the language _until_ decades later the language grew facilities to actually try to "actively manage" this problem.

Lifetimes are an interesting contrast. The Second Edition does spend a few paragraphs on this topic, but mostly the reader is encouraged not to think about it too hard. Objects begin living when they're Constructed, and this lifetime ends when their name goes out of scope whereupon they will be Destroyed. Except, that's not quite true and there are a few paragraphs trying to justify that before a reference to paragraphs later in the book about the Free Store.

By the Fourth Edition, lifetimes get their own sizeable Chapter in the much larger book, "Construction, Cleanup, Copy and Move". So I agree that by this point Stroustrup is aware that this is a problem, indeed that chapter uses words like "trap" and "mistake" and most sub-sections are accompanied by considerable verbiage basically encouraging the programmer to try harder not to get this wrong. But he doesn't have anything to really propose as a solution. Yet.

Today, Stroustrup has a proposed change to C++ to add actual lifetime tracking. I don't expect it will make it into C++ 23. You claim that Stroustrup "never, ever rants" but he seems quite animated when it comes to the committee not accepting all his ideas as quickly as he might like or adjusting them in ways he isn't pleased with, and equally animated about cutting down other people's proposals.

Ownership and lifetimes

Posted Jul 14, 2021 15:37 UTC (Wed) by mathstuf (subscriber, #69389) [Link] (2 responses)

> In fact, the only requirement to spend an entire career coding C++ never once troubled by violations of the ODR is simply to obtain declarations via headers, rather than copy-pasting them.

Just had to deal with this last week in fact. ODR violations are rampant when some dependency does not follow C++ "best practices" nor uses extra-language bits that are compiler/platform dependent (`__attribute__(visibility)` and `__declspec`).

One of our dependencies doesn't export symbols properly. Luckily, CMake has a way to say "le sigh, just export everything" on Windows to fix that problem. However, there's a deeper problem lurking in such a codebase: RTTI duplication. There are these simple interface classes that have their definitions completely in the header. Seems reasonable; header-only is fine, right? However, the source code of the library does `typeid` comparisons with a `std::type_info` that is passed in to see which of these interface types you're asking about. Because the complete definition (trivial `{}` bodies for the ctor and dtor with pure virtual methods otherwise) are in the header, every library that sees this declaration can say "huh, no export symbol? I can make it mine" and generate its own unique RTTI table for the type. The linker will resolve these together into a shared library boundary, but nothing resolves it across a shared library boundary at runtime, so you then get two different `typeid` blocks for the same type. Hilarity ensues when the dependency goes "yeah, I have no idea what you're on about, have a `nullptr`".

Now, C++ *could* have just standardized `export` or some other syntax to say whether a declaration "belongs" to the current TU's target or not, but that requires macros at compile time to know which library you're actually compiling for so things get linked up properly. And C++ *hates* talking about compilation strategies beyond "pile of TU outputs linked into a program" because it never bothered to reign in the madness from the beginning and now suggesting anything is likely to get somebody clutching pearls immediately. So, C++20 has modules where what is "in" and what is "out" can be more easily tracked with actual standard-compliant syntax, but this has been an issue since C's textual inclusion compilation model was a thing and only now we have a solution that requires rewriting all of your headers and leaving old, dumb `%.o: %.cpp` build systems behind anyways (because compiling C++20 modules is the same problem as compiling Fortran modules and everyone remembers how much fun that has been, right?).

Ownership and lifetimes

Posted Jul 15, 2021 11:49 UTC (Thu) by foom (subscriber, #14868) [Link] (1 responses)

The problem you describe here is that windows (PE/COFF) DLLs don't support C++'s vague linkage symbols across DLLs properly. This makes windows DLLs effectively incompatible with the C++ standard's requirements.

Neither MacOS (mach-o) nor Linux (elf) shared libraries have this issue. They both work fine in this situation, by ensuring that vague linkage symbols are exported and deduplicated across the shared library boundaries by default.

One might expect this would have been addressed in Windows at some point in the last few decades...but it hasn't been.

Ownership and lifetimes

Posted Jul 15, 2021 13:46 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

Well, the fun thing here is that the problem appeared on macOS arm64. Previously, everything had been working on all platforms (our library does use `-fvisibility=hidden` to emulate Windows behavior on the other platforms because we *do* export our symbols properly). Which makes me wonder why the typeinfo wasn't already duplicated…but whatever. Anyways, something is different with macOS arm64 and this problem came up and now it's fixed by improving the code, so I'm happy at least (and it's one more "ghostly linker fun" bug under my belt :/ ).

Ownership and lifetimes

Posted Jul 18, 2021 18:10 UTC (Sun) by marcH (subscriber, #57642) [Link]

> To believe that C++ is not rapidly growing and changing is to believe a fantasy that C++20 is hardly different from C++17, from C++14, from C++11, from C++03, from C++98.

OK, so language theory discussions are fascinating (thank you everyone) but now let's get real a bit. Let's pretend I'm managing a software team and I've been asked to get rid of most safety issues in the C++ codebase of our mission-critical application. What -Wold-unsafe-c++ compiler flag do I turn on to make sure my not-all-perfect developers don't make any mistake and stick to "modern C++"? If that compiler flag is not available, what static analyzer(s) should I use? I have practically unlimited budget so I don't mind commercial products. (Even an unlimited budget is unfortunately not enough to hire an elite team of C++ developers who never make any mistake)

> there is no worry about lunch.

I don't think anyone doubts C++ will still make a lot of money after even the youngest people in this discussion are dead, no reason to feel threatened.
There is a shortage of developers, not a shortage of code to write. Apparently you can still get paid to fix COBOL code:
https://www.theverge.com/2020/4/14/21219561/coronavirus-p...

Ownership and lifetimes

Posted Jul 18, 2021 18:49 UTC (Sun) by marcH (subscriber, #57642) [Link]

> Stroustrup never, ever rants. When he writes, every word counts. To perceive ranting only demonstrates confusion.

Whether it's true or not, I'm afraid you don't realize how cultish that is perceived.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 4:03 UTC (Mon) by roc (subscriber, #30627) [Link]

How much Rust experience do you have, ncm?

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 10:02 UTC (Tue) by ofranja (guest, #11084) [Link]

> The satisfaction one gains in having solved the artificial puzzles the language imposes on top of each programming task can be easily mistaken for actual pleasure in using the language.

This could be said about the mere act of programming, specially in a compiled language, and specially in C++.

It causes me surprise to hear this statement from someone with so much baggage in C++, one would expect the years of experience to have shown humans are very prone to mistakes, even by oneself. And in the event that the software one writes is perfect, there is still the need to deal with software from less-than-perfect human beings. Turning a certain class of mistakes into compile-time errors sounds like a good trade off for the majority of situations where the software itself is of any importance.

> This quirk of human psychology may be seen in many other activities, wherever unnecessary difficulty is treated as a virtue. The fanaticism that tends to result is the same in all cases.

I would not discard this effect, but again: same points apply to C++. I've heard similar argument (fanatismus) being used for C++ as well, by the way.

Unless we apply an unbiased reasoning to this argument I would say it is very selective of the borrow checker. It may be a learning curve in itself but just because C++ does not provide one it doesn't make it magically easier. I would argue the opposite.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 10:20 UTC (Mon) by professor (subscriber, #63325) [Link] (4 responses)

I dont understand.. What happened to semaphores and thread locks?

Is Rust Java 2.0?

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 12, 2021 11:08 UTC (Mon) by excors (subscriber, #95769) [Link] (3 responses)

Do you mean, why can't they keep using C and just add some semaphores and locks?

What happened is that people discovered it's nearly impossible to do that correctly in non-trivial programs. You can design your code with a rule that a certain set of variables is only accessed by threads holding a certain lock, which would guarantee it's safe from race conditions; but the old languages don't provide any tools to enforce that, and in practice it's very easy to make mistakes and access the variable without the lock. Or in attempting to avoid race conditions you might add too many locks, or try to acquire one recursively, and then you deadlock.

I think what happened next is that people started recognising the value of more modern (i.e. 1980s instead of 1960s) concurrency design patterns, with multiple single-threaded modules linked by thread-safe message queues. You can implement that in C, but it's very easy in a large program to make a mistake and become non-thread-safe again without noticing (e.g. by accessing a global variable, or by sharing a mutable data structure over the message queue, possibly via some third-party library that you can't redesign to your new style of concurrency).

Then people started designing languages that make the good patterns much easier to use, and make the bad patterns harder or impossible, so you can be much more confident that any code written in that language and accepted by the compiler is concurrency-safe.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 10:55 UTC (Tue) by khim (subscriber, #9252) [Link] (2 responses)

> Then people started designing languages that make the good patterns much easier to use, and make the bad patterns harder or impossible

That's not Rust, that's Java 1.0.

Rust picked many things from many languages (it's definitely not the first “safe language”), but it did three things which made it unique:

  1. Unsafe code via out-in (it even used the exact same unsafe keyword C# uses)
  2. Safety, including dynamic memory usage — without GC
  3. The ability to out-out of rich standard library and only keep tiny core (and they are even thinking if maybe you can out-out of that, too).

This, basically, put it into unique position for now. (2) is especially important: suddenly, you can have amenities of high-level language while doing very low-level stuff. Like kernel or even embedded firmware.

C#, Java, or Haskell (while certainly nice languages for some uses) would never be able to replace C/C++. Simply because they need fat runtime. Even older versions of Ada couldn't do safe dynamic memory processing without fat runtime (not 100% sure if modern versions can do that).

With Rust you can do all kinds of projects which previously forced you to use C or C++. Doesn't necessarily mean you would want to do that. But you can.

This changes things and makes Rust, most definitely, something different that Java 2.0.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 13, 2021 21:05 UTC (Tue) by mrugiero (guest, #153040) [Link] (1 responses)

To be fair, excors never claimed Rust invented the concept of safety. They claimed people started abandoning C for everything they could, reducing its niche, because of those defects. Rust is an evolutionary improvement with some original ideas, at least original in the sense of actual real world application, and using many of the later-than-C-but-not-really-new ideas that proved to be good in the field. There's merit in selecting the good parts of prior art and mixing them in a useful way, the same way there's merit in meta analysis even when they don't create new knowledge.

Announcing Arti, a pure-Rust Tor implementation (Tor blog)

Posted Jul 18, 2021 17:54 UTC (Sun) by marcH (subscriber, #57642) [Link]

> There's merit in selecting the good parts of prior art and mixing them in a useful way, the same way there's merit in meta analysis even when they don't create new knowledge.

I would call this "engineering".


Copyright © 2021, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds