GrantMoyer 1 day ago

It's surprising this bug went unnoticed for so long, but at least it's easy to fix, since it's not a bug with the type system itself; it's just a bug in the compiler. The compiler should always have been rejecting that code according to lifetime rules of Rust's type system, so the fix is to just make it reject the code, rather than having to change the fundamental rules of lifetimes.

  • mav65 1 day ago

    Not knowing anything about rust, the problem in these type of case is making it rejecting that bad code without also rejecting valid programs. But maybe this is indeed easy to fix, I don't know.

    • bluGill 1 day ago

      There are no such valid programs. Proof by contradiction:

      A valid program would be exploiting undefined behavior in rust, but rust has no undefined behavior. Thus such a program must not exist.

      Now a program may appear to work before the fix, but it was never a valid Rust program.

      • afdbcreid 1 day ago

        I can't tell if you are sarcastic, but in case you are not:

        By Rice's theorem you cannot be sound and complete, i.e. accept all valid programs and reject all invalid ones. Most languages choose to be sound but not complete, i.e. reject all invalid programs but also some valid ones (C and C++ are the notable exception, although most languages have escape hatches). GP was saying that the fix might reject valid programs that compile today. This is true for some existing soundness bugs, but not necessarily for this one specifically.

        • bluGill 1 day ago

          Rice's theorem does not apply. This is not about what the compiler does, it is your program. If your program is not sound then it is invalid Rust even if the compiler accepts it and it seems to do the right thing.

          That said, I was sarcastic.

          • afdbcreid 1 day ago

            It does apply, of course (even if not to this case specifically). The implemented Rust semantics are not sound, as evidenced by this issue. We need to find (or adjust) sound semantics. Which, mathematically, is equivalent to designing Rust from scratch (ignoring things like RustBelt because they did not formalize the entire system). Due to Rice's theorem we know we need to give up some sound programs. Can we give up exactly the programs we already gave up for the previous Rust? Maybe, maybe not.

            • Someone 1 day ago

              > The implemented Rust semantics are not sound, as evidenced by this issue. We need to find (or adjust) sound semantics.

              You’re ignoring the possibility that Rust semantics are sound, and the implementation doesn’t fully implement them. In that case, we do not have to find sound semantics.

              That, I think, by far is the most likely option.

              Reason: I’ve not seen a single comment claiming the example should compile, and zillions (implicitly) acknowledging this is not what Rust should do.

              • afdbcreid 1 day ago

                I explicitly did not ignore the option that there are possible sound semantics:

                > but not necessarily for this one specifically

                > Maybe, maybe not.

                But "the Rust semantics" are not defined, formally. The closest we have is what Rust implements currently, and that was shown here to not be sound. Other than that, we maybe have vague ideas in the brains of some T-types members, which are not detailed enough to determine soundness (source: those type system people want to formalize the semantics so they will be).

                And for the record, we know of other soundness issues where the likely resolution path will involve rejecting valid programs we accept now, and the only question is how many.

            • i2talics 1 day ago

              The tricky thing about formalization is that you usually have to reimplement the type checker into a proof assistant in order to do formal soundness proofs. It's not necessarily clear that this reimplementation is identical to the actual Rust compiler (in fact, you often have to massively simplify the type system to make the proofs tractable), so bugs in implementation can cause unsoundness without being related to fundamental flaws in the soundness of the type system.

              • afdbcreid 1 day ago

                Indeed. Proving the implementation will likely never be done, it's just way too hard. But proving Rust abstract semantics are sound will by itself be a major leap forward (RustBelt did that for a subset of Rust).

            • Permik 1 day ago

              It could be that I'm totally yapping bullshit, but the "designing from scratch" can vary depending which field of maths you're talking about. For instance, if we model the semantics as a series of composable functions, then you only have to scratch only the specific dependency tree of the functions. Basically everything can be reused with no wasted work, and the output space gets culled.

              • afdbcreid 1 day ago

                Which is why I said to ignore RustBelt. Because we don't have formal semantics today, we only have the actual implementation which is not composable.

          • i2talics 1 day ago

            Terminological nitpick, but soundness is a property of an entire type system not of an individual program. A type system is sound if it only accepts valid programs. A program is valid if it never exhibits undefined behavior.

            Rice's theorem implies that it's impossible to precisely distinguish valid and invalid programs just by looking at their source code. Thus Rust rejects some valid programs in order to be sound (e.g. "if false { None.unwrap_unchecked() }").

            In the case of the bug report in OP, I don't think that there are many valid programs in practice that exploit this soundness issue, so fixing it just means rejecting more invalid programs.

        • charcircuit 1 day ago

          Rust does not target Turing machines so Rice's theorem does not apply.

      • wging 1 day ago

        Rust does have undefined behavior, though.

    • foldr 1 day ago

      In this case the issue is that the compiler just isn't properly type checking the implicit call to the drop method that's inserted at the end of the nested block. AFAIK, no correct code should depend on the absence of that check.

  • WiSaGaN 1 day ago

    It's fascinating that this kind of bug is exactly you can't really avoid even when rust is supposedly to guard against. Rust mitigated this problem a lot in practice, but you can never be certain because of issues like this in practice. This is similar that a math proof that's already been peer reviewed and accepted as truth, may still be possible to be wrong, although the chance is very small but it's not zero. Epseicially when the complexity gets higher.

    • Garlef 1 day ago

      ... and even if you formalize it, it could still be false due to an error in the theorem prover itself.

      • GrantMoyer 1 day ago

        And even if the theorem prover has no errors, the math behind the theorem prover could be inconsistent according to Gödel's incompleteness theorem. So even in principle, we can never be completely certain about the soundness of Rust, though the more theoretical concerns tend to be dwarfed by basic human error.

        I think it's a good thing to keep in mind, that the actual implementation of Rust almost certainly isn't sound. Even an "ideal Rust" still has unsafe, which can affect the soundness of even faraway safe code. But I don't think it's nessesarily wrong to talk about Rust as if it were safe. Much of our communication has implicit assumptions, and the way we talk about Rust is no different. It would be exhausting to qualify every discussion of saftey with "assuming the compiler has no bugs", "assuming all unsafe code follows the (not fully specified!) rules", etc.

        Ultimately it's like any other implementation of theory into practice. The theoretical model of Rust lets us reason about and design an implementation to achieve certain practical goals even though the model is a simplification of reality. In Rust's case, practical use has demonstrated it achieves design goals like reducing bugs and reducing development time (compared to peers like C++) to a substantial degree.

        • ModernMech 1 day ago

          It’s like Python describing itself as fast. Everyone knows that means “fast enough for intended use”, not “fast in an absolute sense”. But for some reason when Rust describes itself as safe people take that to mean in an absolute sense.

          • electroglyph 1 day ago

            Rust scores a lot higher on the safe scale than Python scores on the fast scale. Also, who are these mythical people that call Python fast?

            • ModernMech 23 hours ago

              Python calls itself fast in its own webpage:

              https://www.python.org/about/

                Python is powerful... and fast; plays well with others; runs everywhere; is friendly & easy to learn; is Open.
        • GoblinSlayer 11 hours ago

          Gödel and halting problem don't apply to real programs, because they don't need to be accurate: they can reject correct code.

      • gavinsyancey 1 day ago

        Or more likely, an error in the formalization. "What you proved is true, but it's not sufficient for what you care about." See for example WPA2 KRACK attacks after WPA2 was proven secure.

      • anyfoo 21 hours ago

        This moving of goal posts whenever correctness through type systems is being discussed is a bit tiresome, because it quickly leads to such ad absurdum corner cases.

        Yes, you are all correct. The compiler may have a bug. And if it does not, then the type system may have a problem. And if it is formally verified, then the theorem prover might have issues. And if it does not, then the very math it relies on may be wrong.

        But what do we contrast this to, what is the alternative to correctness through the type system? Almost every time, when it isn't "nothing", it's "tests". We rely on tests to test whether the program behaves correctly.

        And as we all know, quite in contrast to type systems and their checkers, tests are always error-free, complete, and sensible?

    • orf 1 day ago

      How is this different from any other compiler bug?

      There was one in the Linux kernel a while ago that mistakenly eliminated an important null check.

      Is this different?

      • yencabulator 23 hours ago

        No, people who don't actually use Rust just like to pretend it's something more than it is, for some performative outrage or something.

        Here's the current list of similar (unsoundness-causing) open compiler bugs in Rust:

        https://github.com/rust-lang/rust/issues?q=state%3Aopen%20la...

        • randypewick 15 hours ago

          Oh, I think you're so right. I heard ton of people online assuming that Rust could help to catch any freaking bug, and when they noticed that - well, it obviously doesn't - ah, then it's just crap or hype.

    • lacker 1 day ago

      In theory it would be possible to formally verify the soundness of the borrow checker. Maybe with AI advances we'll be able to do that in the near future. I mean, how much more complicated can it really be than proving Navier-Stokes?

      • mlindner 23 hours ago

        You can't formally verify the soundness of something that inherently necessarily relies on hardware implementations that themselves could be faulty.

        • altairprime 23 hours ago

          You can certainly verify the soundness of what is within your control, the compiler code, which is what is being suggested above.

        • LoganDark 23 hours ago

          You can formally verify that the algorithm has the desired properties, though. If the hardware requires additional properties for soundness, then that would only be an error in the properties, not in the proof. (Of course, that would no longer prove soundness on that hardware.)

        • arjvik 23 hours ago

          You take hardware properties as axioms (for instance, ARMv6 cache coherency is specified in detail as part of the lengthy spec, even though you have no guarantees that the hardware actually is faithful to the spec)

      • itishappy 23 hours ago

        Note that the Lean kernel itself is not formally verified.

        • schiffern 19 hours ago

          Don't let the OpenAI marketing department hear you...

    • arkt8 21 hours ago

      Interesting, the main argument is that C need too much expertise of programmer to avoid problems.

      Now, you have a language sold as safe, with popularity made manily blaming C... but now we can say it gave the false sense of safety, distracting programmers from real issues in the name of its error messages that lead for endless refactoring if some new feature is added to project just to o have peace with the compiler. It is a language that program the programmer, an inversion of roles.

      • uobytx2 21 hours ago

        No, this isn’t the way to interpret this. Rust has been very successful not just in appearing safer, but actually delivering safety over C. The sense of safety was almost entirely real. Just some situations it didn’t cover.

        • easterncalculus 20 hours ago

          I don't understand why people talk about this like we live in some fantasy land where C compilers don't have tons of bugs like this. And that's just the bugs, not even the accepted UB.

      • Mawr 19 hours ago

        > but now we can say it gave the false sense of safety

        Except we can't say that, at all. This is just a single bug in relatively obscure code, so 99.99999% of your code remains safe.

        Meanwhile in C, 100% of your code has the potential to trigger a similar bug, except there's no path for the underlying cause to ever be fixed, unlike here.

        You're essentially complaining that something isn't 100% safe, but that's just your misconception of what "safe" means. Nothing is 100% safe, not can it ever be.

        It's especially ridiculous to then compare something 99.999% safe to something 0% safe and conclude that all that "supposed safety" is useless, because look: in 0.001% of cases it's NOT safe!

        • uecker 3 hours ago

          Both the "100% of of your code has the potential to trigger a similar bug" and "there's no path for the underlying cause to ever be fixed" are just nonsense.

      • JimTheMan 19 hours ago

        Imperfection isn’t evidence of ineffectiveness.

        Considering this has gone unflagged for 11 years... Finding a flaw in Rust’s safety guarantees doesn’t mean that they provide no benefit, over a programming language without them.

    • nextaccountic 18 hours ago

      > It's fascinating that this kind of bug is exactly you can't really avoid even when rust is supposedly to guard against.

      Note that Rust is not a theorem prover and Rust programs are usually not formally verified (there are some extensions like Creusot to verify Rust programs, but they are incomplete and a work in progress)

      Compiler bugs are, like, just logic bugs. There's a project to eliminate compiler bugs that cause unsoundness, project zero [0] but, still, without formally verifying the implementation, there is nothing really guaranteeing there's no such bugs left.

      (note: unsoundness in this context means having safe code cause UB due to a compiler bug; the fix is usually to make the compiler reject the code with a compiler error)

      To make matters worse, Rust still doesn't have a spec, and there is not even a tight definition of what are the rules of unsafe code - that is, what rules you must follow so that you unsafe code doesn't trigger UB. Discussions around this are done mainly in issues of the unsafe code guidelines repo [1]

      [0] https://goals.rust-lang.org/2026/roadmap-project-zero.html

      https://github.com/rust-lang/unsafe-code-guidelines/issues

      • masklinn 12 hours ago

        > Note that Rust is not a theorem prover

        Not that that would make any difference, theorem provers can also have bugs. Famously this summer someone “disproved” the collatz conjecture by exploiting a soundness bug in Lean.

weinzierl 1 day ago

This is remarkable but not super unusual. There are more than 100 issues labeled unsound currently. Some are long standing but from what I understand the new trait solver will unblock fixes for some of them (but probably not the one in OP).

  • theemathas 1 day ago

    Finding unsoundness bugs isn't the most unusual, yes. But this one is unusual in how simple the code that causes it can be (see the versions of the reproducer code in the comments). For other unsoundness bugs, the code would need to contort itself a lot to avoid the compiler checks.

    • Ygg2 23 hours ago

      Writing manual Drop isn't usual. And writing drop with such lifetimes is definitely on the weirder scale.

lambdaone 1 day ago

Perhaps ironically, AI-based searching of the Rust compiler for bugs is likely to find more of these, pushing Rust closer and closer to the point of complete reliability.

The eventual formalization of Rust and a creation of a formally proven compiler is presumably going to be the end point of this process.

  • kimi 1 day ago

    Or we realize that it is not possible, and Rust accepts to be "just" a definitely safer C.

    • wongarsu 1 day ago

      There is a formally proven compiler for a large subset of C, so I don't see why formalizing (a large subset of) rust and making a formally proven compiler shouldn't be possible

      • UncleMeat 1 day ago

        Because people want a performant optimizing compiler.

        • MaxBarraclough 1 day ago

          CompCert produces surprisingly fast native code.

          This 2022 article [0] says it generates binaries that run about 7% slower than what GCC produces with -O1.

          [0] https://www.cs.cornell.edu/courses/cs6120/2022sp/blog/compce...

          • UncleMeat 8 hours ago

            That's a big gap, especially with the norm for releases being O2 if I understand correctly.

            • MaxBarraclough 2 hours ago

              > That's a big gap

              I wouldn't say so. The gap between GCC and Clang/LLVM is bigger than that on some benchmarks, [0] although the gap between their overall performance (using geometric mean) is much less. [1]

              It's a very impressive result considering how much effort has gone into GCC. It highlights how compiler optimisation work can face diminishing returns.

              > the norm for releases being O2 if I understand correctly

              Agreed, but the difference isn't that great. From the article:

              > CompCert code is 7% slower than gcc-01 and 12% slower than gcc-02 on average.

              Reminds me of how the cproc/qbe C compiler gets very roughly 50% of the performance of Clang/LLVM in 0.1% the lines-of-code. [2]

              [0] https://www.phoronix.com/review/gcc-16-vs-clang-22/3

              [1] https://www.phoronix.com/review/gcc-16-vs-clang-22/6

              [2] https://drewdevault.com/talks/qbe/ (and see the linked slideshow PDF, as the abstract is a little misleading)

      • afdbcreid 1 day ago

        There is a severe misunderstanding here. Beside being only a subset, CompCert definitely has UB. It just formalizes codegen for codebases not containing UB, which obviously won't be enough for Rust.

      • afdbcreid 1 day ago

        Also unlike C, it should be possible to formalize all of Rust, not just a subset. For two reasons: Rust evolution (not initially but today) is strongly tied with formalizing it and the language team consults with formalization experts (which are part of the Rust project themselves) all the time (and formalization or semi-formalization projects are ongoing), and also the mathematical understanding of system languages itself has advanced.

        • j16sdiz 1 day ago

          This reminds me of Hilbert’s Program .

        • uecker 3 hours ago

          It is possible to formalize all of C.

  • stingraycharles 1 day ago

    Why would that be ironic? AI is helping us find so many subtle bugs and isolate the root cause, it’s nearly perfect for this type of use case.

    • apt-apt-apt-apt 11 hours ago

      Perhaps they meant "like an iron, it will stamp out the bugs"

  • mi_lk 1 day ago

    What aspects of it are remotely ironic?

    • brzz 1 day ago

      Hey, if Alanis Morissette can make the same mistake…

    • jere 1 day ago

      Obviously, many people have viewed AI’s contribution to programming as just producing unreliable garbage.

      Yes, that’s an incomplete and tenuous belief, but that’s where the irony is. If you’re omniscient you don’t get to experience irony.

    • antonvs 1 day ago

      “Slop generator makes all future programs more reliable”

      • sanderjd 1 day ago

        Yeah this is actually quite interesting. I can see how people who have this "slop generator" perspective on AI would see this as an irony. But to me, it isn't an irony, it's a demonstration of why this perspective on AI is wrong.

        • antonvs 22 hours ago

          I assume that's why the original comment said "perhaps ironically".

          I'm firmly in the "AI is incredibly powerful and useful" camp myself, but there's no question that currently, without good human oversight and feedback, AI output can have many issues which can be described as slop.

          But yes, improved type systems are one of the ways this can be managed, and essentially help bootstrap more reliable systems.

          There's a minor irony in imperfect system being used to help build more perfect systems, but you could say the same thing about human developers.

          • sanderjd 20 hours ago

            Yeah I mean I'm not that interested in debating the definition of "irony", but it just doesn't strike me as ironic at all that AI is good at doing the grunt work to expose a bug like this! If you think "wow, it's ironic that AI can be used to improve software quality" instead of "well yeah, this is exactly the kind of thing that AI is good at", then IMO you've got your priors about AI mixed up.

            • antonvs 13 hours ago

              You're right. I was just saying I could see where the idea of irony was coming from.

              • sanderjd 4 hours ago

                Yeah I can see it too! That's what made it an interesting point to me. I totally recognize there are people out there who see this as an irony. My point is that this is an interesting demonstration of the way in which (IMO) those people are misperceiving things.

  • malkia 1 day ago

    and what stops AI from "accidentally" writing code with such bugs?

    • hbn 1 day ago

      Code review and testing? As always?

    • antonvs 1 day ago

      The compiler. That’s the whole point here. Type systems can prove the absence of entire classes of bugs, at compile time. If AI identifies bugs in type systems that can be corrected, then all future programs benefit, including those written by AI.

  • lifeisloving 1 day ago

    I asked myself, How many comments to do I have to collapse before someone says something about AI. 3.

    I used to compare this hype to crypto hype, but its so much worse. Can we just try not to shove llms into every single conversation.

    Is there a hackernews type space where the word is banned? Even lobste.rs has this problem. I need some sort or way to just hide all content on certain sites where LLMs/AI are mentioned.

    • streetfighter64 1 day ago

      I'm not a huge AI hype man, but I think you'll just have to accept it. It's a new useful tool, of course people are excited to apply it to everything.

      Like it or not, programming will become largely LLMs. And the comment you're replying to is actually making a pretty good case for where the use of LLMs is good: generating code to be formally verified.

      • lifeisloving 1 day ago

        Something something halting problem. I never said don't use the tool!! I use the tool too! I just dont want to talk/read about it all the time.

        Programming will never be dead.

        1. Because the situation you describe is fantasy.

        2. Even if it is a reality and all software can be verified (it cant), I will still be programming and so will millions of others because its fun, programming and sex are really damn close to things I cant live without. Not everyone got into engineering for the money. I legitimately love this activity, it is my actual passion. I would rather be poor than give it up.

        Its like im being told everyday all day, non stop that the thing I love is not worth loving.

        • SV_BubbleTime 1 day ago

          I guess that’s something you need to work through that you’re just so sick of reading about the single biggest evolution in technology since the internet :(

          Maybe tech isn’t for you if you don’t like trying to stay on top of it.

          • lifeisloving 1 day ago

            Huh...

            Anyways, I probably know more about llms than you, I probably use them more than you. I just dont want to turn every conversation into a discussion about them.

            I would argue the smartphone is 1000x more impactful than LLMs, along with many other inventions since the internet. I'm not really sure what contribution llms have had that are actually THAT impactful for peoples lives. Its possibly (but unlikely) a net negative, time will tell. Most people using them are not getting smarter, thats concerning. Most are just making more money for their bosses who are itching to replace them with an llm.

            • streetfighter64 1 day ago

              I think the problem you're seeing is not with LLMs per se, but with capitalism. Imagine we have a quite useful machine that's reducing the amount of work needed to accomplish stuff, and all normal people are afraid of that machine simply because they worry they'll have less work. How backwards is that!

              If we didn't let people live off the work of others, as the capitalists do, then we could all rejoice in that we've found yet another way of reducing the labor required to produce stuff.

              Yet, in the real world, it seems as despite the progress of technology, the labor of the everyman is constant, and only the richest get more and more shiny jets and yachts.

        • wanderlust123 1 day ago

          This seems more like you projecting what you want in terms of what you enjoy and hoping the world optimises around that preference.

          The truth is LLMs is what you need to be optimising around as they will become the standard.

          • 1sh172645 1 day ago

            Why don't you start TruthLLM like Trump started TruthSocial?

        • 1sh172645 1 day ago

          You need to bow in the direction of Silicon Valley every three hours or the inquisition comes.

        • samus 1 day ago

          Of course people will still program for the foreseeable future. But it is still a legit question how long it will be before people come to accept a vibe coded program and are ready to deal with its flaws (of course with more vibe coding) compared to hiring a consultancy.

          I'm not talking about mission critical software, but bespoke business applications that are produced by software engineering sweatshops and where the actual users are inured to incomplete features with sharp edges, arcane bugs, and incomprehensibly long intervals between bug report and fix.

          Even in mission critical software we will likely see a lot of LLM tool usage. Even if the copyright plug is pulled and all vibecoded applications are regarded as copyright violations, its uses to analyze existing code and give advice will remain. In this world, writing applications entirely by hand will become an artisanal discipline.

        • streetfighter64 1 day ago

          I see. I'm not trying to put down your love of programming. The only programming that I really can say excites me (C64 or the like) died a long time ago, before I even started programming for money.

          Nothing is stopping you from enjoying the sort of programming that you like. But I think it's healthy to accept that that style will soon not be mainstream. It will be like knitting your own clothes, and that's okay.

          Regarding formal verification, it's not needed, as LLMs already make on average about as many errors as the average human programmer.

          For me, 90% of programming is just a tool to get the job done. It's like a machine in a factory that spits out 50 spoons a minute, and it doesn't need to be any more beautiful than that. If you enjoy woodcarving and want to spend an hour making your own spoon, do that and don't let the existence of the machine make you feel that hobby is any less worth loving.

      • 1sh172645 1 day ago

        Thank you for citing the Anthropic propaganda manual!

    • purplesyringa 1 day ago

      lobste.rs has a `vibecoding` tag that you can hide.

      • alethic 1 day ago

        Unfortunately, a large proportion of stories submitted to Lobste.rs are slopped out... even if they don't mention AI, it's hard to escape there. Hacker News at least has functioning story-level moderation.

    • vor_ 1 day ago

      I browse Hacker News stories via this: https://unslop.news/

      • otherayden 23 hours ago

        Yeah the HN home page today seems especially bad

      • lutoma 11 hours ago

        Oh that is very nice. I had been thinking about building something like that, happy to see someone beat me to it. Might actually make me check hacker news more frequently again.

    • brabel 15 hours ago

      Reddit r/programming banned AI topics and AI written content and comments. Unfortunately there is not a whole lot going on there anymore as a result.

  • groundzeros2015 1 day ago

    > complete reliability.

    I think that’s a myth! What tends to happen in mature software is there are unfixable tradeoffs that can be made that favor one use case or another. And of course people will keep adding features too

    • dymk 1 day ago

      That’s why they said “closer”

    • vips7L 1 day ago

      Just wait until someone relies on that bug too.

      • Ygg2 23 hours ago

        Rust considers fix to unsoundness bug, a change that can be done at any SemVer revision (i.e. a patch version bump can break it).

        If your spacebar heater relies on such behaviour Rust can and will break it. If you're in the crater group you'll be notified and urged to upgrade it.

Eridrus 1 day ago

I feel like these things get waved around as gotchas without any sense for whether any real code is impacted.

It will be interesting to see if fixing this bug actually causes any crates to not compile.

  • Falell 1 day ago

    We should know shortly, the PR to fix this will presumably be paired a crater run, a build of the entire public crates universe.

mrkeen 1 day ago

Type systems are hard! Check out https://counterexamples.org/

I gave it a quick scan for Rust examples; there are 11 samples among the following pages:

  https://counterexamples.org/eventually-nothing.html
  https://counterexamples.org/mutable-matching.html
  https://counterexamples.org/selfishness.html
  https://counterexamples.org/scope-escape.html
  https://counterexamples.org/nearly-universal.html

The first thing I always look for is mutability (combined with some other tricky feature), e.g. "Now it's a Just(3):Maybe<Int>, now it's a Nothing:Maybe<Int>, now it's a Nothing:Maybe<String>."

I wonder if TFA's example could be reproduced without mutability.

  • vrighter 1 day ago

    so what I take from this is that the rust compiler does not guarantee the stuff it claims to. Because new features of the type system is just being yolod instead of formally proven

    EDIT: I said new features of the type system and more importantly, their interactions with the ever growing list of other features, not new features in the compiler. Totally different things. The compiler could be perfectly implementing the wrong choice of algorithms in the first place.

    • thfuran 1 day ago

      No mainstream compiler is formally proven. If you want a verified compiler, you pretty much have to choose between using a subset of standardml or a subset of C and the one proven compiler for each.

      • vrighter 1 day ago

        You're mistaking the semantics of the type system, from the implementation. I'm not talking about verifying the compiler. There's nothing to verify there.... literally. There is no spec to the language. By definition it is verified because the only verification you can do is tautological: "does this rust compiler do what this rust compiler does?"

        But the unsoundness is because the type system itself, abstractly, was not verified. Or the interactions between parts. I.e. If you verified the compiler you'll find that it implements the algorithms perfectly. But tells you nothing about whether those implemented algorithms, however perfectly implemented, actually provided those guarantees.

        • vlovich123 1 day ago

          They probably meant things like LLVM and the various optimization passes. None of those are verified, there’s probably all sorts of correctness issues, and yet it’s still ok. Rust’s usage also has issues and bugs emitting the right intermediate form for LLVM to consume and usually also it’s ok.

          Would it be nice if we had even higher level of quality? Yes. But what’s neat is we have empirical evidence - Rust code does achieve the memory safety goals over C++ even though there’s bugs in the compiler. That’s why Rust is very quickly eating all things C and C++. A huge amount of value that the industry would just be unable to access for a long time if you waited for everything to be formally proven.

        • thfuran 1 day ago

          Okay, but verifying a type system and language specification for soundness wouldn't actually give you any of the guarantees you want if the compiler toolchain isn't verified to implement them correctly. And this sort of thing just isn't standard practice in the industry and never has been. Sure it would be nice if more things were verified, and we are somewhat headed in that direction, but it seems weird to say that rust specifically is just a bunch of half-baked yoloing because it doesn't do something that essentially no other language is doing either.

    • csande17 1 day ago

      Yes. When people describe Rust as "a memory-safe programming language" they are describing an aspirational vision, and not a programming language that has actually been designed with sufficient rigor to guarantee memory safety. Any failure of rustc to actually guarantee this is just a bug in rustc itself, a failure to properly implement the Rust spec, because the closest thing Rust has to a spec is literally just the vague ideal that the compiler should guarantee safety somehow.

      Rust cannot fail, it can only be failed.

      • lolakutty 1 day ago

        >Rust cannot fail, it can only be failed...

        Sweet. But why should anyone care..

      • UncleMeat 1 day ago

        Would you say the same thing about Java? It’s type system is also unsound.

        • csande17 1 day ago

          I'm not an expert on the Java specification, but my understanding is that Java as a language is well-defined enough that we can say things like "Java's type system is unsound", independently from any specific implementation of Java.

          You can't do that with Rust because "Rust's type system" is literally just the vague concept of "a type system that is safe". The implementation of this ideal in rustc can have flaws, but Rust itself cannot, because Rust itself has no flaws by definition.

          • mcherm 1 day ago

            It is true that Rust does not have a complete formal specification for its type system which has been analyzed and proven to be sound.

            You seem to be implying that because of this, Rust has no definition of its type system (other than whatever happens to be implemented in the current compiler). I would disagree.

            As evidence, I would like to point out that not a single person argued that this flaw was not a bug, but was in fact the officially defined behavior. Clearly, the community has a shared understanding of what Rust's type system "ought" to do.

            • csande17 1 day ago

              The true specification was inside our hearts all along!

              • Ar-Curunir 1 day ago

                I mean yes, part of our understanding of systems is a social one!

                • csande17 1 day ago

                  Sure, but in Rust's case the social understanding is "there exists some type system that guarantees perfect memory safety, and has the general aesthetic features associated with rustc's type system, and 'Rust' is defined to be whatever that type system ends up being".

                  This is a nice ideal, but it doesn't actually exist in concrete terms as a design. It can never have flaws because the definition of it is just "rustc without all the flaws".

        • vrighter 1 day ago

          but it isn't claiming to be saving you from things it can't prove it can either.

          • thfuran 1 day ago

            Memory safety was always a major selling point for java.

      • insanitybit 1 day ago

        I don't think the definition of "memory safe" has ever required full end to end stack conformance with a proof. Very few languages have achieved that, though some have. Most people call Java memory safe, C#, Python, Typescript, etc - all of those fall short of a formally verified, sound type system with a verified toolchain.

        • afdbcreid 1 day ago

          Not to talk about Go, which has intentional unchecked-at-runtime UB (data races) yet many argue to consider it memory safe (and I have a feeling that the same people arguing Rust isn't memory safe are also there. Just a feeling though).

      • DriverDaily 1 day ago

        > Rust cannot fail, it can only be failed.

        “Please build the perfect system. Because I specified ‘perfect’ any flaws are due to your incomplete implementation, not my awful brief.”

        If the person writing the rust spec was a client I would have to drop them because they would be setting themselves up for dissatisfaction.

    • roblabla 1 day ago

      There never was formal verification of the entire rust compiler, or even its complete borrow checker/type system. There has been verifications on _subsets_ of them.

      Also, a lot of those soundness issues aren't related to new features _at all_, but usually due to poor assumptions made in optimizations.

      The soundness bugs _are_ taken seriously though, and are slowly being patched out. A lot of the links in OP are now closed because Rust either changed how it generates code to avoid the issues, or fixed LLVM.

      • vrighter 1 day ago

        not of the implementation. Of the type system. And a verification of subsets, but not a verification of their interactions == the whole system is unverified.

        • streetfighter64 1 day ago

          It holds that ¬(∀subsets: isverified(subset)) but it's not true that ∀subsets: ¬isverified(subset), which it think most people would interpret "the whole system is unverified" as

          • vrighter 1 day ago

            If I independently verify that subsystem A properly consumes apples, and that subsystem B is properly emitting oranges, but never verify that subsystem A is receiving apples, and just connect subsystem B to it, then yeah, the system is not verified.

            • samus 1 day ago

              That's not the issue though.

            • cmrx64 1 day ago

              you’re deeply confused but the words “validation” and “qualification” may help untangle the web, there’s a lot more to assurance than what your model seems to hold (and you’re drawing batshit deductions from it)

        • afdbcreid 1 day ago

          The eventual goal is verification of the full system. Not the implementation, yes, that's infeasible. But this will mean all soundness bugs will be either found and fixed or we'll know how to fix them once they're found. In any way they won't be fundamental (which is believed to be the case today, but not proven).

          • vrighter 1 day ago

            so why put them in before knowing if they work reliably? That's the YOLO part, to me

            • dwattttt 1 day ago

              You're claiming that this bug that reproduces back to Rust 1.4 (2015) is a sign they're adding too many features to make sure they don't introduce bugs? Or do you have bugs that are due to these recent features?

            • cscheid 1 day ago

              The same combination of reasons we've been doing these kinds of heuristic implementations forever:

              - people still get value off of an incomplete implementation, because we are allowed to be mindful of the issues (see, eg, UB in C++). In other words, many, many more bugs have been prevented by the borrow checker working as intended than have been caused by it working poorly. It's not particularly close.

              - theory almost always moves slower than practice

              The mutable state situation pointed out by the grandparent poster was a famous issue in typing SML under mutability that required serious changes in the language, see Section 4.2 here: https://smlfamily.github.io/history/SML-history.pdf

              These were Turing-award caliber people figuring it out and, according to your definition, "yolo"ed it. This stuff is _hard_, and these driveby comments truly aren't helpful.

            • vlovich123 1 day ago

              Because there’s real value delivered even before that? Perfect bring the enemy of good and all that

    • jeremyjh 1 day ago

      There is a massive possibility space between “yolo” and formal proof. Rust has substantial evidence of correctness. For example, unit tests and types.

      • vrighter 1 day ago

        That's verifying the implementation. The type system wasn't verified. It implements stuff perfectly, it has tests that prove it, but nobody formally verified that they perfectly implemented the correct algorithms

        • bluGill 1 day ago

          Tests are not perfect, but they are a lot better than where we were in 1990.

          • vrighter 1 day ago

            completely tangential to whether you're testing for the right thing.

            • bluGill 1 day ago

              We are a lot closer to testing the right thing today than we were in 1990!

              There are pros and cons to tests, but they do some things very well. For starters a test is a lot better sign that things work as intended than a formal proof which is often so abstract most people can't be sure how it relates to what was intended. You can prove something correct that is clearly wrong. While a test will only test the one case, at least it is typically easy to understand that case and why that answer is correct. Of course if your requirements are correct your proof will tell you it is correct for all cases while a test is limited to that one case. Again pros and cons, and people speaking against tests are not honest about those.

              • vrighter 10 hours ago

                whether you're testing for the right thing is a binary question. We can't be any closer. To be pedantic, since Rust didn't exist in the 90s then we would be NaN% closer!

    • UncleMeat 1 day ago

      The Java type system is also unsound. That’s life. It is hard to do this fully correctly. In practice this never comes up.

      • afdbcreid 1 day ago

        While true, there are two important differences:

        1) Unsoundnesses in Java's type system are checked at runtime.

        2) They (or at least some) are intentional or at least won't-fix bugs.

        Both are not true for Rust.

    • itishappy 1 day ago

      Formal verification of the type system does seem a worthwhile goal, and to my understanding it's something the community has been making progress towards, but I also understand it's still relatively uncommon for most languages.

      Is this more an abstract concern over the state of the industry, or is there a specific language you had in mind that you'd prefer Rust was modeled after?

      • thfuran 1 day ago

        Relatively uncommon as in there is not, as far as I know, a single mainstream language with a formally verified spec.

    • mirashii 1 day ago

      Important to note that this is is not a bug in the type system itself, it's a bug in the borrow checker not enforcing invariants that the type system says that it should, and formal verification of the type system would not have helped here.

    • steelframe 1 day ago

      The font color is so close to the background now that I can't even read your edit. Sorry, bud.

  • codehero 1 day ago

    "Type systems are hard!" As hard as its safety is pushed on us, not even Rust is free from hand waving.

    • ahartmetz 1 day ago

      At least Rust has a chance to be largely correct because it has much greater effort per amount of code (in the compiler) invested into it than most any application code.

    • caaqil 1 day ago

      > not even Rust is free from hand waving.

      It is moral though, so who cares really.

    • doodpants 1 day ago

      I mean, Rust's whole shtick is safety, so that's really the only thing there is to "push" about the language.

      • oersted 1 day ago

        I wouldn’t say so… I consistently choose Rust mainly because it’s a sanely designed modern C++ alternative. It’s 20% more effort than writing Python or Typescript, and you get to use the full power of your hardware without compromise.

        Safety is a nice side-benefit. The main reason why I like the safety is because it allows you to fearlessly write high-level code without being constantly paranoid about memory as in C++. It’s more about enabling ergonomics without loosing performance, rather than security or correctness.

        • ryandrake 1 day ago

          The paranoia about memory use in C++ should mostly be a thing of the past if you’re using smart pointers and sane patterns. In 2026 almost nobody should be calling new and delete and passing around raw pointers.

          • AlotOfReading 1 day ago

            And yet applications written in modern C++ are constantly discovering new memory safety issues. Sean Baxter wrote a whole manifesto talking about the shortcomings of the existing C++ model [0].

            [0] https://safecpp.org/draft.html

            • bluGill 1 day ago

              The problem with manefestos is they often harp on small parts that don't matter much in the big picture. There are real shortcoming of the C++ model, but if you use modern C++ they are rare.

              The real shortcoming it is very common for people to not write modern C++. I know several C++ developers who refuse to use smart pointers because they don't like magic happening.

              • AlotOfReading 1 day ago

                It's not enough for memory safety issues to be "rare". To meet your obligations under the standard and have defined behavior (i.e. rust's basic guarantee), memory safety issues can't exist at all.

                • munk-a 1 day ago

                  Ah, so this article invalidates all of the safety guarantees of rust? Since one hole was found the entire boat is shot and should be left at the bottom of the harbor?

                  C++ has a terrible reputation which is well associated with, say C++98, if you have a good linter you can bop people on the head for using news anywhere outside a few limited locations where you consider it warranted. All working environments have language features or even programming paradigms that are considered detrimental to code ecosystem health and fighting against these is an organizational lift when working in any programming language. Full type security doesn't mean someone can't create an overly generic object and just start breaking code contracts across the code base. C++ has an awful lot of footguns and more warts than most but it can be made to be sane for development and the new language features really bring it on par with other modern languages.

                  I have worked in C++ (primarily within the Qt framework which pushed hard into const refs instead of pointers) and it's fine. I've also worked in PHP which can also be fine. Rust isn't something I've worked at scale in but it certainly is very attractive if I ever jump to an org working in it - but even in Rust you'll want to restrict style divergence and bad patterns with linting.

                  • AlotOfReading 1 day ago

                    I'm only talking about modern C++, not C++98. C++'s footguns include smart pointers. For example, is the following code safe?

                        std::unique_ptr<int> p(foo());
                        std::print("{}\n", *p);
                    

                    The answer depends on how foo() is implemented. You can't reason about it locally, and strictly speaking it's not possible to determine at compile time. Now, I should be declaring this gsl::not_null<std::unique_ptr<int>> to comply with the core guidelines, but I think we can agree that optional support libraries aren't relevant to this discussion.

                • bluGill 1 day ago

                  Throw your computer away then. Rice's theorem and Godel's incompleteness theorem both make anything other than rare impossible.

                  These issues will exist for all time. The only question is how rare can we make them.

                  • AlotOfReading 1 day ago

                    That's trivially untrue. Nothing about turing machines or lambda calculus requires temporal unsafety. Even this example wouldn't exist if the compiler rejected covariant lifetimes. You already know this of course, so I'm not going to keep beating that dead horse.

                    The obvious follow-up is to find a minimal set of rules that allow us to express what we want without permitting temporal unsafety. The borrow checker is one set of fairly minimal rules that works pretty damn well. Alternatively you could define away the unsafety by giving it semantics, like fil-C does.

          • foldr 1 day ago

            C++ still doesn't have a sane modern pattern for tagged unions. If you want to define a type to represent, say, a simple parse tree, then Rust makes that easy and obvious, whereas C++ offers you a hundred options, all of which suck.

            • sltkr 1 day ago

              Isn't the obvious choice std::variant<>?

              It is kind of annoying to use, but at least there is an obvious default choice.

              • foldr 1 day ago

                I take your point about it being the default, but IMO std::variant is pretty much unusable for a parse tree. It could work for small unions that you visit once in a while, but traversing a nested tree of std::variant types is just a disaster. It somehow manages to be comprehensively worse than using manually tagged unions in all aspects except safety.

          • bluGill 1 day ago

            The reality though it many people are not using smart pointers. I have seen many people argue they don't like them because they want to see every place delete is called. (meanwhile of course they never notice all the places it should be called but isn't - but at least where it is they see it)

            • bayindirh 1 day ago

              Personally I love to use smart pointers where bleeding edge performance is not necessary.

              If I need the absolute fastest code, then that code will be tortured under valgrind. That’s non-negotiable in my book.

              Code is not done until its memory management is proven correct.

            • thayne 1 day ago

              It's more than that. Smart pointer help, but there are cases where even when using smart pointers you can encounter memory safety issues. Especially when you need to interact with c or older c++ code that doesn't use smart pointers. And smart pointers don't provide any protection against data races in multi-threaded code, like rust does.

              • LeSaucy 1 day ago

                smart pointers solve a different problem than data races

                • thayne 1 day ago

                  That's my point. C++ doesn't have an equivalent of rust's protections around Send and Sync.

            • IcyWindows 20 hours ago

              Won't those same people just use unsafe in Rust?

              If not, why would they be allowed to do the same in C++

        • cb321 1 day ago

          Most things like "sanely" and "20%" are pretty subjective. To me writing (or really reading well written) Nim (https://nim-lang.org) is less effort than writing Python or Typescript. Nim is mostly Ada & Lisp ideas packaged in a more terse & flexible surface syntax. Nim also has nice compile-time introspection and very low effort macros to allow packaging near zero-code APIs like github.com/c-blake/cligen. Also, something like 5 out of 5 times I've investigated some Rust alternative to some Nim code, the Rust ran more slowly than my Nim on my tested CPUs.

          With access to inline asm, all speed is ultimately more a measure of effort applied than PLang. So those perf ideas are just "with my level of effort". Even Python via Cython has pretty direct access to asm. The "do it in pure X" that Sun popularized (even in a meta-/cross-PLang-sense) as a business attempt to define Java virtual machines as The platform has had many casualties, not the least of which is the quality of discussion of PLang practicalities, not just on HN, but everywhere.

          • oersted 1 day ago

            I have heard great things about Nim, you may be very right. It’s just that it’s impossible to ignore the benefits of a mainstream dependency ecosystem. The ecosystem is exactly what made Python and Javascript the giants they are today, despite being somewhat mediocre languages. And the Rust ecosystem is in that same league, without giving up exceptional performance, and without giving up too much ergonomics.

            PS: I was very enthusiastic about Cython for a good while and I went deep into it, but I found that it is rather a mess to use in practice. Yes you get C performance within Python, kinda, but you also get all the C footguns, amplified by the complex interactions with Python features.

            • cb321 1 day ago

              Yeah. Other ecosystems are undeniably larger than Nim's. I keep hearing about how LLMs are going to nullify that advantage with "not so sloppy" ports of anything to any PLang, but I've yet to see that pattern materialize. "What is a clean interface" is probably a kind of subjective judgement call, but also very clearly depends on PLangs and even PLang cultures. For example, the microdependency culture of Rust/JS/Node have very little to do with the PLang's themselves.

              EDIT: With Cython how I mostly kept things organized was the "caller allocation" so common in C where memory was always managed the usual mostly refcounting way of CPython/NumPy, but I had dozens (maybe even 100) little "kernels" I could pass that memory into that could even use Intel/MSFT "intrinsic" asm calls (things like immintrin.h) or even just #include C code which did similar. It didn't seem too bad to me, but Nim always seemed a more complete solution (at the PLang level - not counting ecosys). (And these days there is even NimPy (https://github.com/yglukhov/nimpy) to write low-level speed-up code for Python in Nim.)

          • thayne 1 day ago

            There are a lot of nice things about nim, but it's absence of any kind of dynamic dispatch is a pretty serious limitation.

            • cb321 1 day ago

              This is misinformation. There is (at least!): `method`, procedurally typed fields (inside case-object variants or not), run-time keyed `Table` with proc values, {.dynlib.}, importc/importcpp things. Beyond that, yes, Nim has rare compile-time superpowers that do lead many of its proponents to use static constructs (totally grant that!). So, you may not see a lot of dynamic dispatch in code bases, but there is little stopping you from using them in your own code.

              • thayne 1 day ago

                Ah, yes, I should have been more precise. It doesn't have an equivalent of an interface/trait/protocol with dynamic dispatch.

                Yes, you can pass around an object of procedures, but that is awkward, doesn't have any support from the language or stdlib, and from what I can tell isn't a normal thing that is done.

                • cb321 1 day ago

                  Even back in 2013 there were these ideas: https://forum.nim-lang.org/t/278

                  I think you & I are really back & forth-ing "the PLang not enforcing/strongly encouraging a very specific way of doing things that a whole ecosystem/community organizes around". Relying instead on self-organization has many pros & cons, to be sure. Lisp suffered much the same "until" Common Lisp (which still leaves many things open). My tag line lately is: delegation affords so much, but trust sure is tricky. Much of the time people seem to discount the often rather large cost of establishing/maintaining trust. (I'm not saying you are - just that it's an easy thing to do. I think it's why there is this is a big megathread on "trusting rust", even though "rust" is a veritable suffix of "trust". Lol.)

        • munk-a 1 day ago

          > It’s 20% more effort than writing Python or Typescript

          I'd disagree with this point, there is more typing involved with a first draft of code than Python or Typescript, that's certainly true, but if we bring all the tools (e.g. docblock comments for "type declaration") that are habitual to make up for the shortcomings in most developer's minds then that gap shrinks and, imo, ends up swapping. It's cheaper to have automatically enforced and consistently maintained checks than moving that information out of band and the resulting code in a strictly typed and memory enforced language ends up removing a significant cognitive overhead when reading and maintaining the code.

          I have a strong aversion to boilerplate code so it's important to try and allow terse expressions when possible - but unstated assumptions are worse than overstated assumptions.

      • eloisius 1 day ago

        Rust has a lot of things that make it nice to write in. Robust enums and pattern matching are something I miss greatly when I’m back in C++. The trait inheritance system is also very flexible and I miss that. Especially compared to monstrosities like multiple inheritance.

      • hackingonempty 1 day ago

        Part of Rust's schtick is also cost free abstractions.

        • justinhj 1 day ago

          Neither C++ nor Rust is zero cost in many cases. Rust needs unsafe or expensive runtime primitives for doubly linked lists, an lru cache, a tree with parent pointers... Both patch the language gaps with libraries.

      • airstrike 1 day ago

        Only people who don't write Rust think Rust's whole shtick is safety.

        Consider reading past the hashtag.

      • nimih 1 day ago

        Idk, it also has a nicely expressive typesystem outside of lifetimes, a lot of modern syntactic features like pattern matching and monadic error handling, well-written compiler error messages, a well-designed standard library, and substantially less accrued cruft when compared to its largest competitor. Safety might be the cudgel its evangelists like to beat everyone over the head with, but there are certainly things to recommend it outside of that.

    • antonvs 1 day ago

      Rust’s type system enables the possibility of discovering and fixing a bug like this, and ruling out this class of bugs for all future programs.

      The hand-waving comes from other languages which can’t do anything to prevent their users encounter such bugs and the ensuing CVEs.

  • immmmmm 1 day ago

    Aren’t some type systems (eg Lean) able to essentially verify/prove arbitrary mathematics?

    • kachnuv_ocasek 1 day ago

      Yes, until you introduce inconsistent axioms. Then you can prove anything.

  • oconnor663 1 day ago

    https://github.com/JelleZijlstra/unsoundness is also a great collection of Python type system holes. In these cases, it's mostly deliberate design decisions, not bugs. The unfortunate fact is that a fully sound Python type system would be a pain to use.

    • metalliqaz 1 day ago

      Perhaps I'm just an old dog that doesn't want to learn new tricks, but I still can't think of Python as typed and I never use type hints. I started with Python during the 2.3 era. I still view Python types as merely docs. So it's nice that someone tracks mypy quirks but I can't imagine relying on the results for anything serious.

      • ChrisSD 1 day ago

        To be very pedantic, Python was always strongly typed in the sense that every value has a concrete type. This is very different to, e.g. C, where `void*` is often used to actually erase the type or, conversely, more abstract languages where there are only interfaces.

        But of course Python function were always duck typed so it often didn't matter to the user.

        • eru 1 day ago

          Well, Python has a static type systems, it's just that everything has the same static type. We should call these 'unityped' languages, not 'untyped'.

      • oconnor663 1 day ago

        If you deal mainly with small-to-medium size Python programs, which is probably the norm, that makes sense to me. But if you have a large Python application, or if you own a library API that might have a lot of callers, typecheckers catch sooo many mistakes.

        • ReflectedImage 21 hours ago

          Not really, I measured it.

          Typing prevents 1 minor bug per developer per year reaching the testing environment.

          It costs 2x development time to use. (With LLMs it's doubles token usage, very measurable)

          It's not actually a sane trade-off.

      • Twirrim 1 day ago

        I've been writing python for closing in on two decades (I want to say maybe 2.5 was my introduction point?).

        I've found type hints to be remarkably useful and catch significantly more bugs than I ever would have thought, and have quickly picked up the practice of using them wherever I code. My general finding is that if I have to struggle to put useful type hints in place, I probably need to rethink my code.

        I even type hint my unit tests because I've learned that sometimes type incorrectness means my tests haven't been testing what I thought they were testing.

        Frameworks like pydantic[0] can help you turn those type hints into something runtime enforcing too.

        [0] https://pydantic.dev/docs/validation/latest/get-started/

        • ReflectedImage 21 hours ago

          Generally speaking, static typing is the great enabler of writing bad Python code.

          As soon as static typing is introduced into a Python code based, the developers start writing unscalable coding patterns that don't scale to larger programs.

      • tikhonj 1 day ago

        You can't rely on Python's type hints for serious verification, but it can be great for expressing abstractions and giving people (and, today, agents) better affordances for using them. Even static errors that will not always fire can still help a lot for using a library correctly and for noticing mismatches in your codebase as it evolves over time.

    • gsnedders 1 day ago

      > The unfortunate fact is that a fully sound Python type system would be a pain to use.

      Even beyond Python, most gradual type systems are unsound by design.

Surac 1 day ago

The question is. If rust used rust would that have prevented this?

  • zamalek 1 day ago

    Rust does not prevent all bugs, only certain ones (that are common and dangerous).

  • loa_in_ 1 day ago

    Rust allows for type-proofing your logic, but it can't force you to.

  • romac 1 day ago

    The Rust compiler (rustc) is written in Rust, but there can always be bugs in the compiler, regardless of whether it's written in a memory-safe language or not.

    • throawayonthe 21 hours ago

      it's a joke, riffing on the "would rust have fixed this?" referring to any vulnerability

j4k0bfr 1 day ago

Took me a good couple minutes to wrap my head around. Man, what a nasty bug. I guess this specific use-case is rare. Time to see if any of the big libs are affected...

  • coliveira 1 day ago

    A nasty and rare bug can and will be exploited once it is found. The only thing necessary is for malicious actors to start adding this case in innocent looking code and there you have.

    • afdbcreid 1 day ago

      That's a misunderstanding. This is not a security vulnerability and Rust explicitly does not defend from malicious programs, only from mistakes. This bug however is quite dangerous, because unlike many soundness bugs it seems plausible to hit by mistake.

      • Liquid_Fire 1 day ago

        > it seems plausible to hit by mistake

        The report seems to claim the opposite:

        > Looking at the bug itself, it is also very likely that this unsoundness has not caused memory unsafety by accident. While it looks easy to trigger, to exploit this you need an intentionally malicious Drop implementation.

        • afdbcreid 1 day ago

          This edit is newer than my comment (and its writer is an experienced T-types member, so I take back my words).

        • j4k0bfr 15 hours ago

          I'm happy to admit I don't really know what I'm talking about with this bug, however the ability to leak memory is pretty demonstrable, no? The OP's example of using a global cache with Drop seems a bit gross... but that hasn't ever stopped C devs lol (as a proud C dev myself).

          I guess my take is that I'd rather assume this is exploitable in the wild until sufficient time has passed. Would be cool to see clippy pick up on this bug in older versions!

          • rstuart4133 14 hours ago

            > however the ability to leak memory is pretty demonstrable

            It is, but safe Rust merely makes it hard to do by accident. Leaking is not "memory unsafe" because is does not currupt anything, so it's legal.

          • aw1621107 14 hours ago

            > however the ability to leak memory is pretty demonstrable, no?

            This bug wouldn't be nearly as interesting if it "just" resulted in a memory leak. Memory leaks aren't considered unsafe in Rust because they can't result in UB in the same way as e.g., OOB writes. In fact, there are APIs accessible in safe Rust which explicitly leak memory! [0]

            This bug is effectively a use-after-free, which is definitely something that the Rust compiler should catch.

            > Would be cool to see clippy pick up on this bug in older versions!

            No need for that. A future version of the Rust compiler that incorporates a fix should reject the incorrect code, so all you'd need to do is compile older code with that new compiler.

            [0]: https://doc.rust-lang.org/std/mem/fn.forget.html

      • rstuart4133 15 hours ago

        > This bug however is quite dangerous, because unlike many soundness bugs it seems plausible to hit by mistake.

        Possibly. I'm no rust expert, so I had the read the code slowly, building up a mental model of the types being used. For me, the effort that required is one of the more painful aspects of Rust.

        Nonetheless when I got to this line, I stopped reading:

            q.0 = Some(&l);
        

        Given the type declarations it's "obvious" it should not compile as it directly contradicts the types 'static lifetime. You don't deliberately write code that doesn't compile.

        I write lots of code that doesn't compile of course. It's perfectly safe because the compiler catches it. Right now, I feel like a climber at the top of a mountain who just discovered he forgot to attach his safety harness.

        Who knows. Maybe all of crates.io will compile with the fixed compiler, because this is a mistake humans or LLM's never make. We will see.

        • aw1621107 14 hours ago

          > Given the type declarations it's "obvious" it should not compile as it directly contradicts the types 'static lifetime. You don't deliberately write code that doesn't compile.

          You don't need 'static to trigger the bug [0]

          [0]: https://github.com/rust-lang/rust/issues/164250#issuecomment...

          • rstuart4133 41 minutes ago

            True, but I would have been surprised if that wasn't the case. The reason line looked wrong to me is the lifetime of Some(l) was shorter than the type declaration wanted. The simplest explanation for the bug is compiler wasn't checking the lifetime at all, and the link you provided seems to confirm that is the case.

            If that's true it's not a very complex or subtle bug. The very first response of "How on earth was this not found before this???" seems entirely appropriate to me.

randyrand 1 day ago

I just wish Rust handled out of memory more gracefully like a normal error.

  • bluGill 1 day ago

    Why bother? Most systems these days have over commit and so you can never get an out of memory error. The OS will happily give you more and more RAM, and then when you try to use that memory kill a program (may or not be your program). The only out of memory error you can see is if you are trying to allocate more memory than the address space allows. This is so unlikely that nobody considers it worth bother to try to handle.

    • JoshTriplett 1 day ago

      It is important to try, for a few reasons. Among other things, increasing amounts of Rust written in the Linux kernel itself, and other environments where you need to take more care with memory allocation.

      Rust as a language is capable of that. If you don't use the standard library then you can provide that functionality yourself. The standard library is trying to support it, without creating interfaces that are a massive pain to use.

      For instance, it's easy for us to support `Vec::try_reserve`, and we do, but that's not trivial for users to use everywhere; it's error-prone, and it's easy to make a mistake and call a method that goes past your reservation. It's painful for us and for users to make `Vec::push` support this (and having a `try_` variant for every function), so we've been working on a better solution. One current possibility is to have a dedicated type for a Vec that has OOM handling, where `push` can return an error, so you know if you use that type you can never accidentally fail to handle OOM.

    • IshKebab 1 day ago

      > Most systems these days have over commit

      Sure if you ignore the most popular desktop OS in the world.

      Also overcommit (at least how Linux does it) is dumb. It leads to broken OOM behaviour (killing a totally random process, or more often locking up the system and hard rebooting). And some apps do need to handle OOM properly, e.g. formal verification systems which can use enormous amounts of memory. Jasper has to resort to monitoring page fault stats to know when it is using too much memory.

      • adgjlsfhk1 18 hours ago

        > It leads to broken OOM behaviour

        no it doesn't. the broken oom behavior is distros not configuring earlyoom/systemd-oom properly. The problem here is that the kernel doesn't know what software is critical to your OS so the distro needs to be responsible for what processes to protect.

        For apps that need to handle oom, Linux is missing something a handle to tell apps to shrink their memory use. Apple does this and it seems to work quite well (and proves that Linux style overcommit works well since it's what they use)

    • randyrand 1 hour ago

      For micros and other embedded spaces.

  • yencabulator 23 hours ago

    On a typical Linux box, overcommit and eager or confused OOM killer will ruin your day anyway.

    For no_std style work where running out of memory is actually a hard limit, you have two choices:

    1. disable the global allocator and use APIs that take Allocator, to force yourself to only consume APIs that can return errors from allocation. (The ergonomics aren't always great, and fattening all types with a pointer to Allocator isn't great; might be able to use a zero-sized Allocator, with trickery. Say goodbye to many libraries.)

    2. use static analysis and try to avoid ever hitting a code path like Vec::with_capacity that doesn't return a Result. Make sure the tooling also analyses your dependencies. (Tooling for the static analysis is painful. And still, say goodbye to many libraries.)

    I do wish there were more conveniences for alloc-can-fail APIs, like the failable version of Vec::push needs both try_reserve and push_within_capacity (nightly only).

  • uzerfcwn 21 hours ago

    As much as I would love this on principle, I don't think Rust can make it ergonomic without huge changes like bolting on algebraic effects or something.

wat10000 1 day ago

The emotional reactions to this stuff are so weird. Yeah, software has bugs, what a surprise. That doesn't mean that static safety is useless or that we should all just continue YOLOing stuff in C.

ashkankiani 21 hours ago

This makes me feel better about my programming language I'm building. No amount of eyes can solve every problem.

I'm using sqlite's testing principles that Dr Hipp explains (MC/DC, mutation testing, fuzzy checking, property testing) and even some loose lean proofs written by LLMs, but in the end, it's all just kayfabe. I'll find out some bug one day anyway.

  • higeorge13 12 hours ago

    Could you share any reading material for this?

FuzzywarmWalnut 1 day ago

Worked on a variance-related lint once and the scary part is how rarely anyone writes down variance by hand, so bugs there just sit untested for a decade.

  • afdbcreid 1 day ago

    Nobody writes variance at hand in Rust because it's impossible (since before 1.0). You sometimes need to enforce stricter variance than the default (can cause unsoundness and is very subtle but actual unsoundness here is rare) or give more permissive variance (harder and also cannot cause unsoundness, just annoyance).

    When implementing the type system, however, variance does have to be treated with care. Historically it wasn't much, now it is.

gosen 1 day ago

I'm sure we'll get more of those on other languages / frameworks too. I tend to believe that it's for good

MrBuddyCasino 1 day ago

The heart of the matter:

  struct Q<T: 'static>(Option<T>);

  impl<T: 'static> Drop for Q<T> {
    fn drop(&mut self) {
        // Code in here has access to a non-'static &String
        // but assumes that it's a &'static String
    }
  }

  fn main() {
    let l = String::new();
    let mut q = Q(None);
    q.0 = Some(&l);
  }

I wonder if the certified compiler for safety critical uses (edit: Ferrocene) has the same issue.

  • wg0 1 day ago

    DeepSeek v4.1 Flash thinks it should NOT compile. Whereas in reality it DOES compile which is why it is filed as a bug.

    • jug 1 day ago

      They're seriously using AI as a judge for what to file?

      • afdbcreid 1 day ago

        The issue and none of the comments mention AI. It is pretty clear your parent said it by themselves.

      • wg0 1 day ago

        I was just checking what outcome an LLM would have based on the patterns in its probabilistic distribution it has seen the wild.

        Most LLMs would probably say this piece of code won't compile.

        • ChickeNES 1 day ago

          chatgpt and grok linked to the the soundness issue, claude I am in usage timeout, and gemini shit the bed as usual: "The compiler rejects the program with error[E0597] on the assignment q.0 = Some(&l)"

  • afdbcreid 1 day ago

    > I wonder if the certified compiler for safety critical uses has the same issue.

    It uses the same code, so yes.

    (Although I don't know what are their guidelines, it might be that they require avoiding code relying on implied bounds, for example).

  • 1718627440 1 day ago

    Can someone ELI5 for people who don't know Rust (but e.g. C)?

    • thinkharderdev 1 day ago

      Rust is supposed to guarantee statically that a reference cannot outlive its referent. The `T: 'static` bound means that the value that Q holds must have a 'static lifetime (e.g. either be an owned value or a reference to a static value). So this program should not compile since a reference to l is not 'static. This code is unsound because rust will drop the string l before q so when the Q destructor runs the underlying string has already been freed yet we have a valid reference to it.

      • 1718627440 1 day ago

        What does "q.0" and "Some(...)" mean?

        • bonzini 1 day ago

          "Some(...)" means that this Option<T> does have a value of type T in it; "None" means it doesn't.

          "q.0" is not really needed, it's a struct with unnamed fields. Here is the same with named fields:

            struct Q<T: 'static> { pub x: Option<T> }
            ...
            let l = String::new();
            let mut q = Q { x: None };
            q.x = Some(&l);
        • cowlevel 1 day ago

          Some(...) is just constructor for an option type as seen in other languages e.g. java's Optional, haskell's Maybe, c++'s std::optional. I assume that it's needed here because the field can't start as a null pointer otherwise. Maybe the vulnerability still works if the field starts with one string value and swaps to a different string value, but having it start holding None made for a simpler demo.

          q.0 is the first field of q, which is anonymous. They could have just as well called it x and written q.x.

        • thinkharderdev 1 day ago

          So Q is a "tuple-struct". In rust you can define a struct like

          struct Q<T> { value: Option<T> }

          with a named field or you can define it like

          struct<T> Q(Some<T>)

          which is the same struct layout but without an explicit name for the value. In that case, the field is implicitly names `0`

          So q.0 = Some(foo) is equivalent to q.value = Some(foo).

          The Some(..) is just one variant of the Option enum:

          enum Option<T> { None, Some(T) }

          Option represents a value that may or may not be initialized. For uninitialized values you use the None variant and then you can initialize it to Some(value).

          The C rough equivalent would be

          struct Q { void* value; }

          struct Q q = q { NULL }; q->value = ...

      • 1718627440 1 day ago

        So the equivalent in C would be:

                $ cat main.c
                #include <stdlib.h>
                #include <string.h>
        
                struct Q {
                        /*@null@*/ /*@only@*/ char * t;
                };
        
        
                /*@only@*/
                struct Q *
                Q_new (/*@only@*/ char * t)
                {
                        struct Q * q = malloc (sizeof *q);
                        q->t = t;
                        return q;
                }
        
                void
                Q_set (struct Q * q, /*@only@*/ char * t)
                {
                        free (q->t);
                        q->t = t;
                        return;
                }
        
                void
                Q_free (/*@only@*/ struct Q * q)
                {
                        free (q->t);
                        free (q);
                        return;
                }
        
        
        
                int
                main (void)
                {
                        /*@only@*/ char * l;
                        /*@only@*/ struct Q * q;
        
                        l = strdup ("");
                        q = Q_new (NULL);
        
                        Q_set (q, l);
                        free (l);
        
                        /* This is UB */
                        Q_free (q);
        
                        return EXIT_SUCCESS;
                }
        
                $ splint main.c
                Splint 3.1.2 --- 21 Feb 2021
        
                main.c: (in function Q_new)
                main.c:15:3: Arrow access from possibly null pointer q: q->t
                  A possibly null pointer is dereferenced.  Value is either the result of a
                  function which may return null (in which case, code should check it is not
                  null), or a global, parameter or structure field declared with the null
                  qualifier. (Use -nullderef to inhibit warning)
                   main.c:14:17: Storage q may become null
                main.c: (in function main)
                main.c:43:6: Unrecognized identifier: strdup
                  Identifier used in code has not been declared. (Use -unrecog to inhibit
                  warning)
                main.c:44:13: Null storage passed as non-null param: Q_new (NULL)
                  A possibly null pointer is passed as a parameter corresponding to a formal
                  parameter with no /*@null@*/ annotation.  If NULL may be used for this
                  parameter, add a /*@null@*/ annotation to the function parameter declaration.
                  (Use -nullpass to inhibit warning)
                main.c:47:8: Dead storage l passed as out parameter to free: l
                  Memory is used after it has been released (either by passing as an only param
                  or assigning to an only global). (Use -usereleased to inhibit warning)
                   main.c:46:12: Storage l released
                main.c:12:1: Function exported but not used outside main: Q_new
                  A declaration is exported, but not used outside this module. Declaration can
                  use static qualifier. (Use -exportlocal to inhibit warning)
                   main.c:17:1: Definition of Q_new
                main.c:20:1: Function exported but not used outside main: Q_set
                   main.c:25:1: Definition of Q_set
                main.c:28:1: Function exported but not used outside main: Q_free
                   main.c:33:1: Definition of Q_free
        
                Finished checking --- 7 code warnings
        

        (The equivalent warning is main.c:47)

        • NobodyNada 1 day ago

          If you wrote a Q_free function and called it after `free(l);` to actually demonstrate the UAF, that would be pretty close to the semantics of the Rust example.

          • 1718627440 1 day ago

            I have added that now.

            I originally didn't do this, because I didn't feel the need to invoke UB without necessity. Also I wanted to demonstrate, that the error can (and is) caught in C, without actually committing the double-free (so that the program behaviour is still well-defined, but the abstraction is already violated).

            • NobodyNada 1 day ago

              I'm not familiar with Splint, but my understanding is that the error is because of the @only@ marker indicating that the string is not shared. That's an incorrect translation of the Rust program, where the reference to the string is explicitly a shared reference rather than an owned reference. The issue isn't the sharing; it's that rustc mistakenly allows the code to assign a reference that is valid until the end of the current scope to a field that expects a reference valid forever (like a string constant in the program binary). The Rust program with equivalent semantics to your C program (passing an owned String instead of a shared reference) is correctly rejected by the compiler.

              Also, the Q_free function should not free q->t. It may access it (e.g. printing it), but it does not own that reference and is not responsible for deallocating its memory.

              Sorry, I should have looked closer the first time! My excuse is that it was too early in the morning to be thinking about such things.

              • 1718627440 1 day ago

                Yes, @only@ means that the parameter/variable is owning. I believed that would have been the meaning in Rust. Now I can no longer edit my comment, oh well.

                > Also, the Q_free function should not free q->t.

                Well, that's because I thought it would own it. But if in Rust it is not implied that the Q owns the string, then I fail to see where the error is? Both l and q will be deallocated at the end of the main function. Depending on the order of the deallocation maybe q exists for a theoretical time while pointing to already deallocated memory. But both get deallocated at the same point, so q does not outlive the existence of l, so where is the error?

                • NobodyNada 1 day ago

                  The error is the destructor of `q` could look at the reference and stash it away somewhere, like a global variable (since the compiler thinks the reference is valid forever). Then, some other part of the program could access that variable and cause a UAF.

      • biorach 1 day ago

        > rust will drop the string l before q

        Why?

        • 1718627440 1 day ago

          My thoughts as well. The problem can be alleviated either by making the ownership change an error or "just" invoking the destructors in the correct order.

          But I think https://news.ycombinator.com/item?id=50072252 answers it:

              A 'static lifetime constraint on T says: types that satisfy T must not contain any borrowed value/content whose lifetime will be shorter than the life of the program. 
          

          So the compiler assumes it is guaranteed, that 'l' still exists, so it doesn't consider it in regard of finalizer ordering.

        • NobodyNada 1 day ago

          That's incorrect; the compiler drops q before l. Drops happen in LIFO order; and the compiler knows that it can't drop l before q has been dropped, because q contains a reference to l.

          The issue is that the destructor of q can observe a reference which is about to be deallocated as having a 'static lifetime (i.e. it will live forever), and can thus stash it away somewhere for other code to access after it's been freed (as in the examples in the issue which demonstrate UB.)

    • efficax 1 day ago

      'static lifetime bounds are kind of confusing in Rust, but here goes: A 'static lifetime constraint on T says: types that satisfy T must not contain any borrowed value/content whose lifetime will be shorter than the life of the program. So suppose you have a string s, and Option<&String> q. If q has the constraint 'static, and you do q = Some(&s) this should be rejected by the compiler since a reference to s gets a shorter lifetime than 'static by default (you could do q = Some(&'static s) if s is say a string literal or a leaked box but not for a normal string). In the examples it looks like you have to use a tuple to trick the borrow checker but the concept is the same: Rust allowed violation of the 'static lifetime bounds. The drop implemenation demonstrates it: drop happens in reverse declaration order, so the string s gets dropped first. Now q has a dangling reference, a pointer to dropped memory essentially, and we get a pretty classic use after free bug.

badatnames 1 day ago

There is a collection of these someplace. Rust is better but it'll never be perfect, news at 10

  • zer00eyz 1 day ago

    Rust is good, I generally do not dislike it - but it does have flaws.

    I will happily continue to write things in Golang first. I don't enjoy refactors in Rust, and it's rare that I see things that genuinely need its raw performance.

    Cloudflare's Oxy is a stellar example of build in Golang till your design is settled and then port over for performance when you need it.

vincent-uden 1 day ago

What the hell. This is not the esoteric, crazy, impractical constellation I expected to find with a title like this. The minimal example is so simple and is definitely something you'd easily come across in normal code.

  • LoganDark 1 day ago

    I wonder if the reason it works is because you'd easily come across it in normal code, and someone didn't realize that saving the effort of implementing a check for this would result in unsoundness.

    • afdbcreid 1 day ago

      That's not how it works. rustc doesn't "check" for specific cases explicitly, the borrow checker (apparently at fault here by reports) has a set of rules that should reject invalid programs. So either one of the fundamental rules was broken (unlikely here from what I've heard), or some optimization caused the rules to not be implemented correctly.

      • LoganDark 23 hours ago

        I know the borrow checker uses rules, but I don't know enough about the internal implementation details to use fully precise terminology. I don't mean borrow checking is just a chain of if-statements or something. I meant check in the abstract.

        From the GitHub thread: "I think unification just generally doesn't check lifetime bounds of the type." [0]

        There are steps, or rules or whatever, that perform soundness (or well-formedness or whatever) checks. And clearly one was missing.

        My guess was just that maybe someone didn't think it was necessary for soundness.

        [0]: https://github.com/rust-lang/rust/issues/164250#issuecomment...

  • jvanderbot 1 day ago

    Not really. I've worked with rust for 4 years, systems side, and never had to write a custom drop implementation. That's the gotcha here, not the rigamarole with the static+Send option type (which _would_ be something you'd encounter in prod).

    • bryanlarsen 1 day ago

      I've written dozens of custom Drop implementations. Well, many of them are named cleanup because of the async Drop mess in Rust, but...

      • dwattttt 1 day ago

        How many of them only conditionally implement Drop, based on a generic param lifetime?

        • Xirdus 1 day ago

          Why would you ever conditionally custom impl Drop? I don't think I've ever seen that pattern, and I can't think of a use case.

          • jason_oster 1 day ago

            Therefore explaining why the bug hadn't been hit in practice for 11 years.

            • Xirdus 1 day ago

              The bug in the OP is about UNconditional impl. And honestly, looks like very standard code, definitely something that could've been written for real. I can't even explain why it passes checks, it clearly shouldn't.

              • dwattttt 23 hours ago

                This code, from the bug submission?

                  impl<T: 'static + Send> Drop for Q<T> {
                      fn drop(&mut self) { if let Some(t) = self.0.take() { KEPT.lock().unwrap().push(Box::new(t)); } }
                  }
                

                The bound on T in the Drop impl means Drop is not implemented for all T, only where T: 'static + Send. Q<T> also having the same bound doesn't make a difference to the Drop impl.

                • NobodyNada 22 hours ago

                  You cannot write a type which conditionally implements Drop: https://play.rust-lang.org/?version=stable&mode=debug&editio...

                      struct Q<T>(Option<T>);
                  
                      impl<T: 'static> Drop for Q<T> {
                          fn drop(&mut self) {}
                      }
                  
                  
                      error[E0367]: `Drop` impl requires `T: 'static` but the struct it is implemented for does not
                       --> src/main.rs:3:9
                        |
                      3 | impl<T: 'static> Drop for Q<T> {
                        |         ^^^^^^^
                        |
                      note: the implementor must specify the same requirement
                       --> src/main.rs:1:1
                        |
                      1 | struct Q<T>(Option<T>);
                        | ^^^^^^^^^^^
                  • dwattttt 22 hours ago

                    Even if the bounds are the same on the struct and the impl, it's still true that placing bounds on the Drop impl means it's not implemented for all T (just all T that also satisfy Q).

                    You also don't have to place those bounds on the Drop impl just because they're on Q, that's not an error.

                    • Xirdus 19 hours ago

                      The Drop isn't implemented for T at all. It's only implemented for Q<T>. And it's implemented for all Q<T>, in the sense that for every value of type Q<T>, this Drop impl applies.

                      And I'm still not any closer to understanding what the bug is about.

                      • dwattttt 15 hours ago

                        Sorry, yes. I mean that Drop isn't implemented for all Q<T>, just all Q<T> where T meet the bounds of legally constructing Q. I note the difference because you can write a Drop impl with no bounds on T, and I believe it would not be able to trigger the bug.

                        • Xirdus 6 hours ago

                          This is so stupid. One, why did they make Drop special in this one way when every other trait impl has to repeat all bounds exactly to be valid? Two, the bug isn't even in the Drop impl, it's in the assignment on line 11. q.0 can never be Some(&l) because &l is not 'static. The Drop impl is there just to show the invalid read, but the bug doesn't require it, it's just as wrong for types that don't impl Drop.

                          • dwattttt 5 hours ago

                            They didn't special case this (in this way at least). You only need to specify the bounds relevant to this impl at this point.

                            It doesn't even have to be less constrained than the containing types definition. You can provide an impl with more constraints; for example, a type Q<T: Read + Write>, but impl Seek for Q<T: Read + Seek>

                            • Xirdus 1 hour ago

                              I thought only as constrained and more constrained is allowed, and less constrained is always an error. At least that's been my experience - if `Q<T: A>`, then I could never get `impl<T> Q<T>` working in any conditions until I added `where T: A`.

                              Do you happen to know the specific rules of when it's an error and when it's not?

            • Xirdus 6 hours ago

              On further reading, the Drop impl is a red herring. The bug is unrelated to Drop. It's there in the repro to show the effects of invalid assignment, but even without impl Drop the bug is still there.

      • jvanderbot 1 day ago

        OK. That's good to know. I'm not sure why sharing our professional experience with this type of code is controversial, but here we are.

    • neysofu 1 day ago

      That's easily the exception rather than the rule. I've seen custom `Drop` implementations in almost every non-trivial Rust codebase I worked on.

    • gspr 1 day ago

      A custom `Drop` appears very quickly with FFI code. Suppose for example you interface with some C library that expects you to call a function to release some resources.

    • rvz 1 day ago

      Now we are at the phase where, Rust is “safe” but only if you use it “correctly” and without using X language feature or a custom Y feature.

      This is the problem when a language advertises with “guarantees” and it turns out it never had any due to many false assumptions by their promoters.

      So what other soundness bugs are there in the language that we need to know about?

      • jvanderbot 1 day ago

        I'm not defending rust here - a correctness bug invalidates the premise. But I am saying that I've never seen a custom drop in production.

        For some reason this is controversial, but it remains true.

        • cmrdporcupine 1 day ago

          Custom drops are all over the place. As others have said.

          But not custom drops that are doing variadic type stuff like this, usually.

        • bryanlarsen 1 day ago

          You said/implied 2 things:

          - you've never written a custom Drop

          - "Not really". Implying that your experience generalizes

          I've written a bunch of rust programs without custom Drop. I believe your first statement. There are large classes of programs that don't need it. There are also many that do. I think your statement says a lot more about what kind of programs you work on than about custom Drop not being common. People are downvoting the implication that custom Drop is not a common pattern.

      • cmrdporcupine 1 day ago

        No we're in a situation where a bug in the type checker was found and will be fixed and a new release will be made.

        That it took 11 years for someone to come across this is a fairly intense counterargument to your attempt to paint this as a language with dangerous footguns.

  • insanitybit 1 day ago

    For a long time `loop {}` was undefined behavior. Lots of l-unsounds are really nuts but a few are not.

    The reality is that if this were actually code that people wrote, well, it wouldn't have sat around for a decade.

  • fg137 1 day ago

    > is definitely something you'd easily come across in normal code.

    The fact that nobody reported this before means it's not, by definition.

    • vincent-uden 1 day ago

      Not at all. There are way more valid lifetimes than the lifetime system of Rust can express. There are countless scenarios where you could accidentally use the unsound behaviour while not producing a segmentation fault because the lifetimes happens to be arranged such that no invalid memory access actually happened.

      A program isn't invalid just because it violates the ownership and borrowing rules of Rust. There are tons of programs in the world with shared, mutable access, devoid of Mutexes, Arcs and Locks that nonetheless are completely valid.

      • fg137 1 day ago

        I think you are talking about a different problem and that has nothing to do with my comment.

        • foldr 1 day ago

          Simplified, the point is that a lot of badly typed code that this bug lets through might be mostly harmless (or even fully semantically correct, in some instances). So you can't conclude that 'normal' code wouldn't trigger this bug just because no-one's noticed it until now. The bad code could could be happily executing and performing as expected.

asdfman123 23 hours ago

Beg, Borrow, or Steal: a guide to Rust object ownership

Hugsbox 1 day ago

I don't understand how something like this could take so long to be discovered. Pretty crazy stuff.

  • lelanthran 1 day ago

    > I don't understand how something like this could take so long to be discovered.

    Maybe they wrote it in C :-)

    On a serious note, old software is generally more trustworthy than new software, because bugs are discovered over time and with usage.

    • zaphar 1 day ago

      Old C software is generally more trustworthy than new C software. I don't think this rule of thumb transfers across languages very well. And the definition of new vs old has a fairly large effect. If a language has been under constant change it doesn't matter when it was started a large part of the codebase is "new".

    • dabinat 1 day ago

      > On a serious note, old software is generally more trustworthy than new software, because bugs are discovered over time and with usage.

      The age of software means bugs are more likely to be discovered but not necessarily fixed. In the case of Rust, the developers have documented a whole lot of unsoundness bugs that require a new borrow checker architecture to fix.

  • fg137 1 day ago

    Because it's rarely used like this, just like weird bugs caused by edge cases found in all kinds of software in the world.

JABVOLT 1 day ago

very very good job

fnord77 1 day ago

Here's the weakness of compiled programs. Does this compiled code have this vulnerability? You have no idea. At least with a VM or interpreter you can scan for vulnerable versions and replace the runtime or the specific library.

With this you have to recompile everything

  • baq 1 day ago

    That is less and less true by the day, for better or worse.

  • cowlevel 1 day ago

    It's possible to scan compiled programs at the assembly or machine code level. Not enough people do, which is fair enough because it's a slog, but it makes all compiler UB transparent to the analysis.

rurban 1 day ago

And a fork fixed it before upstream rust :)

  • Groxx 1 day ago

    ...yes? that's usually the case in open source software.

sreekanth850 1 day ago

Was this done by LLM? this is a doubt. because recently we are seeing many such bug reports.

cheney_2004 1 day ago

I think one social issue I’m seeing is that the Rust community bashes other languages for safety but then glosses over or even completely ignores their own safety risks (see supply chain). I would rather see Rust focus on its actual features without bashing others and maybe start moving away from claiming the gold metal on security. Being less toxic is always a good thing for long term health.

  • gchamonlive 1 day ago

    It's important to separate the community ethos and the rust core dev team policies, because I'd be surprised if the official stance of the rust team would be condescending to other technologies.

    • SV_BubbleTime 1 day ago

      Have you met humans?

      I’d be shocked if people working on and passionate about thing didn’t shit on other thing. That’s natural and even good in moderation. It’s up to a leader to keep it under control.

      • mcherm 1 day ago

        Yes. In fact, I have met quite a few humans who make a point NOT to go bashing the work of others. (Of course, I have also met quite a few who do spend their time bashing others.)

      • tehjoker 1 day ago

        The more you understand about your own system the more humility one would think you would have. This is like the dumb guy to jedi meme. It's the people in the middle that shit on other peoples' work because they have something to gain by looking comparatively smarter.

    • the__alchemist 1 day ago

      Rust is my favorite language in most domains I program in; I've learned to ignore the online rust OSS community due to a mix of preferring heavy abstractions (then shaming your code if you don't use them), and rude behavior.

      This is fine, for the reasons you state: I can use the language and tools while ignoring the jerks.

  • ModernMech 1 day ago

    Can you give an example of this toxic bashing from rust contributors or are you talking about just random HN posters when you say “rust community”?

    Moreover, I wouldn’t say they’re completely ignoring supply chain risks, as there have been discussions about this as early as 2021 [1] and there are ongoing efforts to address this [2]

    [1] https://internals.rust-lang.org/t/about-supply-chain-attacks...

    [2] https://kerkour.com/fixing-rust-supply-chain-security

    • lifeisloving 1 day ago

      Yeah Ive actually never seen any Rust team members be toxic. Keep in mind there is a micro niche of tech influencers who try to politicize rust because they associate it with liberalism or something like that and paint Rust community as an opposing force to some status quo they think exists or should exist. Those notions have taken on a life of their own.

      People who say this just dont know what they're talking about and are repeating youtubers and X takes.

  • zamalek 1 day ago

    > being less toxic

    There's a difference between people you disagree with and toxic behavior. Can you give examples of toxic behavior?

  • slopinthebag 1 day ago

    the only thing more exhausting than rust evangelism is people who drop in on any rust related thread and start whining about unrelated things just because it's rust.