|
|
Subscribe / Log in / New account

A pair of Rust kernel modules

A pair of Rust kernel modules

Posted Sep 14, 2022 15:42 UTC (Wed) by khim (subscriber, #9252)
In reply to: A pair of Rust kernel modules by Wol
Parent article: A pair of Rust kernel modules

> Probably one of the big drivers pushing the kernel towards llvm/clang is too many developers are getting fed up with the breakages caused by the gcc developers attitude towards "undefined behaviour".

I really like how Rust solved that crazy provenance business.

Instead of trying to invent rules which would work for everyone (that's what C/C++ attempted, but failed to do and thus and still, after 20 years, doesn't have such rules, remember!) Rust just gives you rules which you can use! And then its developers go back to their blackboard to try to invent something better.

What is surprising is that this is what was supposed to happen in the C land, too: Undefined behavior gives the implementor license not to catch certain program errors that are difficult to diagnose. It also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior.

Only in Rust case they actually do that, instead of trying to find an excuse to justify yet-another-way which compiler is allowed to break your program.

C++ once, long ago, was like that, too: it split C-style cast into const_cast, dynamic_cast, reinterpret_cast and static_cast for similar reasons.

But somehow in XXI century all that went out of the window. We can only hope Rust wouldn't repeat the same mistake.


to post comments

A pair of Rust kernel modules

Posted Sep 15, 2022 13:03 UTC (Thu) by farnz (subscriber, #17727) [Link]

The really nice thing about the Tower of Weakenings approach is that Rust is now able to have several layers of rules for provenance. Strict provenance is guaranteed to be correct for all implementations of Rust on all hardware that can support Rust; but because you have this portable set of rules, it's now possible to define rules like "for Rust on AArch64" or "for single-threaded Rust programs" that only apply if you're a special case.

In C and C++ standard terms, this has "strict provenance" as the rules that must apply, while permitting implementations to define relaxations of strict provenance that they will also accept as valid.

A pair of Rust kernel modules

Posted Sep 15, 2022 19:34 UTC (Thu) by Wol (subscriber, #4433) [Link] (3 responses)

> But somehow in XXI century all that went out of the window. We can only hope Rust wouldn't repeat the same mistake.

As I've said before, the C/C++ standards committee should be removing undefined behaviour. Placing the onus on the compiler writers to provide implementation-defined behaviour. Saying it's "whatever the hardware does". Whatever whatever but getting rid of all that crap.

And then there are things you can't define for whatever reason, where you admit that a definition is impossible.

The thing is, Rust has all three of those, and it clearly pigeonholes them. Safe Rust is supposedly *only* *defined* behaviour. And if undefined behaviour creeps into safe code it is defined as a BUG, a MUST-FIX.

I guess all that "hardware defined" stuff probably belongs in the "unsafe Rust" category, where the language can't reason because it doesn't have any idea what's going to happen behind its back.

And then there's the stuff you can't define, which is unsound, because there's some fault in the logic somewhere.

The important thing is, the programmer can REASON about all this lot, unlike C, where hardware behaviour triggers "undefined behaviour", and the C compiler makes a whole bunch of false assumptions and screws up your code (like deleting necessary safety checks, etc etc).

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 15, 2022 20:19 UTC (Thu) by khim (subscriber, #9252) [Link] (2 responses)

But the thing is: this is what was supposed to happen with C and C++, too! Except for safe subset, but otherwise it was planned like that.

I mean… the Rationale for International Standard— Programming Languages— C says: Undefined behavior gives the implementor license not to catch certain program errors that are difficult to diagnose. It also identifies areas of possible conforming language extension: the implementor may augment the language by providing a definition of the officially undefined behavior.

This is your Tower of Weakenings right there!

Note that before C89 was punished it actually worked that way: there was no standard but different implementations permitted different things and even if some were not so easy to implement (e.g. one-element-past-the-end-of-array means it becomes impossible to have simple 64KiB arrays on MS-DOS) they were added to standard where it made sense.

I wonder how that stance turned into “if standard says something is undefined behavior then we have the carte blanche to destroy the program” and then “if standard doesn't say something is undefined behavior yet then we have the permission to destroy your program anyway”.

I don't think there was some evil mastermind behind all these developments, but the end result sure is complete lack of trust.

Periodic Linus outbursts and public complaints is not how you plan development of language which is used by millions!

A pair of Rust kernel modules

Posted Sep 15, 2022 21:35 UTC (Thu) by mathstuf (subscriber, #69389) [Link] (1 responses)

> I wonder how that stance turned into “if standard says something is undefined behavior then we have the carte blanche to destroy the program” and then “if standard doesn't say something is undefined behavior yet then we have the permission to destroy your program anyway”.

Portability I would guess. Once more than one compiler could target a given platform (or one compiler could target more than one platform), "my compiler/platform is better than yours" creeps in and you start down the path of "what kinds of optimizations can we squeeze out here?" come up.

Today? Code that is written to work on multiple platforms from the same source. Here, the compiler saying "well, if it were $obscure_arch, this is different behavior, so we'll show it to you on your machine via UB-based optimizations (but not make any noise about it either)".

On one hand, a UB-less C would be "safer", but its portability would tank because "it worked on my x86_64" means diddly squat when you compile it for aarch64.

A pair of Rust kernel modules

Posted Sep 15, 2022 22:33 UTC (Thu) by Wol (subscriber, #4433) [Link]

> On one hand, a UB-less C would be "safer", but its portability would tank because "it worked on my x86_64" means diddly squat when you compile it for aarch64.

You've missed "implementation defined" and "hardware defined".

If something is "hardware defined" then yes, just because it works on x86_64, you can't expect the SAME code to work on aarch64, but firstly the programmer will KNOW that they need to check behaviour, and secondly they can put the ifdefs and whatever in there, and know that that IS DEFINED behaviour.

The *only* grounds for UB should be because "we can't define it because we can't get the logic to add up". There's no need for the C/C++ standard to define everything itself - it can defer the definition to something else - but all behaviour should be defined *somewhere*, if a definition is possible.

Take for example the size of a byte. In *PRACTICE* it's always 8-bit nowadays. I wouldn't be surprised if it's actually already implementation or hardware defined, but that's a perfect example of something that makes perfect sense as hardware-defined. In places, bytes are 6 bits, and if the programmer doesn't account for it it will cause a major problem if they're targetting an old platform. But the standard CAN, and SHOULD, address it.

Cheers,
Wol


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