|
|
Subscribe / Log in / New account

A pair of Rust kernel modules

By Jonathan Corbet
September 12, 2022

Kangrejos
The idea of being able to write kernel code in the Rust language has a certain appeal, but it is hard to judge how well that would actually work in the absence of examples to look at. Those examples, especially for modules beyond the "hello world" level of complexity, have been somewhat scarce, but that is beginning to change. At the 2022 Kangrejos gathering in Oviedo, Spain, two developers presented the modules they have developed and some lessons that have been learned from this exercise.

An NVMe driver

Andreas Hindborg was up first to talk about an NVM Express driver written in Rust. The primary reason for this project, he said, was to take advantage of the memory-safety guarantees that Rust offers and to gain some real-world experience with the language. His conclusions from this project include that Rust comes with a lot of nice tooling and that its type system is helpful for writing correct code. It is, he said, easier to write a kernel driver in Rust than in C.

[Andreas
Hindborg] Why write an NVMe driver when the kernel already has one that works well? There are no problems with the existing driver, he said, but NVMe is a good target for experiments with driver abstractions. NVMe itself is relatively simple, but it has high performance requirements. It is widely deployed, and the existing driver provides a mature reference implementation to compare against.

Hindborg talked for a while about the internals of the NVMe interface; in short, communications between the interface and the computer go through a set of queues. Often the driver will configure an I/O queue for each core in the system if the interface can handle it. Creating data structures in Rust to model these queues is a relatively straightforward task. In the end, the Rust driver, when tested with the FIO tool, performs almost as well as the existing C driver. The difference, Hindborg said, is that the C driver has already been highly tuned, while the Rust driver has not; it should be able to get to the same level of performance eventually.

He concluded by saying that the Rust NVMe driver is still "a playground" and not production-ready at this point. To move things forward, he would like to create more abstractions that would allow the removal of the remaining unsafe blocks in the driver. It doesn't yet support device removal or the sysfs knobs for the nvme-cli tool. He would also like to look into using the Rust async model, which would "simplify a lot of things" in the driver, but possibly at the cost of performance.

At the end of Hindborg's talk, Paul McKenney asked if there was any available information on the relative bug rates between the C and Rust drivers. Hindborg answered that there have certainly been some bugs; building Rust abstractions around existing C code can be hard to do correctly. That work needs a lot of care and review, but once it works, drivers built on it tend to show few problems.

A 9P filesystem server

Last year, Linus Walleij suggested that, rather than writing drivers in Rust, developers should target areas with a higher attack surface — network protocols, for example. Wedson Almeida Filho has taken that advice and written an in-kernel server for the 9P filesystem protocol in the hopes that this project would demonstrate the productivity gains and security benefits that Rust can provide. Initially, he had started trying to replace the ksmbd server, but that turned out to not be an ideal project. The SMB protocol is too complex and the server needs some significant user-space components to work. He wanted something simpler; 9P fit the bill.

[Wedson Almeida
Filho] The 9P file protocol, he said, comes from the Plan 9 operating system. The kernel has a 9P client, but no 9P server. There is a 9P server in QEMU that can be used to export host filesystems into a guest. The protocol is simple, Almeida said, defining a set of only ten operations. His 9P server implementation works now, in a read-only mode, and required just over 1,000 lines of code.

Almeida was also looking for a way to experiment with async Rust in the kernel. In the async model, the compiler takes thread-like code and turns it into a state machine that can be implemented with "executors" and "reactors", which are implemented in the kernel crate. He created an executor that can run async code in a kernel workqueue; anywhere such code would block, it will release the workqueue thread for another task. There is also a socket reactor that is called for socket-state changes; it will call Waker::wake() from the Rust kernel crate to get the appropriate executor going again.

There is, of course, plenty of work yet to be done. He would like to implement reactors for other I/O submission paths, including KIOCBs (asynchronous I/O), URBs (USB devices), and BIOs (block devices). Memory allocation can still use some work; it would be good if a GFP_KERNEL could give up its thread while waiting for the memory-management subsystem to do complicated things.

At the end, I asked whether the objective of demonstrating the security benefits of Rust had been achieved; has there been, for example, any fuzz testing of the server? Almeida answered that the Rust-based parsing interface makes a lot of mistakes impossible. No fuzz testing has been done — the server has only been working for a couple of weeks — but he will do it. He concluded that he will be interested to see how his server fares in such testing relative to the QEMU implementation.

[Thanks to LWN subscribers for supporting my travel to this event.]

Index entries for this article
KernelDevelopment tools/Rust
ConferenceKangrejos/2022


to post comments

A pair of Rust kernel modules

Posted Sep 12, 2022 14:54 UTC (Mon) by iustin (subscriber, #102433) [Link]

Interesting, so it finally starts? Looking forward to more Rust usage…

A pair of Rust kernel modules

Posted Sep 12, 2022 14:54 UTC (Mon) by koverstreet (✭ supporter ✭, #4296) [Link] (13 responses)

The 9p server in particular is beyond slick.

The async stuff in Rust works beautifully here; internally, the compiler is doing a CPS transformation. This is something (some of us) C programmers have known how to do for years, but in practice it's _tedious_, so when we do it in C it's always less than ergonomic and incomplete.

And the RAII stuff means a lot of tricky cleanup code just doesn't exist.

This the code I always wished I could write - and unlike in C++, we can write it and actually trust that it's correct.

A pair of Rust kernel modules

Posted Sep 13, 2022 10:33 UTC (Tue) by ncm (guest, #165) [Link] (12 responses)

Or, you could code it in C++, correctly, and be done.

Coding it in Rust does not, in fact, guarantee it is correct. Coding C++, you need only choose known-correct primitives to get the same level of assurance. But you would then face rabid, unreasoned hostility from Linus for C++ features you may use in Rust code without approbation; and have your patch summarily rejected with, most likely, a rude remark.

The easy way to get C++ code into the kernel is via eBPF, which offers solid support for building from C++, and where there is nothing Linus can do to stop you. And, it is exactly as safe as Rust eBPF, but likely less annoying to code.

A pair of Rust kernel modules

Posted Sep 13, 2022 11:08 UTC (Tue) by gspr (subscriber, #91542) [Link] (2 responses)

> Or, you could code it in C++, correctly, and be done.

I believe that the parent commenter meant that doing exactly this is signficantly harder than it is in Rust.

A pair of Rust kernel modules

Posted Sep 13, 2022 11:13 UTC (Tue) by milesrout (subscriber, #126894) [Link] (1 responses)

It's far easier than in Rust, because in Rust it's impossible.

Please

Posted Sep 13, 2022 11:16 UTC (Tue) by corbet (editor, #1) [Link]

Can we please try to avoid yet another round of silly language-advocacy postings here? We've all heard it. The article is about people showing real work, albeit at an early stage; let's focus on the actual work.

Thank you all.

A pair of Rust kernel modules

Posted Sep 14, 2022 10:56 UTC (Wed) by xav (guest, #18536) [Link]

> Coding it in Rust does not, in fact, guarantee it is correct

To a certain extend, it does out of unsafe blocks, and way more than C++ can even dream of.

A pair of Rust kernel modules

Posted Sep 15, 2022 19:14 UTC (Thu) by nix (subscriber, #2304) [Link] (7 responses)

The easy way to get C++ code into the kernel is via eBPF, which offers solid support for building from C++
Solid? Earlier this year I had a persistent failure getting this to verify (under 5.16):
        uint32_t id;mp;
        dt_bpf_specs_t zero;

        __builtin_memset(&zero, 0, sizeof (dt_bpf_specs_t));

        for (id = 1; id <= 16; id++) {
                if (bpf_map_update_elem(&specs, &id, &zero,
                                        BPF_NOEXIST) == 0)
                        return id;
        }
A simple loop updating sixteen map values to 0 was rejected... because the verifier could not prove that this incredibly subtle and difficult loop would terminate. (I unrolled it, and everything was fine.)

Trying to write nontrivial C++ code and expecting it to turn to working eBPF without massive amounts of verifier agony is an exercise in futility at present. You can try if you like, but I wouldn't want to listen to the resulting cursing if you did. (Maybe this will change in time, but I very much suspect that turning the verifier into something that isn't full of arbitrary restrictions and can actually verify real code that wasn't written with 90% of one's attention on contorting things in unnatural ways to get it to verify will either slow it to unusability or just slam straight into the wall of Rice's theorem.)

A pair of Rust kernel modules

Posted Sep 15, 2022 19:37 UTC (Thu) by rahulsundaram (subscriber, #21946) [Link] (1 responses)

> Solid? Earlier this year I had a persistent failure getting this to verify (under 5.16):

Have you tried the Rust ones? https://aya-rs.dev/ or https://crates.io/crates/bcc

A pair of Rust kernel modules

Posted Sep 15, 2022 21:13 UTC (Thu) by nix (subscriber, #2304) [Link]

No, but the problem was the *verifier*, not the input language. The same sort of thing written in raw eBPF was also rejected. (It worked if the loop bound was < 4. How... useful.)

Figuring out why required diving into the verifier source code, because there is of course nothing like a spec, and the verifier's verification contains enough holes where obviously valid code is rejected out of hand because nobody's written code to verify it (if you're lucky, there are comments noting the lack of said verification) that it frankly should be called a collection of holes with a little fabric connecting them :)

A pair of Rust kernel modules

Posted Sep 16, 2022 8:51 UTC (Fri) by nybble41 (subscriber, #55106) [Link] (1 responses)

> Earlier this year I had a persistent failure getting this to verify (under 5.16): …

Strictly speaking, without taking into account knowledge of the internals of bpf_map_update_elem(), that loop might *not* terminate. You're passing in a pointer to the loop counter (id) and the function could potentially update the variable via that pointer to prevent it from incrementing. (Yes, even if the pointer argument is const-qualified; you can cast away the const qualifier on a pointer with const_cast as long you're not trying to store into a const object, and the variable id in this example isn't a const object.)

It would probably compile if you copied id into a separate local variable and passed a pointer to that variable to bpf_map_update_elem(). Then the compiler could easily prove that the function doesn't update id since it doesn't have its address (given the standard pointer provenance rules), which places a fixed upper bound on the number of loop iterations.

A pair of Rust kernel modules

Posted Sep 16, 2022 9:22 UTC (Fri) by Wol (subscriber, #4433) [Link]

Or bpf could take fortran to heart, and the definition in the spec that says "for loops do not guarantee that modifications to the index variable will "stick"".

The standard explicitly permits moving the index into a register (which other code has no access to) and then it saves it to the variable whenever it increments or other fancy tricks.

Whatever, as far as the code *inside* the loop is concerned, the index variable is either read-only, or if you do try and modify it, it's undefined.

So, provided the naive loop terminates, you can guarantee that any loop will terminate.

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 23, 2022 9:56 UTC (Fri) by rep_movsd (guest, #100040) [Link] (2 responses)

It looks like the id loop iterator is being passed by pointer to a function.
Why would a function need a primitive value passed in by pointer unless it intended to modify it?

The compiler cannot guarantee that id doesnt change whilst you are looping.

So either the function takes a const pointer to int (which is braindead) and the compiler is brain dead not to see its not modifiable

OR

The function takes it by pointer (which may be braindead) and the compiler is right

A pair of Rust kernel modules

Posted Sep 23, 2022 11:05 UTC (Fri) by adobriyan (subscriber, #30858) [Link]

"key" should be pointer to const.

BPF_CALL_4(bpf_map_update_elem,
struct bpf_map *, map,
void *, key,
void *, value,
u64, flags)
{
WARN_ON_ONCE(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
return map->ops->map_update_elem(map, key, value, flags);
}

A pair of Rust kernel modules

Posted Sep 23, 2022 18:04 UTC (Fri) by nybble41 (subscriber, #55106) [Link]

> So either the function takes a const pointer to int (which is braindead) and the compiler is brain dead not to see its not modifiable

Even if the function did take a const-qualified pointer, it wouldn't matter. It's perfectly legal to do something like this:

void f(int const *p) { *(int*)p = 7; }

... as long as the original *object* was not const-qualified. (Attempting to write into a *variable* which was const-qualified at the point of declaration is, of course, undefined behavior, whether or not the pointer being used is const-qualified.) Consequently, the compiler can't assume that the function won't write into a mutable object even if the pointer argument is const-qualified.

Also, the read-only pointer-to-int argument pattern isn't quite so "braindead" as you suppose. These functions are generic; in this case the key happens to be an int, but that isn't always true, and so the key is passed by reference rather than value. The comparison callback for the standard library's qsort() function uses the same pattern, for example, when sorting an int array.

A pair of Rust kernel modules

Posted Sep 12, 2022 16:28 UTC (Mon) by NHO (subscriber, #104320) [Link]

Then there's Asahi DRM driver for Apple Silicon.

A pair of Rust kernel modules

Posted Sep 13, 2022 9:48 UTC (Tue) by josh (subscriber, #17465) [Link] (1 responses)

The NVMe driver was presented again the this week at Plumbers, to enthusiastic reactions: https://twitter.com/josh_triplett/status/1569363148985233414

A pair of Rust kernel modules

Posted Sep 13, 2022 15:38 UTC (Tue) by MrWim (subscriber, #47432) [Link]

A pair of Rust kernel modules

Posted Sep 13, 2022 11:12 UTC (Tue) by milesrout (subscriber, #126894) [Link] (53 responses)

> At the end of Hindborg's talk, Paul McKenney asked if there was any available information on the relative bug rates between the C and Rust drivers. Hindborg answered that there have certainly been some bugs; building Rust abstractions around existing C code can be hard to do correctly. That work needs a lot of care and review, but once it works, drivers built on it tend to show few problems.

So in other words: oh yes, there are still bugs, but we can just blame them on C. Any issues with interfacing Rust and C? Obviously the fault of C. Even though clearly and logically any bugs introduced by having to interface two languages is only reasonably attributable to the language that came along later and seems intent on forcing its way into the kernel regardless of what anyone else wants.

And things like this:

> At the end, I asked whether the objective of demonstrating the security benefits of Rust had been achieved; has there been, for example, any fuzz testing of the server? Almeida answered that the Rust-based parsing interface makes a lot of mistakes impossible. No fuzz testing has been done — the server has only been working for a couple of weeks — but he will do it. He concluded that he will be interested to see how his server fares in such testing relative to the QEMU implementation.

In other words "no we haven't actually tested it but I'm sure the language prevents bugs, they're totally impossible". Yeah right. This is typical of the Rust community: huge promises, no evidence to back them up, all topped off with an "if it compiles it is correct" attitude that totally disregards that there are many more issues other than those the Rust people have decided count as 'safety'.

Anyone noticed that 'unsafe' as a general concept has suddenly been redefined to mean 'whatever Rust prevents' (if you don't use `unsafe`, which the Rust for linux code does all over the place)? When people involved in Rust's development realised just before the release of the language that the language was fundamentally unsound, allowing memory leaks, they quietly redefined 'safety' to exclude leak freedom, because they didn't have time to properly fix it before 1.0. This was despite months and years of telling people how wonderful Rust was because it prevented memory leaks, lol. This should come as no surprise from the same group of radicals that redefine words on a daily basis from what everyone in the world understood them to mean, inside and outside technology. 'Master branch' is an (attempted) victim of the same ideology - nothing, not even in the truth, will stand in their way.

The entire idea is horrible. I do not want a Rust compiler on my computer, I do not want to need a Rust compiler on my computer to be able to compile the kernel. Rust is 'trusting trust' on steroids, for one thing. It is incredibly slow. Compiling a kernel takes long enough as it is! It's specified as 'whatever rustc does'. It has one implementation, with no other implementations even remotely close to being ready (there are other "implementations", but they are nowhere near complete and cannot do borrow checking, the core feature of the language, so are practically useless.) It is an abhorrently complex language. Nobody has EVER explained what it provides to the kernel that Ada or better static analysis tools for C could not. The ONLY thing Rust has going for it is an incredibly pushy "community". They say "oh it will only be in a few drivers". Yeah, at first. But there's no real point doing it if there's not going to be a lot of it. And that means SLOW compile times and an inability to bootstrap reliably.

Anyway, let's be real: Rust is just not going to happen in the kernel. Rust can express legibly only one way of managing memory. Nobody has even managed to represent the Wayland memory model in Rust, and the kernel is far more complicated than that. The one serious attempt to do so failed after months of work because it required writing thousands upon thousands of lines of memory management boilerplate. If you want to represent anything more complex than Box or Rc you need to just about write a thesis.

And look at the code itself. There's a huge list of nightly (basically brand new!) compiler features that are required to build it. No way should there be code in the Linux kernel that requires anything other than stable language features. At least one of them is described as "Status: the current design is perma-unstable -- a new RFC is needed. The issue may be split." And generic associated types have been in progress for more than 5 years with no real sign that they're going to be stabilised any time soon.

And last I checked, 'async' in Rust is widely considered a failure of design.

A pair of Rust kernel modules

Posted Sep 13, 2022 13:10 UTC (Tue) by PengZheng (subscriber, #108006) [Link] (5 responses)

Thank you very much for stopping me from reading a Rust book, successfully.

I'd better invest that time learning C++20/23.

A pair of Rust kernel modules

Posted Sep 13, 2022 14:04 UTC (Tue) by reijoslav (guest, #98915) [Link] (3 responses)

The comment you're replying to seems to be pretty trolly. The author has actually been banned from some other sites with the reason "Troll".

A pair of Rust kernel modules

Posted Sep 13, 2022 14:45 UTC (Tue) by Wol (subscriber, #4433) [Link] (1 responses)

Said trolly author has clearly never heard of a Turing Machine, so yes ...

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 14, 2022 6:18 UTC (Wed) by milesrout (subscriber, #126894) [Link]

I'm perfectly aware of turing machines.

A pair of Rust kernel modules

Posted Sep 14, 2022 6:19 UTC (Wed) by milesrout (subscriber, #126894) [Link]

Accusing someone of "trolling" because they disagree with you is not constructive. Ironically, what you are doing is actually trolling...

A pair of Rust kernel modules

Posted Sep 15, 2022 21:13 UTC (Thu) by thecodedmessage (guest, #160911) [Link]

This poster is saying some true things in a loaded way to make them seem bad when they're actually reasonable. Rust is a tool, and it can't do everything that people sometimes carelessly claim about it. But that doesn't mean C++ is just as good, or that Rust experts make these claims.

Rust does not eliminate all bugs. It's true that Rust's safety features only prevent the behaviors that they're designed to prevent. Of course that's true -- no programming language can prevent all bugs, but Rust's safety features do prevent some very bad types of memory corruption that are infamous for causing problems in C and C++. Additionally, even 'unsafe' Rust does a better job at preventing those failures than C++, which in many cases doesn't even give you any tools to manage the problem, relying instead entirely on the programmer.

And yes, they tried to eliminate memory leaks in safe code and then realized that wasn't an achievable goal in line with their other goals. That doesn't mean that Rust is bad. Rust is much better at preventing memory leaks than C++, but it is still possible to leak memory. It's way harder to do by accident, though.

Rust is better than C++. The fact that it's not utopian or perfect doesn't mean that it's not better.

A pair of Rust kernel modules

Posted Sep 13, 2022 15:06 UTC (Tue) by rav (guest, #89256) [Link] (6 responses)

> And generic associated types have been in progress for more than 5 years with no real sign that they're going to be stabilised any time soon.

Actually, under two hours after your comment, generic associated types were stabilised: https://github.com/rust-lang/rust/pull/96709#issuecomment...

A pair of Rust kernel modules

Posted Sep 14, 2022 6:05 UTC (Wed) by ssmith32 (subscriber, #72404) [Link]

Gotta ❤️ hard-working, active communities.. !

A pair of Rust kernel modules

Posted Sep 14, 2022 6:21 UTC (Wed) by milesrout (subscriber, #126894) [Link] (4 responses)

Which has still taken 4 years longer than it had any reason to take. C++ and Haskell have both had these features for years. There's a huge amount of prior art. There's no excuse for it to take this long.

A pair of Rust kernel modules

Posted Sep 14, 2022 11:30 UTC (Wed) by jezuch (subscriber, #52988) [Link] (2 responses)

I absolutely love it that they had 5 years to reflect and make sure that it doesn't introduce any subtle warts and that it integrates well into not only current but also upcoming features of the language. It will be with us until forever, after all, and you can't fix it once it's delivered. For the same reason I'm excited about the evolution of Java (yes! Java!). Some of the features there (like Project Valhalla) have been baking for even longer than that. AND IT'S A GOOD THING. Brian Goetz, who leads these efforts, even says that if after all this time someone says "Why on earth did it take you so long? It's such a simple and obvious feature!", then it means that this was time well spent. Because if they delivered it sooner, then it would neither be simple nor obvious.

Python, on the other hand... ;)

A pair of Rust kernel modules

Posted Sep 14, 2022 11:47 UTC (Wed) by Wol (subscriber, #4433) [Link] (1 responses)

> Brian Goetz, who leads these efforts, even says that if after all this time someone says "Why on earth did it take you so long? It's such a simple and obvious feature!", then it means that this was time well spent. Because if they delivered it sooner, then it would neither be simple nor obvious.

Cleanliness and simplicity in design is just SO important! I go on about WordPerfect, about INFORMATION (sadly defunct but my favourite Pick), precisely *because* they set out to have simple logic / design and clean implementation.

I've been tripping over a Word bug for ages, and I've suddenly realised the problem - if a table extends over multiple pages it screws up printing! When printing labels, I often have grief with the printer so I get the first page and nothing else. If you try to start printing from page 2, it seems Word gets lost, assumes the entire table is on page 1, and prints nothing! WTF?

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 14, 2022 15:42 UTC (Wed) by rschroev (subscriber, #4164) [Link]

Try printing to PDF first (Windows nowadays has a built-in virtual printer for that), then printing out that PDF. That workaround can sometimes work wonders for applications that don't handle printers and their quirks very well.

It's sad of course that workaround like this are needed for any application, and double (or more) so for a high-profile word processor.

A pair of Rust kernel modules

Posted Sep 14, 2022 15:21 UTC (Wed) by khim (subscriber, #9252) [Link]

> There's no excuse for it to take this long.

Seriously? Modern, multithreaded OS kernels exist which means you should be able to create something like that in jiffy. Show me how, please. After we would benchmark it and compare to Linux and other popular kernels you would have a case.

> C++ and Haskell have both had these features for years.

And in both cases it took more than a decade to develop these. I still remember time when rebind only existed in the standard, but not in G++.

> There's a huge amount of prior art.

The fact that there are “huge amount of prior art” doesn't assert certain feature is easy, sorry.

A pair of Rust kernel modules

Posted Sep 13, 2022 16:12 UTC (Tue) by ssokolow (guest, #94568) [Link] (17 responses)

Anyone noticed that 'unsafe' as a general concept has suddenly been redefined to mean 'whatever Rust prevents' (if you don't use `unsafe`, which the Rust for linux code does all over the place)? When people involved in Rust's development realised just before the release of the language that the language was fundamentally unsound, allowing memory leaks, they quietly redefined 'safety' to exclude leak freedom, because they didn't have time to properly fix it before 1.0. This was despite months and years of telling people how wonderful Rust was because it prevented memory leaks, lol.

No, the "leakpocalype" (There's your googleable keyword) was specifically about the realization that the original version of the scoped threads API that got re-added recently was unsound because it didn't account for Arc<T> and a reference cycle allowing you to leak memory and, as such, allowed code not marked with "unsafe" to create pointers that outlived what they pointed to.

There was nothing "quietly" about it, and the thing they didn't have time to properly fix before 1.0 was the scoped threads API. It was already clear that preventing memory leaks in the the general case was a Rice's theorem problem. (Among other reasons, it's a good hint it might be when you can "leak memory" in the "same externally observed properties" sense in JavaScript just by losing track of which event handlers you've forgotten to unregister.)

It's specified as 'whatever rustc does'.
As opposed to "whatever GCC does" like the dialect of C that the Linux kernel requires, which LLVM is still working to perfectly replicate?
Nobody has EVER explained what it provides to the kernel that Ada or better static analysis tools for C could not.

Ada is more focused on constraining integer types, which requires more runtime support, which makes it a worse fit for interoperating with an existing C kernel. Also, I don't have a citation for this, but I remember reading a comment that it's misleading to look at GCC's platform support and assume that GNAT has proper support for all those platforms.

(And then there's the fact that Ada's more Wirth-style syntax feels more alien to the average 21st-century programmer than Rust's "Ocaml in a C++ trench coat" syntax does, and part of the interest in Rust is in heading off the "COBOL programmers get paid a ton because demand is outstripping supply" problem the kernel might face in the coming decades.)

As for "better static analysis tools", I've used Splint. Annotating C with the information needed to prove the relevant properties at compile time rapidly makes the code less readable than the equivalent Rust. That's why you generally don't see people just extending C to get the same results.
And last I checked, 'async' in Rust is widely considered a failure of design.

Citation, please. The people I've seen tend to say that it's an impressive exercise in pushing the boundaries for what can be achieved without tracing garbage collection.

A pair of Rust kernel modules

Posted Sep 13, 2022 21:02 UTC (Tue) by NYKevin (subscriber, #129325) [Link] (16 responses)

How does anyone come to the conclusion that Rust is "supposed to" prevent memory leaks, when Box has a whole convenience function specifically for leaking memory? It boggles the mind.

https://doc.rust-lang.org/std/boxed/struct.Box.html#metho...

A pair of Rust kernel modules

Posted Sep 14, 2022 1:54 UTC (Wed) by milesrout (subscriber, #126894) [Link] (1 responses)

Feel free to check when that function was added

A pair of Rust kernel modules

Posted Sep 14, 2022 17:14 UTC (Wed) by lambda (subscriber, #40735) [Link]

> Feel free to check when that function was added

mem::forget was the original variant of this, and it was stabilized as safe pre-1.0 https://doc.rust-lang.org/std/mem/fn.forget.html . It was originally marked as unsafe (in earlier pre-1.0 releases), but when it was realized that safety invariants couldn't depend on destructors being guaranteed to run, it was changed to be marked as safe in order to make that point more clear.

Box::leak is just a newer variant that provides a nicer API, allowing you to extract a reference to the leaked value at the same time.

It was always known that it was possible to leak memory by forming a reference counted pointer cycle, but it was fairly late in the pre-1.0 process that folks realized the interaction between this fact, and some proposed APIs that required blocking in a destructor in order to keep a stack frame alive, were incompatible. There was a long and reasoned discussion about it, and the Rust team decided that because it's not possible to categorically prevent resource exhaustion in a Turing complete language, that it was better to have the rules for what could be done in safe code include leaking memory (or otherwise failing to run destructors), and then code that provides safe abstractions has to keep that in mind, so you couldn't rely on blocking in a destructor to keep a stack frame alive.

It took some time in the development of Rust to figure out what the rules should be for what is marked as "safe" vs "unsafe"; you might imagine that any kind of undesirable behavior, like memory leaks, should be considered unsafe. But the distinction that the Rust project ended up on, and I think is the right decision, is that unsafe is only required for operations which could lead to undefined behavior. Rust provides tools to help prevent other kinds of undesirable behavior, like destructors that free memory for you when exiting a stack frame, but it won't refuse to compile code in which you set up a reference cycle and thus leak memory, as the behavior in that case is perfectly well defined, you just use more resources and may eventually run out.

Does this make sense to you? I feel like you are implying that there has been some massive rug-pull about what safety guarantees Rust provides, while Rust never guaranteed freedom from resource exhaustion, and during the run-up to 1.0 there was some learning about exactly the kind of guarantees you could make about when destructors were run, and some updates to the understanding of what unsafe code could rely on based on that and some engineering tradeoffs. If I'm misunderstanding your implication, or not explaining this clearly enough, let me know!

A pair of Rust kernel modules

Posted Sep 14, 2022 3:08 UTC (Wed) by khim (subscriber, #9252) [Link]

If language is serious about memory leaks then it have to provide tools which leak memory.

This may sound paradoxical, but it's not. If you define “memory leak” as something crazy and mostly useless (like tracing-GC languages do: it's not a memory leak if objects can be accesses by “live pointers”… even if program have no code which may actually ever access these objects) then you may “prevent them” but this wouldn't do anyone any good.

Either your language allows memory leaks by losing track of which event handlers you've forgotten to unregister or it's not a general-purpose language.

And if you admit that layman-definition memory leaks (as in: something which takes infinite amount of memory as time goes on is a memory leak, period) are impossible to prevent then having function which is specifically dedicated to creating persistent objects is obvious choice: this means that objects generated by that function can be treated specially by sanitizers, etc.

Lisps typically have these these to implement interning, e.g.

A pair of Rust kernel modules

Posted Sep 14, 2022 6:22 UTC (Wed) by milesrout (subscriber, #126894) [Link] (12 responses)

Added in 2017, long after Rust 1.0.

https://github.com/rust-lang/rust/pull/45881

A pair of Rust kernel modules

Posted Sep 14, 2022 6:35 UTC (Wed) by zdzichu (guest, #17118) [Link]

Meh, I've expected it would be an April 1st commit. I'm dissapointed.

A pair of Rust kernel modules

Posted Sep 14, 2022 9:10 UTC (Wed) by wtarreau (subscriber, #51152) [Link] (9 responses)

Wow: Box::leak<'a>(Box<T>) -> &'a mut T where T: 'a

Are there really people who can parse this ? And how is that supposed to be pronounced ? That's still one of the biggest showstopper for me in this language, coding entirely with smileys. There are 16 symbols for 24 alphanumeric chars in this statement, I have no idea what this could mean at all nor whether that generates some code or only declares stuff. Go find a typo there... It's totally cryptic to me :-(

A pair of Rust kernel modules

Posted Sep 14, 2022 10:28 UTC (Wed) by ssokolow (guest, #94568) [Link] (4 responses)

Hey, it's a lot easier to understand than C function pointer syntax and you get a lot more guarantees out of it too.

For the record, that says:

  1. Member of "Box" named "leak"
  2. Has one lifetime parameter named "a" (<a'> is a bit odd because it's actually two different "this is a generic" syntaxes smushed together. < and > from C++ denote the list of generic type parameters, and the leading apostrophe is a reurposing of Ocaml's syntax for generics, because lifetimes are a special kind of generic type parameter and Rust is sort of an ML-family language in a trench coat, to the point where the Rust compiler was written in OCaml before it became self-hosting.
  3. Takes one argument of type "Box<T>" where T is a generic parameter.
  4. Returns a mutable reference to whatever type T the box contained with lifetime "'a"
  5. Returns neither a raw/FFI pointer nor something wrapped in Option<T>, so it's non-nullable.
  6. Does not wrap the return value in Option<T> or Result<T, E>, so the operation is considered infallable barring system abstractions failures such as power outages, cosmic ray bit flips, etc.
As for that "where" clause, that's incorrect. The signature is actually
pub fn leak<'a>(b: Box<T, A>) -> &'a mut T
where
    A: 'a,

That "A" generic is the allocator and defaults to the configured global allocator, which defaults to libc's malloc, so the "where A: 'a" part is saying that it will return a mutable reference that must not outlive allocator that was used to allocate what it points to.

It comes from the declaration for the Box struct as a whole:

pub struct Box<T, A = Global>(_, _) 
where
    A: Allocator,
    T: ?Sized;

("?Sized" is used to opt out of the default "only types with sizes known at compile time" constraint... which is particularly relevant here because, in type constraint terms, Box is a wrapper to convert an unsized type into a sized type.)

A pair of Rust kernel modules

Posted Sep 14, 2022 15:16 UTC (Wed) by milesrout (subscriber, #126894) [Link] (3 responses)

C function pointer syntax is absolutely trivial. If you know how to write expressions you know how to write type expressions.

If you have A, an array of pointers to functions that take an integer, a function taking int and returning int, and a pointer to a string, and which returns void*, how do you call it?

A[0] // get one of the function pointers
(*A[0]) // dereference the pointer
(*A[0])(1, f, "hello") // call it

How do you write the type?

int (*fps[])(int, int(*)(int), const char *);

It's almost exactly the same as calling it. This is well known. It is not difficult or complicated, and is far easier to understand than the line noise that is Rust or Perl. In Rust or C++ you need to learn about a hundred different sublanguages to learn the language proper. In C, the declaration and use syntax are almost exactly the same. Once you know one, you know the other.

A pair of Rust kernel modules

Posted Sep 14, 2022 16:15 UTC (Wed) by khim (subscriber, #9252) [Link]

> In C, the declaration and use syntax are almost exactly the same. Once you know one, you know the other.

And in LISP it's even more uniform thus easier, right? Everyone uses lisp, right? No? Not everyone? But why?

Think about it.

> It's almost exactly the same as calling it.

If you forget about the fact that for function which returns function (like already mentioned void (*signal(int, void (*)(int)))(int)) it doesn't work. That function have two arguments yet ends with (int) somehow. And about the fact that standalone variable declared as int x[3]; has entirely different type from argument of function declared in the same fashion. And about bazillion other similar quirks.

Yes, C is simple if you ignore details. Which invariably bites you in the ass later. While Rust makes sure you wouldn't forget about details.

Yes, it's different strategy, but it works much better for the large or huge projects where hundreds or thousands people work on the same codebase.

A pair of Rust kernel modules

Posted Sep 14, 2022 19:27 UTC (Wed) by ssokolow (guest, #94568) [Link]

The fact that the Clockwise/Spiral rule exists, and that I've had to look at this page more than once over the years, seems to disagree.

https://c-faq.com/decl/spiral.anderson.html

I never had to refresh my memory of how Rust type signatures worked back in the days before I started using it actively.

A pair of Rust kernel modules

Posted Sep 20, 2022 22:25 UTC (Tue) by amarao (guest, #87073) [Link]

For any pythoner c-style end of a function looks like wierd smiles too ); or ;}. And logic operations are terrible ! a&&b||c. Compare with not a and b or c.

So when you mock rust for syntax, don't forget about !!a>>b%c&&--d--.

A pair of Rust kernel modules

Posted Sep 14, 2022 11:04 UTC (Wed) by excors (subscriber, #95769) [Link] (1 responses)

I think it's not that complicated if you start learning Rust from a book that gradually introduces all the concepts and syntax (like https://doc.rust-lang.org/book/). But you can't expect to automatically know what it means without putting some effort into learning the language, even if you're already very familiar with e.g. C++.

You can start with the basic syntax for declaring a struct, and an associated function that can be called with an argument of that type, which is pretty straightforward:

struct Foo {
  val: i32,   // i32 is the 32-bit signed integer type
}
impl Foo {
  fn bar(f: Foo) -> i32 {   // return type is i32
    f.val
  }
}

Then you make it generic by replacing 'i32' with a type parameter T (similar to C++ templates):

struct Foo<T> {
  val: T,
}
impl<T> Foo<T> {
  fn bar(f: Foo<T>) -> T {
    f.val
  }
}

Instead of returning a copy of the value, you might want to return a reference. References are either shared ("&T") or exclusive ("&mut T"), where an exclusive reference cannot exist simultaneously with any other reference to the same object. Since Box::leak consumes the object and returns a single reference, it can be exclusive:

fn bar(f: Foo<T>) -> &mut T {
  // ...
}

But reference types have lifetimes (so the compiler can verify the reference won't outlive the object it's referring to). That's one of the major new concepts in Rust, so you need to spend time learning about that. Often it all works automatically with no extra syntax and you don't even need to think about it, but if you're doing something slightly tricky then you need to explain it to the compiler. For Box::leak we can safely return a reference with any lifetime (because that will always be shorter than the (infinite) lifetime of the leaked object), so we make the function generic over an unconstrained lifetime parameter 'a (similar to making it generic over a type T), and use that lifetime for the reference:

fn bar<'a>(f: Foo<T>) -> &'a mut T {
  // ...
}

There's also a potential issue if T contains references to other objects - even though the leaked T is given an infinite lifetime, it may refer to objects with shorter lifetimes, and it's not safe to access the T after those objects' lifetimes. So we add an extra constraint to say that T's lifetime (which (I think) is defined as the lifetimes of any references contained within T) must be as long as 'a:

fn bar<'a>(f: Foo<T>) -> &'a mut T
  where T: 'a
{
  // ...
}

But that's not actually required for safety (the original patch says "Technically not needed, but kept to be explicit." and it was removed in later versions) - I think the borrow checker already prevents that potential issue.

And that matches the original definition of Box::leak. (It doesn't quite match the GitHub issue title you quoted, but they just improvised syntax to make it more concise. And it doesn't quite match the modern definition of Box::leak because they added the allocator type parameter.)

It looks intimidating at first, but I think it's okay when you go step by step with a willingness to learn. And this is a relatively complicated example - most Rust code doesn't need to be explicit about lifetimes, the default behaviour is usually sufficient.

A pair of Rust kernel modules

Posted Sep 14, 2022 14:59 UTC (Wed) by mbunkus (subscriber, #87248) [Link]

Thank you, ssokolow & excors, for two very nice explanations.

A pair of Rust kernel modules

Posted Sep 14, 2022 11:08 UTC (Wed) by khim (subscriber, #9252) [Link] (1 responses)

> Are there really people who can parse this ?

Sure. It's actually easier to parse than something like void (*signal(int, void (*)(int)))(int);.

I mean: is it a function? Or pointer? Where are arguments? Heck, how many arguments are there?

Rust code can be parsed from left to right, at least.

> And how is that supposed to be pronounced ?

How is the definition of signal is supposed to be pronounced?

> There are 16 symbols for 24 alphanumeric chars in this statement

And 13 symbols for 20 alphanumeric chars in C is, somehow, radically better?

> It's totally cryptic to me :-(

Well… if you don't know the language, of course it would be cryptic. But Rust syntax while ugly, serves a purpose: it makes code similar to C++. And, as I have already mentioned, is actually easier to parse than C or C++. Yes, it's punctuation-heavy, but you can blame C and C++ for that: most sigils have come into Rust from there. Only 'a is new but Ada uses such syntax, too.

I still hate Rust syntax (much less elegant than it could have been), but it's useful uglyness: it makes Rust look superficially similar to C++. Which is important mimicry not to spook C++ developers before they would be hooked.

A pair of Rust kernel modules

Posted Sep 14, 2022 19:33 UTC (Wed) by Dr-Emann (guest, #136829) [Link]

For anyone actually trying to parse the signal type, it helps a lot to have a typedef:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
The equivalent in rust is still pretty readable without a typedef:
fn signal(signum: c_int, handler: fn(int)) -> fn(int)

A pair of Rust kernel modules

Posted Sep 14, 2022 22:25 UTC (Wed) by NYKevin (subscriber, #129325) [Link]

Was it absolutely necessary to post two different replies both (essentially) saying the same thing? Especially considering that, as another commenter pointed out, mem::forget is significantly older, so your argument is not even correct.

A pair of Rust kernel modules

Posted Sep 13, 2022 18:23 UTC (Tue) by lambda (subscriber, #40735) [Link] (17 responses)

I'm sure I shouldn't be replying to the troll, but since other folks reading might be misled by this comment, I figure I should provide some clarifications.

> So in other words: oh yes, there are still bugs, but we can just blame them on C. Any issues with interfacing Rust and C? Obviously the fault of C.

The fundamental unique feature of Rust is that it enables you to build safe abstractions around unsafe code (we'll get to what "safe" means in a bit). Whether you are interfacing with C, or defining your own primitives in Rust, doing that can be tricky, but once it's done, you have fairly strong guarantees on what can happen in the safe code that uses those abstractions.

So, this isn't "blaming bugs on C", but just an acknowledgement that Rust is not a silver bullet (and has never been intended as such), and that the fundamental work of building safe abstractions over unsafe code still requires care. Since there are a large number of abstractions that already exist in the Linux kernel, interoperating with them requires work, and there will be bugs in the process.

> In other words "no we haven't actually tested it but I'm sure the language prevents bugs, they're totally impossible".

You're attacking a strawman here. No one has ever said that bugs are totally impossible.

> Anyone noticed that 'unsafe' as a general concept has suddenly been redefined to mean 'whatever Rust prevents'

"Unsafe" in Rust means "can do things that could potentially be undefined behavior" or in other words, could potentially have executions which have no valid behavior under the language model. And as a Turing-complete, general purpose language, Rust is not intended to prevent you from making logic bugs, infinite loops, or resource leaks; it does have a number of design features that help make them more difficult to make (RAII, exhaustive match statements, etc), but it makes a hard distinction between things that it prevents categorically, and things that the language design helps with but doesn't prevent entirely.

And this definition is part of a contract between the compiler, standard library, and libraries that provide safe abstractions over unsafe code. There needs to be a definition of what rules such libraries need to follow, and what assumptions they can make, so that you can combine two different libraries which each provide safe abstractions over unsafe code, and the combination itself will continue to be safe.

So this particular set of rules are "whatever Rust prevents." As an example, pre-Rust 1.0, there were some API designs that were safe only if it was impossible to leak an object and return to the caller; but of course, reference counted pointers could be set up to cause a cycle and leak an object. There was a long involved discussion of this, with various proposals, but in the end, it was decided that categorically preventing leaks would impose too much burden on language and library design; for instance, it would require a much more complicated system for reference counted objects in order to prevent circular references, and impose similar design burdens many other kinds of data structures. So rather, it was decided that leaking objects wasn't something that would be categorically prevented in safe code, and libraries that provide safe abstractions over unsafe primitives can't depend on an object not being leaked for their safety guarantees.

So that's just part of the contract now; there were alternative possibilities for that contract, which would have had different tradeoffs, but this was the tradeoff chosen.

Effectively, what is forbidden in safe Rust is anything which could cause objects to be interpreted as the wrong type, accessed when they are not valid, or accessed in overlapping ways in space or time. This means no out of bounds access, use after free, data races (two threads accessing the same memory in ways that no linear interleaving could produce), iterator invalidation, etc. This is a category of bugs which are quite common in C and C++ programs, which are difficult to reason about because they effectively break the model of the programming language, and are quite commonly prone to exploitation by attackers.

Leaking an object, on its own, does not lead to arbitrary behavior; it's undesirable, and can lead to resource exhaustion, but in any Turing complete language you could write code which never halts or uses up an arbitrary amount of resources.

> because they didn't have time to properly fix it before 1.0

This is not true. It was not the case that "they didn't have time to properly fix it", it's that there is no way to statically prevent leaking of resources in a way that would not be overly burdensome on the API of data structures.

> This was despite months and years of telling people how wonderful Rust was because it prevented memory leaks, lol.

No one has ever claimed that Rust prevented memory leaks. Reference counted types have existed from the beginning, and everyone has always known that it's possible to create reference counted cycles and leak memory that way. Anyone who thought that Rust was supposed to prevent all memory leaks likely misinterpreted the term "memory safety", which is a term that predates Rust, and refers to preventing unsafe access to objects, not preventing leaking of objects.

> Rust is 'trusting trust' on steroids, for one thing.

There are at least two independent bootstrap paths currently possible for the Rust compiler; you can start from the original pre-1.0 compiler written in OCaml and bootstrap from release to release that way. Or there is an independent compiler, mrustc, written in C++ which is able to compile much more recent releases of rustc and start the bootstrap chain that way. This provides the diverse double compilation necessary to defeat trusting trust attacks.

> Nobody has EVER explained what it provides to the kernel that Ada or better static analysis tools for C could not.

Kernel developers are interested in writing kernel code in Rust, not Ada. Ada is far more foreign, and wasn't designed for the same kind of interop with C and encapsulation of unsafe code behind safe interface that Rust was.

A lot of people focus on the safety guarantees of Rust, because it has a unique approach to safety that no other language provides. But besides that, it's a modern language with a lot of nice features that many developers appreciate, and with a focus on balancing those safety goals with usability, performance, and interop with existing ecosystems like C.

"Better static analysis" can only get you so far. The language level support that Rust provides means that you design your APIs around the type system and lifetimes, which means that code can be statically checked independently and separately; the lack of such guarantees and annotations in C makes it far more difficult to add static checking that is anywhere near as robust as what Rust provides out of the box. It's not for lack of trying; people have been writing static checkers for C and C++ for decades, and yet memory safety errors still cause the majority of security vulnerabilities in codebases written in C and C++.

> It's specified as 'whatever rustc does'. It has one implementation, with no other implementations even remotely close to being ready

You realize that the same was true of C in the kernel until relatively recently, right? The kernel is not written in standard C; it's written in GCC C. The kernel has a memory model that is different than the standard C memory model. The kernel is now mostly able to be built with clang as well, but only by years of effort of adding GCC features to clang and modifying the kernel to not rely on them in quite as many places.

There is a Rust reference, and ongoing efforts on continuing to specify Rust, but this is mostly irrelevant to its usage in the kernel.

> There's a huge list of nightly (basically brand new!) compiler features that are required to build it. No way should there be code in the Linux kernel that requires anything other than stable language features.

An unstable feature in Rust is much like an implementation-specific feature in C; and the kernel uses plenty of GCC features. It's a way of providing some features without committing to supporting that feature in exactly that form indefinitely; there may be backwards incompatible changes in the future. Implementation-specific features in GCC may be replaced by standardized C features in the future, but that doesn't mean they aren't used in the kernel.

The entirety of the internal Linux kernel API is considered unstable, Linux only provides a stable interface to userspace; does that mean that no one writing code in one part of the kernel should depend on code in another part because it's unstable? No, it just means that changes to libraries within the kernel may need to be propagated to usages as well. The same is true of these unstable Rust features; you opt into a few, with the knowledge that you may need to make changes later on when upgrading compilers. It's something you shouldn't use willy-nilly, but using a few features where you may need to make changes in the future is not that big a deal.

These aren't being used with abandon; there is a tracking issue explaining all unstable features, and standard library config flags, what they are needed for, how essential they are, whether they're on track to stabilization, etc: https://github.com/Rust-for-Linux/linux/issues/2

Some of them will be stabilized in Rust, some will be removed from the kernel, and some will be lived with.

> (basically brand new!)
> generic associated types have been in progress for more than 5 years with no real sign that they're going to be stabilised any time soon.

Ok, besides the fact that as someone else pointed out, this feature was agreed to be stabilized within hours of your post (it had already been in final comment period for a while), it's funny that you call these features "basically brand new" while also acknowledging that some of thems have been undergoing serious development for years.

> Nobody has even managed to represent the Wayland memory model in Rust, and the kernel is far more complicated than that. The one serious attempt to do so failed after months of work because it required writing thousands upon thousands of lines of memory management boilerplate. If you want to represent anything more complex than Box or Rc you need to just about write a thesis.

There are hundred of crates that provide memory management primitives beyond Box and Rc (https://lib.rs/memory-management), plus numerous examples of successful integration of Rust into C and C++ projects with custom memory management, including Firefox.

There was one project in which someone attempted to provide a general-purpose rust API over wlroots, a C Wayland library, and eventually decided that it wasn't worth it for their purposes. That doesn't mean it's impossible; just that one person tried one approach, didn't like it, and decided it wasn't what they wanted to spend their time doing.

> And last I checked, 'async' in Rust is widely considered a failure of design.

So much of a failure of design that it's being used for substantial production usage like an entire rewrite of the Tor client in Rust in two years: https://blog.torproject.org/arti_100_released/

There are gripes that folks have with aspects of async in Rust; but it's actually a very well received, widely used feature, that just happens to be a little bit young and has had some ecosystem growing pains.

A pair of Rust kernel modules

Posted Sep 14, 2022 9:45 UTC (Wed) by wtarreau (subscriber, #51152) [Link] (11 responses)

> Effectively, what is forbidden in safe Rust is anything which could cause objects to be interpreted as the wrong type, accessed when they are not valid, or accessed in overlapping ways in space or time. This means no out of bounds access, use after free, data races (two threads accessing the same memory in ways that no linear interleaving could produce), iterator invalidation, etc. This is a category of bugs which are quite common in C and C++ programs, which are difficult to reason about because they effectively break the model of the programming language, and are quite commonly prone to exploitation by attackers.

But it could also be said that several other categories of bugs are avoided in C thanks to the language being quite primitive and reading fairly well and being suitable for peer reviewing. Do you have an estimate of the increased amount of logic bugs or algorithmic ones that could be caused by the language being significantly more difficult to use when it resists to your demands ? For example I've been caught many times adding bugs when trying to simply shut up an inappropriate gcc warning. When a compiler tries to force you to do something one way that doesn't match your need, the friction introduces new risks of bugs.

> > This was despite months and years of telling people how> wonderful Rust was because it prevented memory leaks, lol.
> No one has ever claimed that Rust prevented memory leaks.

Note, the two of you said at least once "nobody shows" or "nobody claimed" etc. It's pointless to use such rhetoric. It doesn't add any value and needlessly increases tensions because anyone can have one personal counter example. I've personally heard someone tell me the point above for example, and that irritated me because I knew it was an absurd claim. Actually saying "no authoritative developer said/demonstrated/claimed", or even better "I've never heard any ..." would be easier to deal with for both parties in the discussion.

> > It's specified as 'whatever rustc does'. It has one implementation, with no other implementations even remotely close to being ready
> You realize that the same was true of C in the kernel until relatively recently, right? The kernel is not written in standard C; it's written in GCC C. The kernel has a memory model that is different than the standard C memory model. The kernel is now mostly able to be built with clang as well, but only by years of effort of adding GCC features to clang and modifying the kernel to not rely on them in quite as many places.

I can understand this concern and I do share it as well. Not directly for the kernel in fact, rather for the language's life expectancy. 15 years ago I was told that Ruby was *the* language of the future, that prevented bugs etc... (hint: it just made them slower to appear). Now in 2022 can anyone cite any developer not working for Gitlab still using this language ? I do have the same concern about Rust: as long as it remains the self-defined input of rustc, it's not exactly a language and it can seriously fail over time. Serious implementations are absolutely required for it to survive. For sure Linux uses GCC C. But C is used everywhere and runs the whole internet, some built with gcc, some with any other compiler. It maintains an ecosystem afloat and forces implementations from various origins and use cases to exchange and evolve the standard. Rust does need to adopt a similar approach where there is no more *the* leading implementation and a few others trying to catch up like clang does with gcc or gnugo does with Go, but a set of slightly different implementations all following one standard to reach a 100% compatible code base. From there it's fine if some projects decide to only use one flavor for various reasons.

A pair of Rust kernel modules

Posted Sep 14, 2022 10:53 UTC (Wed) by Wol (subscriber, #4433) [Link] (6 responses)

> Rust does need to adopt a similar approach where there is no more *the* leading implementation and a few others trying to catch up like clang does with gcc or gnugo does with Go, but a set of slightly different implementations all following one standard to reach a 100% compatible code base. From there it's fine if some projects decide to only use one flavor for various reasons.

That is incredibly difficult to achieve. For two perfect examples from the database arena, SQL and DataBASIC. There's a whole bunch of subtle differences between SQL dialects, as many people here will be able to attest. Likewise, although far fewer people here are familiar with it, DataBASIC. Both have multiple competing implementations, and there are many corner cases where early design decisions collide badly with compatibility - my favourite DataBASIC statement

REM: REM = REM(6,3); REM this takes the remainder of 6 / 3

Every single usage of REM makes sense, and is legal in at least one DataBASIC compiler, but trying to support all four in this one statement is, well, tricky ... (I believe at least one does, probably OpenQM/ScarletDME.)

We're likely to end up with just the one implementation of rust just to get round the dialect problem. Like most C code is written to the "it compiles with gcc" standard for exactly the same reason.

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". And if we do get the kernel compiling successfully with llvm/clang we could rapidly hit a tipping point where new code supports the "well it compiles with llvm/clang" standard.

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 14, 2022 15:42 UTC (Wed) by khim (subscriber, #9252) [Link] (5 responses)

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

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

A pair of Rust kernel modules

Posted Sep 14, 2022 13:56 UTC (Wed) by tialaramex (subscriber, #21167) [Link]

> For example I've been caught many times adding bugs when trying to simply shut up an inappropriate gcc warning.

If the warning is inappropriate in Rust, simply explain why in the source code

// We genuinely need Drop here, see https://some.example/url
#[allow(drop_bounds)]

And we can promote a warning in the opposite way

// We tried asking people nicely, it didn't work. If you write an overlapping range this won't compile. Learn to count.
#[forbid(overlapping_range_endpoints)]

A pair of Rust kernel modules

Posted Sep 14, 2022 15:35 UTC (Wed) by lambda (subscriber, #40735) [Link]

> But it could also be said that several other categories of bugs are avoided in C thanks to the language being quite primitive and reading fairly well and being suitable for peer reviewing. Do you have an estimate of the increased amount of logic bugs or algorithmic ones that could be caused by the language being significantly more difficult to use when it resists to your demands ? For example I've been caught many times adding bugs when trying to simply shut up an inappropriate gcc warning. When a compiler tries to force you to do something one way that doesn't match your need, the friction introduces new risks of bugs.

I have not noticed any such tendency in Rust.

One of the advantages of Rust is that the more powerful type system, and a number of language design features, make a lot of things more explicit and possible for the compiler to reason about precisely. For instance, reference types and nullability are orthogonal, so you don't have to constantly add checks for null; the type tells you if a reference could possibly be null, and so there there can be fewer spurious compiler warnings due to the higher precision of the type system.

Another example would be warnings about use of uninitialized value, like the famous Debian SSH key bug that was introduced by trying to silence a warning about use of uninitialized values. Because this warning was found by someone later who wasn't the original author, they weren't as familiar with the code when trying to fix it, and they made a mistake and removed the actual source of entropy that was being used as well as the uninitialized value. In Rust, this is not a separate warning, but part of the language, so it's something that needs to be dealt with by the original author, rather than by someone else later on trying to silence warnings and not paying enough attention.

That's one of the major design goals of Rust; rather than having to rely on imprecise lints that can frequently lead to spurious warnings and dubious fixes, to have greater expressiveness in the language itself that allow these checks to be precise and enforced consistently, which leads to less confusion.

Usually, the kinds of workarounds that you need to do in cases where the compiler gets it wrong are to just be a little bit more explicit, possibly at the cost of being more verbose. I don't know of many cases where this has caused the introduction of bugs; I'm sure it could happen, but in my experience it seems like the additional expressiveness and precision of the type system far outweighs that, leading to many fewer of these kinds of bugs than you find in C.

> Note, the two of you said at least once "nobody shows" or "nobody claimed" etc. It's pointless to use such rhetoric. It doesn't add any value and needlessly increases tensions because anyone can have one personal counter example.

Sorry, fair point! This is a somewhat common misconception, so you're right, my rhetoric was probably too strong here.

> 15 years ago I was told that Ruby was *the* language of the future, that prevented bugs etc... (hint: it just made them slower to appear). Now in 2022 can anyone cite any developer not working for Gitlab still using this language ?

Ruby seems like a fairly different case than Rust, but off the top of my head, Homebrew, Vagrant, Discourse are all fairly widely used tools written in Ruby; and of course, Ruby on Rails is still a quite popular framework for writing web apps, though many of them are non-free, simply SaaS applications.

> I do have the same concern about Rust: as long as it remains the self-defined input of rustc, it's not exactly a language and it can seriously fail over time.

There are plenty of other successful, long-lived languages. Python has been around for as long as the Linux kernel, and it is defined by a single primary implementation, while also having alternate compatible implementations that are useful like PyPy, and Python is widely used for a large variety of software.

Rust is younger, and thus its alternate implementations are younger and not yet as complete, but it has one independent implementation mrustc which can be used for bootstrapping the compiler, it has another completely independent implementation in the gcc-rs project, and it has a GCC-based backend being added to rustc to supplement the LLVM based backend. The progress on these two implementations has been discussed on LWN recently: https://lwn.net/Articles/907405/

I've also heard rumors that there are other implementation projects that haven't yet been made public; of course those could never see the light of day, but there is a lot of active work in this field right now.

There is also the Rust reference, there's an extensive test suite, there's the entirety of crates.io which is used as an additional test suite, and there's a draft Ferrocene Language Specification https://spec.ferrocene.dev/ which is intended to provide a set of requirements that can be verified against for safety-critical applications.

> Rust does need to adopt a similar approach where there is no more *the* leading implementation and a few others trying to catch up like clang does with gcc or gnugo does with Go

I'm not sure I follow; as you're saying here, the situation for Rust is no different than the situation with C in the Linux kernel, where GCC is the leading implementation and clang is catching up. Are you saying that Rust needs to be held to a higher standard, where there are two independent implementations with feature parity before you can use it? I don't think that this is a reasonable requirement.

Yes, there is value in having multiple independent implementations, but there's also substantial cost in writing the new compiler and the standardization process itself. As mentioned, there is work in progress on all of these fronts (alternative implementations, and more detailed specifications/standards), but I don't think there's any reason to avoid using Rust before those are complete.

A pair of Rust kernel modules

Posted Sep 15, 2022 19:02 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link] (1 responses)

> Not directly for the kernel in fact, rather for the language's life expectancy. 15 years ago I was told that Ruby was *the* language of the future, that prevented bugs etc...

Ruby has been overshadowed by Go and JS now that most complex webapps have frontends in JavaScript and the backend just provides a REST API. But back in the day, Ruby allowed tons of small companies to quickly build decent applications and get to market with them.

This list includes GitHub, AirBnB, Groupon, Zillow and many others. The company where I work is built on top of a Ruby app as well.

So it's fair to say that Ruby absolutely fulfilled its promise in the area of web apps. And it has never been really intended as a systems language or a language for desktop applications.

A pair of Rust kernel modules

Posted Sep 15, 2022 19:39 UTC (Thu) by rahulsundaram (subscriber, #21946) [Link]

> And it has never been really intended as a systems language

Yep, it hasn't advertised as one. Aside from the web arena, tools like Puppet or Chef uses it but that's quite different from being a systems language.

A pair of Rust kernel modules

Posted Sep 14, 2022 9:51 UTC (Wed) by Fabien_C (guest, #160870) [Link] (4 responses)

> Ada is far more foreign, and wasn't designed for the same kind of interop with C and encapsulation of unsafe code behind safe interface that Rust was.

Ada/C interoperability is on par with Rust/C interoperability as far as I can tell (not a Rust expert). See https://learn.adacore.com/courses/intro-to-ada/chapters/i...

Using Ada's formal verification subset (SPARK), one can even prove the correct use of a C API/Library at compile time. Very powerful in terms of software correctness, safety, and security.

A pair of Rust kernel modules

Posted Sep 14, 2022 16:08 UTC (Wed) by lambda (subscriber, #40735) [Link] (2 responses)

> Ada/C interoperability is on par with Rust/C interoperability as far as I can tell (not a Rust expert).

Fair enough! I'm not an Ada expert either, so I can't necessarily speak to how the approaches compare.

I can say that I've seen a lot more work in the free software world to incrementally port portions of software to Rust, such as the original motivating example of Firefox, librsvg, curl, and this work in the Linux kernel, than I have in Ada. The mindshare in Ada seems to mostly be around safety-critical systems, while Rust seems to appeal to free software developers more as a general purpose programming language, which provides some better guarantees out of the box than C or C++ do, even when not doing a full formal verification process for safety critical systems.

I'd love to see examples where Ada has been used successfully to rewrite parts of free software to improve safety or maintainability, let me know if you know of any!

My comments about Ada were mostly to respond to why Rust over Ada or other static analysis tools, and while I don't know Ada well enough to do a detailed comparison, there just seems to be a lot more interest in using Rust for these kinds of use cases than Ada. If anyone has writeups on why Ada would be good for this kind of use case, I'd love to see them.

A pair of Rust kernel modules

Posted Sep 14, 2022 22:02 UTC (Wed) by khim (subscriber, #9252) [Link] (1 responses)

> I can say that I've seen a lot more work in the free software world to incrementally port portions of software to Rust, such as the original motivating example of Firefox, librsvg, curl, and this work in the Linux kernel, than I have in Ada.

The biggest problem of Ada IMO is that it was always supposed to be about safety, but it never addressed the most common source of bugs: pointer safety. Not even with SPARK. It's like discussing about how can you fortify the door in a house with three walls. I suspect they planned to solve it like everyone else (with tracing GC), but that never materialised (because most Ads users don't want tracing GC) thus was always kinda weird “safe” language which doesn't tackle the most common source of bugs.

Finally, in year 2020, it solved that problem. By picking ideas from Rust, of course.

But by that time momentum was lost and it would be very hard to overcome that “safe language without safety” stigma.

In addition Ada very much likes to live in the world where it can dictate the rules thus Rust is much more suitable for the kernel IMO.

> The mindshare in Ada seems to mostly be around safety-critical systems, while Rust seems to appeal to free software developers more as a general purpose programming language, which provides some better guarantees out of the box than C or C++ do, even when not doing a full formal verification process for safety critical systems.

It would be interesting to see how well Rust would do there. I'm not sure Rust would be able to push Ada from that niche, but it's also highly unlikely that Ada would be able to go into general-purpose computing.

Mindsets of Ada programmers and general-purpose computing programmers are just too different.

> If anyone has writeups on why Ada would be good for this kind of use case, I'd love to see them.

It wouldn't. Ada provides some additional facilities which Rust doesn't provide (such as range types), but these are not dependent types which are needed to express safety and thus add bloat to the language without improving safety much.

This about it: the most famous example of range types are months and days… and yet, in Ada, you can not define type for day-of-month which is between 1 and 28 for February and 1 and 31 for January!

A pair of Rust kernel modules

Posted Jan 16, 2024 13:56 UTC (Tue) by yawaramin (guest, #169121) [Link]

> and yet, in Ada, you can not define type for day-of-month which is between 1 and 28 for February and 1 and 31 for January!

Yes you can:

```
procedure Adaproj is
type Month is (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
type Month_Day (M : Month) is record
case M is
when Sep | Apr | Jun | Nov =>
Day1_30 : Integer range 1 .. 30;
when Feb =>
Day1_29 : Integer range 1 .. 29;
when Jan | Mar | May | Jul | Aug | Oct | Dec =>
Day1_31 : Integer range 1 .. 31;
end case;
end record;
begin
null;
end Adaproj;
```

Sure, it's not exactly trivial; but it's possible.

A pair of Rust kernel modules

Posted Sep 15, 2022 19:10 UTC (Thu) by Cyberax (✭ supporter ✭, #52523) [Link]

> Using Ada's formal verification subset (SPARK)

SPARK doesn't support dynamically allocated objects well: https://docs.adacore.com/spark2014-docs/html/ug/en/source...

It's similar to Rust without lifetime annotations and with less static analysis for stack objects.

There are academic papers that try to fix that, but the outcome would basically look like Rust.

A pair of Rust kernel modules

Posted Sep 13, 2022 19:44 UTC (Tue) by atnot (subscriber, #124910) [Link]

> Nobody has EVER explained what it provides to the kernel that Ada or better static analysis tools for C could not.

To quote David Gerard: "could" is a word that means "doesn't"

A pair of Rust kernel modules

Posted Sep 14, 2022 8:54 UTC (Wed) by em (subscriber, #91304) [Link]

> And generic associated types have been in progress for more than 5 years with no real sign that they're going to be stabilised any time soon.

GATs have been stabilized yesterday, fyi: https://github.com/rust-lang/rust/pull/96709

A pair of Rust kernel modules

Posted Sep 16, 2022 11:26 UTC (Fri) by flussence (guest, #85566) [Link]

> The entire idea is horrible. I do not want a Rust compiler on my computer, I do not want to need a Rust compiler on my computer to be able to compile the kernel.

Simply write a better language with measurably lower defects per hour invested and then people will use it.

This isn't rocket science (according to you), but it *is* science. Not religion. Code talks, bullshit walks, see you when you've done the work.

A pair of Rust kernel modules

Posted Sep 20, 2022 22:09 UTC (Tue) by amarao (guest, #87073) [Link]

Wow. Do you use systems, or it's in the evil camp too?

Glad to see this!

Posted Sep 13, 2022 13:20 UTC (Tue) by david.a.wheeler (subscriber, #72896) [Link]

I'm very glad to see this. The only real way to have justified confidence that the Rust APIs will work for kernel modules is to try using those APIs.

A pair of Rust kernel modules

Posted Sep 14, 2022 0:46 UTC (Wed) by rsidd (subscriber, #2582) [Link] (23 responses)

Wow, the anti-rust trolls are worse than the anti-Gnome or anti-Lennart trolls. One of them above actually writes, apparently without irony, «How does anyone come to the conclusion that Rust is "supposed to" prevent memory leaks, when Box has a whole convenience function specifically for leaking memory?»

It boggles the mind.

A pair of Rust kernel modules

Posted Sep 14, 2022 6:11 UTC (Wed) by ssmith32 (subscriber, #72404) [Link]

Well, if you wanna be glass half-full(ish), I believe Lennart received death threats. So progress, of a sort. I would say the community has come a long way, if this is the worst of it. Still a bit annoying, but progress is like that.

A pair of Rust kernel modules

Posted Sep 14, 2022 8:16 UTC (Wed) by marcH (subscriber, #57642) [Link] (19 responses)

I'm not sure it's a troll. Trolls want to be read but this was too long, unstructured, lacking logic and with more emotional content than technical. I bet most people didn't get past the first few lines. So it was not a good troll but bad trolls are usually not like that either: the English style is usually not that good. So I'm afraid it's someone genuinely getting that emotional because of... computer code? Concerning, someone should help.

A pair of Rust kernel modules

Posted Sep 14, 2022 9:20 UTC (Wed) by milesrout (subscriber, #126894) [Link] (18 responses)

Grow up. Criticism of a programming language on technical grounds is not "emotional". What is emotional is the trolling and dogpiling of the Rust community in response to any kind of criticism.

A pair of Rust kernel modules

Posted Sep 14, 2022 9:54 UTC (Wed) by rsidd (subscriber, #2582) [Link] (17 responses)

It was a troll. For example, you wrote
Nobody has even managed to represent the Wayland memory model in Rust, and the kernel is far more complicated than that. The one serious attempt to do so failed after months of work because it required writing thousands upon thousands of lines of memory management boilerplate.
In fact, the developer of wayland-rs rebutted this two years ago, and both wayland-rs and smithay (an alternative to wlroots -- not wayland -- in rust) are actively maintained today. Not in wide use (gnome/libweston dominates, kde and wlroots are a distant second/third, not much space for others). But it's there. Perhaps you are thinking of weston-rs.

Many of your other comments -- such as they are, omitting the "yeah right", "anyone notice that..." etc -- have been amply rebutted by others above.

As far as the kernel is concerned, if there was a huge issue with Linux's memory model, Linus would have noticed by now, I think.

A pair of Rust kernel modules

Posted Sep 14, 2022 10:37 UTC (Wed) by Wol (subscriber, #4433) [Link] (16 responses)

> > What is emotional is the trolling and dogpiling of the Rust community in response to any kind of criticism.

Isn't it interesting that milesrout wrote this? Because that is exactly what he is doing ...

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 14, 2022 11:12 UTC (Wed) by corbet (editor, #1) [Link] (15 responses)

How about if we all stop calling each other names here? Please?

A pair of Rust kernel modules

Posted Sep 14, 2022 12:36 UTC (Wed) by nirbheek (subscriber, #54111) [Link] (14 responses)

As a spectator in this discussion, I have to say that the antics of people like milesrout make me not want to read the comments section at all. I wish the comments section had a way to collapse all replies underneath a rambling / trolling comment (similar to reddit) so I can skip to things that are actually worth reading.

A pair of Rust kernel modules

Posted Sep 14, 2022 12:41 UTC (Wed) by mathstuf (subscriber, #69389) [Link] (11 responses)

As a subscriber (at least the "professional hacker" level), you have access to a feature to mask out certain users. I believe it hides the whole tree from any of their contributions.

A pair of Rust kernel modules

Posted Sep 14, 2022 13:03 UTC (Wed) by nirbheek (subscriber, #54111) [Link] (9 responses)

That's useful, thanks! It's a bit sad to me that the editors are allowing the comment section to become toxic enough to require adding such a feature. As a former reddit community moderator, it's frustrating to me when I see people allow this to happen.

A pair of Rust kernel modules

Posted Sep 14, 2022 13:17 UTC (Wed) by Wol (subscriber, #4433) [Link]

For the most part, it doesn't happen here. I suspect the majority of readers are subscribers, which means it's only "old" articles that get the attention of trolls.

The difficulty is when you get articles that by their very nature are contentious, and debate can easily get heated. That, sadly, then attracts trolls like moths to a flame.

Which then encourages subscribers to subscribe to a level that permits them to apply their own moderation.

It's like democracy - "the worst form of government, apart from all the others we've tried". Moderation is a bad thing. Just is it better than the alternatives? For the most part, for this site at least, it clearly is not.

Cheers,
Wol

A pair of Rust kernel modules

Posted Sep 14, 2022 13:21 UTC (Wed) by corbet (editor, #1) [Link] (6 responses)

Out of curiosity, what would you propose that "the editors" do to make things better? Assuming we had the time and stomach to go deleting/blocking posts, what are the criteria we should use? Most of the time, asking LWN readers to behave like adults works; I'm not sure what to do in cases where it doesn't.

A pair of Rust kernel modules

Posted Sep 14, 2022 19:21 UTC (Wed) by atnot (subscriber, #124910) [Link] (2 responses)

> Assuming we had the time and stomach to go deleting/blocking posts, what are the criteria we should use?

My opinion is that a large part of the problem is that those two, very blunt weapons are the only ones available. It means that as long as one nominally follows the rules[1], one is completely free to (deliberately or accidentally) abuse LWNs perverse feedback loops to derail discussions: Write the most incendiary thing you think you can get away with, get it as far up the page as possible by being early, fight with every reply and watch your discussion take up vertical space on the page until nobody has the patience to scroll past it to read anything more substantive anymore. At that point you have won by being the loudest and stop replying to avoid getting chastized by Your Editor.

With no mechanism to counteract this, it's unsurprising it keeps happening. Softer measures like hiding, collapsing or locking a thread, sending it to the bottom of the sort order, showing limited reply depth or rate limiting back and forth replies are probably more effective there than hardline moderation.

> Most of the time, asking LWN readers to behave like adults works; I'm not sure what to do in cases where it doesn't.

I think it's remarkable how well this works, all things considered.

[1] https://eev.ee/blog/2016/07/22/on-a-technicality/

A pair of Rust kernel modules

Posted Sep 15, 2022 18:03 UTC (Thu) by marcH (subscriber, #57642) [Link]

> Softer measures like hiding, collapsing or locking a thread, sending it to the bottom of the sort order, showing limited reply depth or rate limiting back and forth replies are probably more effective there than hardline moderation.

This.

Surprise, surprise, "analog" problems rarely ever have binary solutions (unless of course you read social media).

A pair of Rust kernel modules

Posted Sep 16, 2022 3:32 UTC (Fri) by milesrout (subscriber, #126894) [Link]

> With no mechanism to counteract this, it's unsurprising it keeps happening. Softer measures like hiding, collapsing or locking a thread, sending it to the bottom of the sort order, showing limited reply depth or rate limiting back and forth replies are probably more effective there than hardline moderation.

And what would be the grounds for doing this? Is this JUST for criticism of Rust? Or does it include a broader category of messages than that?

In my opinion there is no issue. The discussion isn't even heated. I made a SINGLE comment and was immediately accused of trolling. It seems to me that ANY criticism of Rust immediately gets labelled as trolling. Yet lots of topics covered here are contentious and prompt back-and-forth discussions that often are not particularly productive. Only criticism of Rust seems to get immediately labelled as trolling, as far as I can see.

A pair of Rust kernel modules

Posted Sep 15, 2022 7:05 UTC (Thu) by ssmith32 (subscriber, #72404) [Link]

Just throwing ideas out: if you ask someone to be an adult more than X times in window Y + random episilon, put them in a cooling off queue - not necessarily a ban, just slow the rate of posts, to a stop, and then ramp back up (assuming no more adult warnings)

It could be automated - other than ticking an "adult warning" on your post. The randomness is to prevent gaming - keeps you wondering if this time is the one.

I know, a bit naive, just thinking what would help me when I get too troll-y. Particularly in my younger years - I'd like to think I'm older and wiser then when I joined. Because I'm definitely older ;)

A pair of Rust kernel modules

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

Two concrete proposals:

  1. Have the editors able to "flag" a post and all its children as problematic, which results in the thread content being hidden by default, and require readers to click through to read each flagged post in turn. This is a weaker form of deletion.
  2. Support delayed posting, with the minimum required delay set by the editors for replies to any post or its children, and also something that can be set on an individual account - the delay applicable at any point in the thread is the maximum delay of all of its parent posts. This means that when I hit "Post comment", instead of it actually posting, it enters a "quarantine" state, and I have to come back to the thread to release the comment from quarantine at a later time. This is a weaker form of blocking.

The idea behind the first option is to reduce the visibility of overheated threads, allowing you to indicate that you think that a given thread is non-productive (and discouraging people from either reading it or replying to it). The idea behind the second is to let you use time to cool off a thread that's become heated, or to increase the effort trolls and abusers have to put into actually being seen.

Finally, when I killfile a user, I should have the option to not only killfile that user, but also all immediate replies to them; that way, if I killfile a user who's good at trolling, I don't see the replies that they successfully troll for (but I do see the replies to replies, which may be interesting tangents from the troll).

A pair of Rust kernel modules

Posted Sep 16, 2022 5:04 UTC (Fri) by edomaur (subscriber, #14520) [Link]

Also, an idea would be to add a "cooling down" timer to subtrees selection of discussions, with a visual marker to signal that there is delayed posting enforced in that part of the comments. This can be also linked with a moderator message (typically one "please refrain..." from our favorite editor in chief)

A pair of Rust kernel modules

Posted Sep 16, 2022 12:01 UTC (Fri) by flussence (guest, #85566) [Link]

The system here isn't perfect, or modern, and people often criticise it when there's an angry mob thread like this, but to date I haven't yet witnessed an angry mob directed *at* the moderation. That's a better success rate than nearly every web forum I've used in the past 20-odd years.

Incidentally a major subreddit became Main Character Of The Day on other social media this week for grotesque moderator overreach. I would say the reddit/voat/8chan/urbit model of expendable community and digital royalty built atop it has produced some of the worst results. That website has trench lines by the hundred and the tools are designed to only escalate.

LWN user ignore list pros & cons

Posted Sep 14, 2022 14:54 UTC (Wed) by mbunkus (subscriber, #87248) [Link]

Yeah, this helps, and milesrout is one of the people I have on my ignore list. However, this doesn't prevent the "unread comments" functionality from showing child posts to one of the ignored people. That way one is often sucked back in to such threads as reading such a reply makes me often wonder what they're referring to — as I simply don't remember anything they could refer to (due to it being hidden by default).

Not sure what the best solution is here; maybe collapse those as well by default? Even if the top-most shown comment isn't by an ignored user? Or at least marking it in an obvious way?

Anyway, I'm very grateful to have that ignore list. For that & the excellent content in general I continue to be a happy subscriber.

A pair of Rust kernel modules

Posted Sep 19, 2022 0:50 UTC (Mon) by ras (subscriber, #33059) [Link] (1 responses)

> As a spectator in this discussion, I have to say that the antics of people like milesrout make me not want to read the comments section at all.

As a counter point, I've enjoyed the discussion milesrout has created. Some of the replies have been excellent - the best I've seen on this subject anywhere on the web. They're from people who clearly know the subject very well and also write clearly.

I think that's because they are passionate about the subject. They wear that passion on their sleeves, which I suspect is what you are objecting to - it's not a dry "authoritative" academic treatment of the subject. Yes, that passion could easily drag the discussion into the weeds, but without the passion they would not of invested the time and effort needed to craft such replies.

It's difficult to argue passionately about something, while maintaining the disciplined needed to address the just subject and not the people delivering it. Yet, that is mostly what has been achieved here, in what is effectively an open forum. I put it down to corbet's gentle steering. As other's have said, he limited tools available. His most effective one seems to be leading by example.

A pair of Rust kernel modules

Posted Sep 19, 2022 3:24 UTC (Mon) by marcH (subscriber, #57642) [Link]

LWN is probably the only site in the entire world where you can find people with expertise, writing skills, patience and willingness to politely answer impolite trolls by sharing knowledge badge-like articles - for free. It happens only on LWN but even on LWN it does not happen every time and a tiny bit of semi-automated moderation may not hurt. My 2c.

A pair of Rust kernel modules

Posted Sep 14, 2022 22:28 UTC (Wed) by NYKevin (subscriber, #129325) [Link] (1 responses)

That was not anti-Rust, it was anti-anti-Rust. It was in reply to someone who (wrongly) claimed that Rust's safety model was broken because it fails to prevent memory leaks. I was pointing out that Rust never claimed to do this in the first place, and that it makes no sense to assert otherwise. You may disagree with my reasoning, but please do not mischaracterize my position.

A pair of Rust kernel modules

Posted Sep 15, 2022 0:50 UTC (Thu) by rsidd (subscriber, #2582) [Link]

Sorry for misunderstanding.


Copyright © 2022, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds