Just because emotions seem to be always boiling whenever Rust is mentioned, I want to clarify for people who only follow casually that there is nothing unusual or scandalous about these finds.<p>The Rust project as a whole currently has 178 open issues with the tag I-unsound[1]. Many of these describe issues that only exist in the nightly compiler, of course, but it does happen that bugs are not caught before shipping. That's software.<p>[1]: <a href="https://github.com/rust-lang/rust/issues?q=is%3Aissue+state%3Aopen+label%3AI-unsound" rel="nofollow">https://github.com/rust-lang/rust/issues?q=is%3Aissue+state%...</a>
That there's nothing unusual about these finds, the Drop static lifetime bug, or cve-rs is proof that Rust is not, and probably never will be, memory-safe. It's still an improvement though.
Even more, the fact that unsafe blocks are a thing allows for this kind of deep scrutiny of the STD.
> there is nothing unusual or scandalous about these finds<p>I would not go so far. I just mentioned in a separate comment, a minute before writing this here, that it is rather
outrageous that the premier language for AI these days (aka Rust),
has not used AI to find these bugs before. Would you not
also consider that it should follow from simple logic that
a language that is the premier AI language now, also would
use AI as it preaches for it, to find bugs?
I’m having a hard time understanding you here. Are you saying that since rust is a good language for AI to write code in, it says something about the (lack of) power of AI, that it wasn’t what found the bug? Because the logic there seems twisted: “F1 drivers, the biggest users of F1 cars, almost never make improvements to F1 engines”.
Are you paddling some? I’ve never seen rust described as premier language for AI
><i>that there is nothing unusual or scandalous about these finds</i><p>that there is nothing unusual <i>is</i> the scandal
I've always felt that parts of the Rust standard library to be weirdly un-rusty. Like indexing a vector panicking instead of returning a Some(T) in case the index is out of bounds. It's easy to avoid if you put the effort in of course, but it did always feel weird that one of the first data structures you learn has this behavior right out of the gate.
That's not really a memory safety bug, due to the fact that it panics rather than doing something unsafe.<p>The `variable[i]` notation is intended to function like in other languages, where it returns an unwrapped value. It would be ugly, noisy, unergonomic, and annoying to have to properly handle `Some` (like in `variable[i].unwrap()`) every single time you ever used it. Imagine doing `c[i].unwrap()[j].unwrap() += a[i].unwrap()[k].unwrap() * b[k].unwrap()[j].unwrap();`.<p>If you really want the result to be wrapped in `Some`, you can use `variable.get(i)`.
> That's not really a memory safety bug, due to the fact that it panics rather than doing something unsafe.<p>The ? operator can be nicer to read then all those .unwraps() as an alternative and doesn't panic.<p>I guess the concern with panics is you're not forced to think about how you want to handle them like you do when you get a `Result` or `Option` returned.<p>As a result it could be used as a DDOS against your app if it's network accessible.
gotta remember tho that ? didn’t exist in 1.0, and now we can’t break existing code
Applying the <i>?</i> operator to an <i>Option<_></i> doesn't work inside a function returning <i>io::Result<_></i>, for example, and turning the <i>None</i> from an out-of-bounds vector access into some <i>io::Result::Err</i> usually wouldn't make sense.<p>I would go so far as to say that an out-of-bounds index is <i>always</i> a logic error (to be handled by panicking), not an input error (to be handled with <i>Result</i>). And if the out-of-bounds access was caused by invalid input, then logic error consists of not checking the input before indexing.
The former issue arises from post-hoc thinking. Of course it's hard to retrofit into the language, but I see no reason why there shouldn't be facilities for the ? operator to turn a None into an appropriate error type.<p>The latter is a subjective matter. There are reasons to never want a panic (hello there, Linux kernel) and reasons to do more sophisticated stuff (core dump, cleanup or notifications) before crashing. And maybe one thread shouldn't lead to process death. I think most of these decisions should be kept to the user's discretion.
GP didn't say it was a memory safety bug.
I think it is a reasonable tradeoff, especially since `get(i)` is available to do what you want. An array index oob error is usually a logic issue, not some recoverable error, and in a lot of cases you're doing it where it is impossible to be wrong, so it is a lot of error-checking (and giving up things like x[0] += 1) to have the Index trait return an Option instead of a direct reference.
That's just a design decision orthogonal to memory safety:<p>For "fallible" variant indexing, you have `the_slice.get(index)`: <a href="https://doc.rust-lang.org/stable/std/primitive.slice.html#method.get" rel="nofollow">https://doc.rust-lang.org/stable/std/primitive.slice.html#me...</a><p>Although its method signature is kind of cursed due to generics, it matches your requirement that allows graceful OOB handling.<p>If the default indexing behavior were like `.get()` it would be too cumbersome to express repeated use of indexing, or multi-dimensional array indexing, etc.<p>Also there is get_unchecked which is unsafe. Trivially you'll trigger OOB access when misused.
> Like indexing a vector panicking instead of returning a Some(T) in case the index is out of bounds.<p>If you are doing this then you've made a mistake in your code. Rust is consistent in catching these early.
Wrapping everything in optional does lead to optional fatigue, and people just unwrap each optional they get since they know the index is inbounds, missing the one instance where it really is possible to get None.<p>Maybe optional fatigue is Rusty but it's not a good style in any language
> But many operations in Rust can panic, from out-of-bounds indexing to calls into user-provided code, and by default a panic unwinds<p>That's why I think having unwinding in Rust is a mistake. It gives a false sense of safety, but it's very hard to write unwinding-correct code. So, it would be better to handle panics as immediate process termination instead.
> Pattern 2: Trusting user-provided implementations to be correct<p>reminds me of the tales from <a href="https://oxide.computer/blog/iddqd-unsafe" rel="nofollow">https://oxide.computer/blog/iddqd-unsafe</a>
> Notes from Microsoft Security's Frontier Offensive Research & Generative Exploitation Lab.
An effect system could gelp us reason about code by making calls to panic-capable functions marked as such. Maybe we could mark some types as panic unsafe?
Do not ever use with anything other than panic = abort.<p>It is just the sketchiest feature in a very realiable language.<p>It doesn't make sense to me why anyone whould use rust with panic handling.<p>And the of course the language trusts the operating system, how else can you program?<p>This kind of thing is basically why all projects blocked AI issues, it is just slop that kind of makes sense if you don't know what you are doing.
Very interesting finds for sure. But taking the "trusting user-provided code" as an example: isn't this just a case of malicious code being malicious? I understand the point that the malicious act comes through memory unsafety, and it's a big gotcha that <i>safe</i> Rust (i.e. Rust without `unsafe`) can trigger memory unsafe behavior. But the code doing it is still acting maliciously (by having an `AsRef` implementation that returns different slices at different times). And the code being abused (the one that does the unsafe indexing) <i>does</i> have `unsafe` – so this is a case of the user writing unsafe Rust that interacts with <i>malicious</i> safe Rust.<p>I don't know if it's ever been in Rust's threat model to handle malicious code.
Sufficiently deniable malice is indistinguishable from incompetence. If a condition can be triggered "maliciously", then it can probably be also triggered inadvertently. There's no point in saying "that's malicious so it doesn't count".
Rust's goal is no UB in safe Rust. That includes in (incorrect) impls of safe traits.<p>Note that incorrect code can still cause<p>1. incorrect outputs, or<p>2. arbitrary performance degredations<p>safe rust doesn't have to work magic. All it must do is prevent UB.
Of course this in Rust's model. The <i>whole point</i> of even having the distinction between safe and unsafe traits is that this is in the model.<p>I thought maybe I explain this well in the README for <a href="https://github.com/tialaramex/misfortunate/" rel="nofollow">https://github.com/tialaramex/misfortunate/</a> but apparently not, so that's on my FIXME list now.<p>When I write such an explanation it will probably use Comte as an example. Comte implements ExactSizeIterator which is a safe trait for claiming your iterator gives accurate information about how many items are left. It's lying (but equally a safe implementer might just be mistaken), and Comte is not in fact giving accurate size information. However, if you need to rely on a <i>promise</i> that the iterator length is correct Rust has an <i>unsafe</i> trait for such promises named TrustedLen.<p>Unlike Comte, mis-implementing TrustedLen could cause Memory Unsafety, but you would need to write the `unsafe` keyword and be lying or mistaken, which is what Rust promised you will happen.<p>To give a concrete example, if I tell Rust I want to put the results from this iterator over Goose into an array [Goose; 6] in usual cases it will emit code to check for overflow and panic if the Iterator makes the wrong number of Goose, even if the iterator implements ExactSizeIterator and claims to have six Goose, that panic check happens. But if it implements TrustedLen and makes the same claim, the compiler will believe it and skip the check. If it was wrong about having six Goose, your program is nonsense and anything might happen.
Only JavaScript partially supports this, based on the domain where the code originated from, so your website code is not infected by the Javascript run by an ad you embed.
I sure wish they'd rewrite the Azure Linux VM Agent in Rust. That thing normally burns 10-15% of a core, and also blocks VM restart for tens of minutes, god knows why.
I've seen certain MSFT engineers get a lock ordering warning from taking mutexes in a wrong order and "fix" it by using a spin loop + try lock instead.
no amount of rust will fix the problems in azure that lead to <a href="https://news.ycombinator.com/item?id=47616242">https://news.ycombinator.com/item?id=47616242</a>
The best AI language has not used AI to find all bugs yet?<p>I don't quite like AI, but I think from an objective point of
view one can reason that AI led to the discovery of more bugs,
if we deduct the non-bugs from those reports.
Is it just me or is it painful that they format their product name like that in the blog text.
[flagged]
[dead]
The community-driven quest for "panic safety" in Rust is the same curse that befell C++ in terms of "exception safety", maybe worse because at least more C++ shops are sensible enough to disable exceptions. It's an exercise put forth by language lawyers that increases program complexity beyond comprehension, often without achieving the stated goal. It's simply not practical to think through 20 convoluted edge cases for every innocent little function, which means that no realistic program will safely recover from a panic. It's best to admit this and engineer your system accordingly.
To me, panic being an unwind feels like Rust's biggest sin. It's especially problematic IMO since an idiomatic Rust program would use Result and pass errors as function returns, except the panic unwind machinery sits there as a hidden return path that's very easy to forget about. It's the same problem as writing exception safe C++, every function call can turn into an early exit from the function.<p>Most Rust learning material teaches panic as if it's an abort. They don't lie about it unwinding, but 99% of uses of panic use it like a fatal error with no expectation of recovery. The fact you can _recover_ from panics is even worse because you can then continue running a program after one of these "fatal" errors failed to abort the process.<p>There's some powerful things panic/catch_unwind let you do. I'm yet to be convinced the complexity imposed on all code is worth the squeeze on the cases where panic = unwind is a genuine requirement.<p>I wish the default was panic = abort, but as a whole I still find Rust the best tool for where I use it.
This is such a deep topic with literally decades of discourse behind it.<p>I tend to agree with the general principle that panicking or throwing an exception should terminate the process in most cases. But those last microseconds of a process' lifetime matter quite a lot: Are you able to save the user's work? Are you able to log the error so the crash can be diagnosed?<p>With Undefined Behavior in the picture, you cannot do anything. The whole process is toast, and its entire memory state is invalid.
I would say the problem with this becomes that it’s all best effort.<p>You can’t rely on it for correctness because for your software to be reliable it needs to deal with an abrupt power outage and recover.<p>Best effort diagnostics make sense. And the “Rust 2.0” or successor language will with certainty close this gap.<p>But I also understand why we are here. A decade ago when 1.0 came out Rust had already used up most of its complexity budget for traits, enums, borrow checker, generics, functional style programming and so on.<p>Diverging even further from what was expected by the majority of programmers would very likely have left Rust as an esoteric language with a tiny following. Instead of what it became.<p>And back then unsafe was thought to work more like “just do like in C”.<p>There has been years of research formalizing how it actually works that’s brought us to the current understanding where it’s not trivial to write it correctly.
> The community-driven quest for "panic safety" in Rust is the same curse that befell C++ in terms of "exception safety", maybe worse because at least more C++ shops are sensible enough to disable exceptions.<p>You seem confused. The "exception safety" topic in C++, which clueless people often cite Google's style guide as an appeal to authority, is that it's undesirable to modify old legacy code that does not use exceptions to call libraries that do. The sole reason this is not desirable is that calling code that throws exceptions introduces code paths that the legacy code was not designed to consider (i.e., all stack unwinding and RAII cleanup in surprising points with surprising implications).<p>And project managers tasked with a project that involves legacy C++ code can't simply spare time and resources to redesigns legacy project to accommodate for these changes, or the risk of having stable production code one day crash just because someone linked to a library that now throws.<p>Therefore, the "exception safety" discussion in C++ is not a technical one. It is a project management one, and one which involves high reliable legacy code.
A good use for AI
[flagged]
I think that the point of Rust as far as memory safety isn't perfection. The point is centralizing proper memory safety.<p>With C, every single programmer has to properly account for memory safety in just about every program they write. If you fix a memory safety bug in one program, that's not necessarily going to help any other program.<p>With safe Rust, that work has largely been done for you. If a memory safety bug is found and fixed in Rust's standard library, it's found and fixed for every program that uses safe Rust (with a recompile using the new standard library version).<p>The point is for some experts to work together to get things as memory safe as possible in one place instead of everyone having to get things as memory safe as possible in every place.
You don’t need frontier models and a research project to find memory safety issues in C. Rather the opposite actually.
There were also memory safety bugs found in Rust code without frontier models before. Note that I do not deny that Rust has an advantage with regard to memory safety (at the cost of other things, including supply chain issues), but it is massively overhyped.
True but C never went out of its way to highlight memory safety features and shut down (with a rather aggressive posture to boot) any criticism of the language with arguments revolving around this feature as if it was the Christ's second coming.<p>In lieu of finding out that there are in fact multiple memory issues in std is at least amusing and some might say well deserved egg in the face of the more, shall we say, enthusiastic defenders of the language.
You mean the Rust fans. And there are C fans who say that only n00bs do accidental UB. Nobody cares what fanatics say.
I have my share of criticism of Rust. But even a safe language has to deal with unsafe memory etc. at some point in the stack. The goal is to minimize such uses of <i>unsafe</i> and for the cases of <i>unsafe</i> that exist to prove that they are safe.<p>These <i>haha gotcha's</i> are criticism leveled at language designers who never denied that there is unsafe code, that there can be bugs in unsafe code, and that such bugs can leak to safe code.<p><i>egg in the face</i><p>Is it an egg in the face when it requires LLM analysis to find these nowadays? It tells me that the Rust developers got really good at eliminating memory bugs that are lurking in <i>unsafe</i> code.<p>Also, this doesn't change anything to the benefits of Rust's ownership model, which removes classes of bugs that are very common in C/C++, so the Rust advocates were still right.<p>(I'll leave my rants about Rust in a thread where it's more appropriate, but they are not about memory safety.)