The amount of paranoia I need for unsafe Rust is orders of magnitudes higher than C. Keeping track of the many things that can implicity drop values and/or free memory, and figuring out if im handling raw pointers and reference conversions in a way that doesn't accidentally alias is painful. The C rules are fewer and simpler, and are also well known, and are aleviated and documented by guidelines like MISRA. Unsafe Rust has more rules, which seem underspecified and underdocumented, and also unstable. Known unknowns are preferable over unknown unknowns.
I've been thinking of writing a language with Rust's ergonomics but less of the memory safety stuff. I prefer using no dynamic allocations, in which case the only memory safety feature I need is leaking references to locals into outer scopes. As for the thread safety stuff, most of my stuff is single-threaded.
The code I have in C is often code that does't fit in Rusts safety model. Dealing with ffi is annoying because slices have no defined layout. `dyn` is limited compared to what I can do with a manual vtable. I have seriously attempted porting my personal stuff to Rust, but theres enough papercuts that I go back to C. I want the parts of Rust I find to be helpful without those parts I don't.
To add to the sibling comments, a world-class LSP enabling you to get a great experience in any editor/IDE out of the box. This is not at all exclusive to Rust of course, most strongly typed languages have one at this point, but I've been working in Python lately and this is what I miss the most. (I'm using an LSP in Python, but it isn't as good at the best of times, and it seems like no matter how many times I fix it's configuration it's broken again the next day.)
I love how everything is an expression with a value. And match expressions are quite nice, especially with the option type. I really miss those when working in javascript.
I vaguely remember reading when this occurred. It was very recent no? Last few years for sure.
> The Linux kernel began transitioning to EEVDF in version 6.6 (as a new option in 2024), moving away from the earlier Completely Fair Scheduler (CFS) in favor of a version of EEVDF proposed by Peter Zijlstra in 2023 [2-4]. More information regarding CFS can be found in CFS Scheduler.
Ultimately, CPU schedulers are about choosing which attributes to weigh more heavily. See this[0] diagram from Github. EEVDF isn't a straight upgrade on CFS. Nor is LAVD over either.
Just traditionally, Linux schedulers have been rather esoteric to tune and by default they've been optimized for throughput and fairness over everything else. Good for workstations and servers, bad for everyone else.
The kernel policy for CVEs is any patch that is backported, no? So this is just the first Rust patch, post being non-experimental, that was backported?
I haven't looked at fs-verity at all, but per-file merkle trees should definitely be built into the filesystem as a standard thing. Rsync and file transfer programs want it, and having to compute that every time is crap - if it's built into the filesystem it can easily be computed lazily and invalidated if need be.
(obligatory plug for people to jump in and get involved with writing code if they want to see more of this stuff happen)
Seems like you could set up a cert for a honeypot domain to collect ips of bots running off of the certificate transparency logs. If domain isnt linked from anywhere, then its pretty sure to be a bot isn't it?
Lack of stable build-std and panic_immediate_abort features result in a order of magnitude size difference for some rust code I have. Using no_std brings it to ~60kb from ~350kb, but still more than the ~40kb for the C version
Afaik despite Rust not having exceptions, panic still unwinds the stack and executes 'drop'-s the same way C++ does, which means the code retains much of the machinery necessary to support exceptions.
The panic_immediate_abort feature should prevent this. build-std is the name of the feature that recompiles the Rust standard libraries with your chosen profile, so the combination of these two features should result in no unwinding code bloat.
It's possible for a crate to assume there will be unwinding, but given the Rust communities general attitude to exceptions it's not common.
By default, all it means is that unwinding the stack doesn't happen, so Drop implementations don't get called. Which _can_ result in bugs, but they're a fairly familiar kind: it's the same kind of fault if a process is aborted (crashes?), and it doesn't get a chance to finalise external resources.
EDIT: to clarify, the feature isn't really something crates have to opt in to support
I've been working on Rust bindings for a C SDK recently, and the Rust wrapper code was far more complex than the C code it wrapped. I ended up ceding and getting reasonable wrappers by limiting how it can be used, instead of moddeling the C API's full capabilities. There are certainly sound, reasonable models of memory ownership that are difficult or impossible to express with Rust's ownership model.
Sure, a different model that was easy to model would have been picked if we were initially using Rust, but we were not, and the existing model in C is what we need to wrap. Also, a more Rust-friendly model would have incured higher memory costs.
I totally hear you about C friendly APIs not making sense in rust. GTK struggles with this - I tried to make a native UI in rust a few months ago using gtk and it was horrible.
> Also, a more Rust-friendly model would have incured higher memory costs.
Can you give some details? This hasn’t been my experience.
I find in general rust’s ownership model pushes me toward designs where all my structs are in a strict tree, which is very efficient in memory since everything is packed in memory. In comparison, most C++ APIs I’ve used make a nest of objects with pointers going everywhere. And this style is less memory efficient, and less performant because of page faults.
C has access to a couple tricks safe rust is missing. But on the flip side, C’s lack of generics means lots of programs roll their own hash tables, array lists and various other tools. And they’re often either dynamically typed (and horribly inefficient as a result) or they do macro tricks with type parameters - and that’s ugly as sin. A lack of generics and monomorphization means C programs usually have slightly smaller binaries. But they often don’t run as fast. That’s often a bad trade on modern computers.
The code is written in an embedded style, i.e. no dynamic memory allocation or thread creation/deletion after program initialization. It's also prioritizing reducing memory usage over performance since we are targeting memory constrained devices (and our performance target is 10 tps and we have like 100k tps). Thus we'd use trait objects over monomorphization. Dynamic collections are also off the table unless backed by a fixed-size arena on the stack or static mem.
We heavily use arenas. We also have runtime-typed objects used to represent dynamically typed data like that obtained from JSON/Yaml or over IPC. If we were to be more friendly to modeling in Rust, we'd likely require that all memory reachable from an object node be in the same arena, disallowing common patterns like having list/map's arrays in one arena and having keys/strings in another or in static mem (this allows reusing other buffers without forcing copying all the data, so backing arrays can be smaller).
> Also, a more Rust-friendly model would have incured higher memory costs.
I'm not sure how modelling everything in a rust borrow checker friendly way would change anything here? Everything you're talking about doing in C could be done more or less exactly the same in rust.
Arenas are slightly inconvenient in rust because the standard collection types bake in the assumption that they're working with the global system allocator. But there's plenty of high quality arena crates in rust which ship their own replacements for Vec / HashMap / etc.
It also sounds like you'd need to write or adapt your own JSON parser. But it sounds like you might be writing part of your own JSON / Yaml parser in C anyway.
Arenas aren't the issue. Its objects with mixed lifetimes and mutability. I cant easily model the lifetimes of objects when there are cases like an instance where buffer memory reachable from the object has a different lifetime than maps/lists. Also these objects could be transively shared or mutable. In order to make a Rust friendly model, I'd have the tree be all shared or all mutable, and have all reachable memory have the same lifetime. This would often mean allocating the full tree into one arena. That is where the overhead comes from. Each arena would need enough memory to store the entire object; currently they can be smaller since they often only need to hold parts of objects, not the entire thing.
This is ultimately a good example of how to use Rust. You express as much of the API as you can safely, and the rest is unsafe. APIs that can't be safely modelled can still be exposed to Rust & marked unsafe, if they're needed
Wouldn't a data type with no safe method of construction satisfy that? You can only get one by calling an unsafe function & satisfying its constraints.
reply