[HN Gopher] Cve-rs: Fast memory vulnerabilities, written in safe...
       ___________________________________________________________________
        
       Cve-rs: Fast memory vulnerabilities, written in safe Rust
        
       Author : npalli
       Score  : 224 points
       Date   : 2024-02-20 13:17 UTC (9 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | WirelessGigabit wrote:
       | It's weird to see lifetime correlations expressed as
       | &'a &'b
       | 
       | and not with                   where 'a: 'b
       | 
       | I suppose I don't understand enough of how the first is different
       | from the second one, and how it impacts this issue.
        
         | dannymi wrote:
         | It's just a reference to a reference. It has nothing to do with
         | lifetime correlations.
         | 
         | Also, it's a lot less weird if you don't stop in the middle of
         | the type. The entire type is for example                   &'a
         | &'b u8
         | 
         | or                   &'a &'b ()
         | 
         | So the outer reference has lifetime 'a and the inner reference
         | has lifetime 'b.
        
           | Georgelemental wrote:
           | > It has nothing to do with lifetime correlations
           | 
           | Yes it does; there's an implied `'b: 'a` outlives
           | relationship that's required for the type to be well-formed.
        
         | kbknapp wrote:
         | In fact, I believe that's exactly where this bug lies. You're
         | effectively able to trigger a case in which passing `&'a &'b`
         | _without_ providing any correlation (`where  'a: 'b`) that one
         | would normally be required to provide makes the compiler behave
         | as if those correlations were passed, albeit inferred
         | incorrectly.
        
         | LegionMammal978 wrote:
         | The first one creates an _implied bound_ , while the second is
         | an explicit bound. The important thing about implied bounds is
         | that they allow _late binding_ of lifetimes to function
         | pointers (or closures): that is, you can have a single function
         | pointer type like  "for<'a> fn(&'a str)" that can be called
         | with any lifetime 'a. Here, the lifetime 'a is called "late-
         | bound", since it can be different with each call.
         | 
         | In contrast, if a lifetime is subject to an explicit where
         | bound, it must be "early-bound": each function pointer can must
         | choose one particular value for that lifetime, that must be
         | upheld for every call. For a practical example, you might have
         | tried to declare a closure with a &T parameter, only to get
         | lifetime errors when you call it twice. This is because the
         | lifetime in the closure type is early-bound and must be the
         | same for every call. (Sometimes the compiler figures out that a
         | late-bound lifetime is desired, but the rules are very subtle.
         | This is also why it's difficult to write a function that
         | accepts a generic async closure.)
         | 
         | Late binding is necessary for certain kinds of _variance_ ,
         | which is a big part of this issue. Function pointers are
         | contravariant in their parameters, which means if you have a
         | type like "fn(&'short str)", you can cast it to "fn(&'static
         | str)", since a 'static reference will always be valid for
         | 'short. They're also covariant in their return type, so that
         | "fn() -> &'static str" can be cast into "fn() -> &'short str".
         | But when performing these variance transformations with late-
         | bound lifetimes, the compiler doesn't always take into account
         | the implied bounds in the source type properly, which allows
         | you to perform casts that aren't actually sound.
        
         | WirelessGigabit wrote:
         | Edit (since I cannot edit my comment after 2 hours): for the
         | code to properly verify the lifetimes one needs to write
         | where 'b: 'a
         | 
         | meaning 'b is at least as useful as 'a. So 'b can live the same
         | time, or longer, but not less.
        
       | robinsonrc wrote:
       | It's good to see that at least Miri catches the issues. Hopefully
       | the compiler can catch up with that!
        
         | vlovich123 wrote:
         | Does polonius catch the issue?
        
         | throwawaymaths wrote:
         | If you need a compiler sidecar anyways, why not just have a
         | simpler language where all the borrow checking is done in a
         | sidecar?
        
           | dralley wrote:
           | You don't "need" a compiler sidecar unless you're
           | specifically writing code to exploit obscure bugs. This is a
           | 0.0001% case
        
             | throwawaymaths wrote:
             | yeah or if you're using someone else's code that you're
             | trusting doesn't have "obscure bugs" put there to smuggle
             | in a vuln.
        
               | dralley wrote:
               | Nonetheless, it's far less of an issue than in any other
               | language. You don't need 20 lines of crazy code to slip a
               | serious security vulnerability into C, you can add one
               | with a single character changed half of the time.
        
               | pcwalton wrote:
               | This is exaggerated re. C, but it is true that the
               | important thing for practical security is whether memory
               | safety is violated in practice, and obscure compiler bugs
               | you have to go out of your way to try to exploit don't
               | affect that. _That being said_ , this bug is pretty bad,
               | and it should be fixed.
               | 
               | I should point out that the reason the bug is difficult
               | seems to mainly be because of backwards compatibility
               | concerns. If compatibility weren't an issue, Rust could
               | just ban function contravariance and nobody would care.
        
               | muldvarp wrote:
               | If you run somebody else's code and you don't trust that
               | person, you need to read their code carefully anyway.
               | Safe Rust code can do all kinds of shenanigans including:
               | 
               | * Wiping your disk
               | 
               | * Downloading and running code from the internet
               | 
               | * ...
               | 
               | Rust's safety guarantees don't exist to protect you from
               | a malicious Rust programmer. They exist to protect you
               | from mistakes a well meaning but fallible Rust programmer
               | can make.
        
               | throwawaymaths wrote:
               | > Rust's safety guarantees don't exist to protect you
               | from a malicious Rust programmer.
               | 
               | This greatly ignores human behavior. A LOT of people who
               | are reviewing rust code are going to only concentrate on
               | unsafe blocks (that's if you're lucky), because rust is
               | advertised as "rust gives you safety", and the word
               | "safety" strongly suggests "don't worry about these
               | things, they are safe". if the advertised safety is a
               | false sense of safety that's a problem.
        
               | muldvarp wrote:
               | Do you have any data backing that argument? I could just
               | as well make the argument that Rust has an extensive
               | "correctness above all else" culture that encourages
               | people to thoroughly review pull requests. Without data
               | both of these claims are just that: claims.
        
               | knose wrote:
               | these people you're talking about would make the same
               | mistake with code written in any language.
        
           | steveklabnik wrote:
           | Miri is fantastic, but also isn't a "compiler sidecar,"
           | exactly. It is an interpreter. It's closer to a sanitizer
           | than a compile-time check. It also means a huge, huge
           | overhead to running your code, and in a performance-sensitive
           | language that's a tough sell.
           | 
           | It's also only needed for when you dip into unsafe, which is
           | not particularly often, and so imposing this on all code
           | would be the wrong tradeoff.
        
             | vlovich123 wrote:
             | Well libstd has unsafe all over the place. And as OP points
             | out it catches this unsoundness issue in the language even
             | though there's no unsafe anywhere, so it goes beyond just
             | "dip into unsafe".
        
               | steveklabnik wrote:
               | Sure, but the unsafe in libstd is some of the most tested
               | unsafe in existence. And sure, there are some soundness
               | bugs, but in my experience they are edge cases that
               | rarely come up. I don't think I have personally ever run
               | into one in the wild.
               | 
               | Regardless, it is not feasible for you to run your code
               | under miri all the time, so you have to pick and choose
               | where you use it, as a practical matter.
        
               | vlovich123 wrote:
               | Yup, just highlighting that it goes beyond more than just
               | runtime checking for safeness of unsafe code only :)
        
       | dralley wrote:
       | Seems to rely on at least one known compiler bug (admittedly one
       | open since 2015) https://github.com/rust-lang/rust/issues/25860
        
         | dgfitz wrote:
         | Looking at the syntax in that bug report makes me think I could
         | never learn rust.
        
           | faitswulff wrote:
           | You could also think of it as "look at all the weird syntax
           | olympics you need to do in order to trigger a compiler edge
           | case!"
        
           | the_mitsuhiko wrote:
           | That is not syntax you would ever see.
        
             | wredue wrote:
             | I wrote pretty basic rust stuff and had to use lifetime
             | syntax quite a bit. If you are just forcing deep copies all
             | the time, you might not see it often, but if you're just
             | going to deep copy everything always, you're probably going
             | to be better off with another language to be honest as
             | you're tossing away much of the benefit of using a language
             | like rust anyway.
        
               | pkolaczk wrote:
               | I rarely use lifetimes and I don't deeply copy
               | everything. This tool is probably the fastest in its
               | class - does this code look like having a lot of
               | lifetimes, cryptic syntax or deep copying?
               | 
               | - https://github.com/pkolaczk/latte/blob/main/src/main.rs
               | 
               | - https://github.com/pkolaczk/latte/blob/main/src/exec.rs
               | 
               | There was one fundamental "aha" moment for me when it
               | clicked: move semantics. Once I learned it, suddenly 99%
               | of stuff became simple (including making async quite nice
               | really, contrary to popular HN beliefs).
        
               | wredue wrote:
               | You can cherry pick all you want, although I would
               | generally agree that "top level" executables will most
               | likely bump against lifetimes far less frequently than
               | libraries, frameworks, modules etc.
               | 
               | I would also generally agree that a single pass through
               | the official book should mostly be enough to be able to
               | read and understand the op.
        
               | pkolaczk wrote:
               | Therefore I cited the core of the program as well. It
               | also does a bunch of non trivial async processing there.
               | 
               | I've written at least two other non-toy Rust programs and
               | I haven't hit "lifetimes everywhere" problem there
               | either. I guess the most lifetime related problems stem
               | from trying to program the Java/Python/JS style in Rust -
               | from overusing references and indirection. If you model
               | your program as a graph of objects referencing each other
               | then I can imagine you have a hard time in Rust.
        
               | datadeft wrote:
               | I use a lot of deep copy in my every day Rust and the
               | performance is still 10x of my Python that I started to
               | use in 2009.
        
           | mattigames wrote:
           | That's like saying you could never learn JS beacuse the
           | following valid JS snippet, when in real life you would never
           | see such thing unless someone its trying to obfuscate the
           | code:                   [,{a,'z':q|0}[`${a?.x??b}`]]
        
           | FpUser wrote:
           | They've just written terse code with lots of single character
           | identifiers. Not the style on would / should use for real
           | life development of readable code.
        
           | secondcoming wrote:
           | Once you conquer the headaches and eye-strain, it's not too
           | bad.
        
           | wredue wrote:
           | One of my criticisms of Rust is that it's a very RSI causing
           | language. Very heavy on reaching awkward keys.
           | 
           | I mean, a read through the guide makes this very readable,
           | but it doesn't change that it looks like symbol soup and have
           | lots of awkward repetitive strain to type it out.
        
             | tuetuopay wrote:
             | This is one I surprisingly very few complaints about the
             | symbols used. My personal pet peeve are languages that use
             | the walrus operator (:=) for variable
             | assignment/declaration. Those two are on the same side of
             | the keyboard, in the same finger column, so really slow and
             | painful to type. If they were two keys for two different
             | fingers, or better yet, for two different hands, that would
             | be awesome (I have the same issue at work for the warsaw
             | region abbreviated to waw). I write Rust daily and have yet
             | to find such an inconvenience.
        
               | CSSer wrote:
               | Odd. I'll give you that it's slow to type, but I can't
               | agree that it's painful. Colon is on the home row under
               | my pinky, and equal is next to the delete/backspace key
               | that I hit all day long.
        
             | alpaca128 wrote:
             | Depends on the keyboard layout you're using. Most languages
             | are more convenient on an English layout than certain
             | others because the syntax was most likely designed by
             | someone using a qwerty keyboard. The symbols /[]'\;= are
             | all accessible without modifier key.
             | 
             | I have a custom layout on my keyboards which makes each
             | symbol reachable without moving my hands, which made it a
             | lot more pleasant.
        
           | oneshtein wrote:
           | `&` is a reference.
           | 
           | `'a` is a label for a memory area, like goto labels in C but
           | for data. You can read it as (memory) pool A. Roughly, when
           | function entered, memory pool is created, then destroyed at
           | exit.
           | 
           | `'static` is special label for static data (embedded
           | constants).
           | 
           | `()` is nothing, like void in C.
           | 
           | `&()` is an reference to nothing (an address) like `void
           | const *` in C.
           | 
           | `&&()` is an reference to reference to nothing, like `void
           | const * const *` in C.
           | 
           | `& 'static & 'static ()` is like void `const * const *` to a
           | built-in data in C.
           | 
           | `& 'a & 'b ()` tells compiler that second reference is stored
           | in pool 'a, while data is stored in pool 'b. (First reference
           | is in scope of current function.)
           | 
           | `_` is a special prefix for variables to instruct compiler to
           | ignore warning about unused variable. Just `_` is a valid
           | variable name too.                 static UNIT: &'static
           | &'static () = &&();            fn foo<'a, 'b, T>(_: &'a &'b
           | (), v: &'b T) -> &'a T { v }
           | 
           | Let's say that `&'a` is from a function `a()`, while `&'b` is
           | from a function `b()`, which called from the function `a()`.
           | 
           | The trick here is that we relabel reference from pool `'b`,
           | from an inner function, to pool `'a` from outer function, so
           | when program will exit from function `b()`, compiler will
           | destroy memory pool `'b`, but will keep reference to data
           | inside until end of the function `a()`.
           | 
           | This should not be allowed.
        
             | brink wrote:
             | I think that's the best description of a lifetime I've seen
             | so far.
        
             | dgfitz wrote:
             | Thank you very much for spending time explaining this. It
             | makes more sense with that kind of description. I'm still
             | not sure how long it would take someone like myself to be
             | comfortable and proficient with the syntax.
             | 
             | I guess stated another way, I don't generally have issues
             | reading code from a wide swath of languages. If someone
             | plopped me in front of a rust codebase I'd be at the mercy
             | of the manual for quite a long time.
             | 
             | Thank you again, sincerely.
        
               | steveklabnik wrote:
               | Rust decided to spend very little budget on syntax. The
               | issue though, is that where it took said syntax from is
               | very wide.
               | 
               | & is used for references in a lot of languages.
               | 
               | () is a tuple, same syntax as Python
               | 
               | 'a isn't even novel: it was taken from OCaml, which uses
               | it for generic types. Lifetimes are generic types in
               | Rust, so even though it's not for an _identical_ thing,
               | it 's related enough to be similar.
               | 
               | _ to ignore a name for something has a long tradition in
               | programming, sometimes purely as a style thing (like
               | _identifier or __identifier), but sometimes supported by
               | the language.
               | 
               | fn name(args) -> {} as function syntax is not SUPER
               | unusual. The overall shape is normal, though the choice
               | between "fn," "fun," "func," or "function" varies between
               | languages. The -> comes from languages like Haskell.
               | 
               | <> for generics is hotly debated, but certainly common
               | among a variety of langauges.
               | 
               | the "static name: type = value;" (with let instead of
               | static too) syntax is becoming increasingly normalized,
               | thanks to how it plays with type inference, but has a
               | long history before Rust.
               | 
               | So this leads to a very interesting thing, where like,
               | it's not so much that Rust's syntax is entirely alien in
               | the context of programming language syntax, but can feel
               | that way unless you've used a lot of things in various
               | places. And that also doesn't necessarily mean that just
               | because it's influenced from many places that this means
               | it is coherent. I think it does pretty good, but also,
               | I'd refine some things if I were making a new language.
        
               | styfle wrote:
               | > I'd refine some things if I were making a new language.
               | 
               | Which parts would you change?
        
               | steveklabnik wrote:
               | About a year ago I wrote this:
               | https://steveklabnik.com/writing/too-many-words-about-
               | rusts-...
               | 
               | I do think there's some good criticism of doing this,
               | though, and so even a year later it's not clear to me
               | it's a pure win.
               | 
               | I am sympathetic to the vague calls to action by Aria et
               | al. to improve the syntax for various unsafe features. I
               | understand why we ended up where we ended up but I think
               | overall it was a mistake. I am not sure I agree with her
               | specific proposals but I do agree with the general thrust
               | of "this was the wrong place to provide syntactic salt."
               | (my words, not hers, to be clear)
               | 
               | Ideally `as` wouldn't be a thing. Same deal, this is just
               | one of those things that's the way it is due to history,
               | but if we're ignoring all that, would be better to just
               | not have it.
               | 
               | I am still undecided in the : vs = debate for structs.
               | 
               | I am sad that anonymous lifetimes in structs died six
               | years ago, I think that would be a massive help.
               | 
               | Probably tons of other small things. Given the context
               | and history, I think the Rust Project did a great job.
               | All of this is very minor.
        
               | lmm wrote:
               | > About a year ago I wrote this:
               | https://steveklabnik.com/writing/too-many-words-about-
               | rusts-...
               | 
               | The = on functions idea is particularly interesting by
               | comparison with Scala, which has shifted towards
               | requiring = over time.
        
               | jcranmer wrote:
               | To be fair, even for someone who is comfortable in Rust,
               | the example is definitely on the rather confusing side of
               | the language. (Not entirely surprising--it's a bug about
               | a soundness hole in the language, which invariably tends
               | to rely on overuse of less commonly used features in the
               | language).
               | 
               | In particular, explicit use of lifetimes tends to be seen
               | as somewhat more of a last resort, although the language
               | requires it more frequently than I like. Furthermore, the
               | soupiest of the syntax requires the use of multiple
               | layers of indirection for references, which itself tends
               | to be a bit of a code smell (just like how in C/C++, T *
               | tends to be somewhat rare).
        
               | mkehrt wrote:
               | I write rust professionally and really like it, but I do
               | think that its noisy syntax is a flaw. I'm not sure how I
               | would clean this up, but it really can be inscrutable
               | sometimes.
        
               | datadeft wrote:
               | For an anecdota it took me roughly a year. I was trying
               | it several times. I still use .clone() a lot but it is
               | getting better. :)
               | 
               | The real question what is the use of Rust for you. Do you
               | work on anything where Rust could be a value?
        
               | viraptor wrote:
               | > If someone plopped me in front of a rust codebase I'd
               | be at the mercy of the manual for quite a long time.
               | 
               | This is not a representative sample of Rust. That's
               | explicitly triggering edge cases which requires abuse of
               | syntax you wouldn't normally see.
               | 
               | Check out this for something more realistic that anyone
               | should understand https://github.com/ratatui-
               | org/ratatui/blob/main/examples/ca...
        
             | dingi wrote:
             | If memory safety needs this level of fuckery to get going,
             | it's not worth it for vast majority of software. Maybe
             | stick to a GCed language until we can come up with a sane
             | way to do it. These examples look cryptic as hell.
        
               | steveklabnik wrote:
               | It's cryptic because it is a reduced test case to show
               | off a bug. 99.9% of code doesn't look like this.
               | 
               | Just because "int ( _(_ foo)(void ))[3]" is a valid C
               | declaration doesn't mean that all of C code looks like
               | that.
        
               | pcwalton wrote:
               | This is basically the Rust equivalent of the obfuscated C
               | code contest and indicates little to nothing about the
               | actual Rust people write.
        
               | datadeft wrote:
               | > this level of fuckery to get going
               | 
               | C++ has the same level of fuckery without memory safety.
               | I don't think there is an extreme level of fuckery in
               | Rust. I wish they got more influence from the ML
               | languages than C++ but it is not unbearable.
        
           | dralley wrote:
           | You should treat this the same as you would something like
           | the Obfuscated C competition. Just because it's supposed to
           | compile and run properly doesn't mean it's good code.
        
             | estebank wrote:
             | You're right, but in this case it _shouldn 't_ compile :)
        
         | GaggiX wrote:
         | I thought it was just using the totally safe transmute, this
         | one:
         | https://blog.yossarian.net/2021/03/16/totally_safe_transmute...
         | 
         | But I guess there is another trick.
        
         | Georgelemental wrote:
         | As noted on that GitHub page, fixing the bug will become
         | possible once rustc adopts a new trait solver:
         | https://blog.rust-lang.org/inside-rust/2023/07/17/trait-syst...
        
           | Maken wrote:
           | Everything is always a new solver away.
        
             | TylerE wrote:
             | a _sufficiently advanced_ new solver. Just like how the
             | lisp guys insisted for decades that a sufficiently advanced
             | compiler would solve all their performance woes. Right up
             | until it became obvious that it couldn 't.
             | 
             | Feels a bit like early chess engines. They tried to create
             | super sophisticated heuristics to determine move quality,
             | but then one person (or more probably multiple people
             | independently more or less simultaneously) realized it's
             | both easier and better to just do more or less the simplest
             | thing that can possibly work, but do it as much as possible
             | in the allotted time.
             | 
             | In other words - don't try to logically decide on the best
             | move with some super advanced set of rules. Just assign a
             | fairly basic and straightforward score based on calculating
             | every reasonble move out 15, 20, 30 moves deep.
        
               | Georgelemental wrote:
               | In the case of the trait solver, there is a clear end
               | goal to reach: "the type system should be sound." This is
               | a yes/no question, which you can prove/disprove
               | mathematically.
               | 
               | (I suppose chess engines also have an end goal of perfect
               | play, but that is a much harder problem)
        
               | dzaima wrote:
               | There's a very simple solver that completes that goal:
               | one that reports that it cannot prove any code as
               | correct. So there must be a secondary goal of "maximize
               | the amount of accepted code", which is a significantly
               | less trivial question.
        
               | TylerE wrote:
               | Yes, exactly.
               | 
               | Saying "just do the thing correctly, duh!" is easy. Ya
               | know the saying about the difference between theory and
               | practice?
        
           | meindnoch wrote:
           | Is it going to be even slower than the current one?
        
             | dralley wrote:
             | Who says the current one is slow?
             | 
             | Just because the compiler as a whole isn't the fastest one
             | around doesn't mean the responsibility falls equally on
             | every constituant part of the compiler.
        
               | estebank wrote:
               | The most obvious slow down people perceive of compile
               | times is due to monomorphization. It is a combinational
               | explosion when instantiating every generic type that is
               | in use, _and_ it exacerbates the issue of rustc producing
               | verbose LLVM IR bytecode.
        
           | nialv7 wrote:
           | Can you quote the relevant part? Because IIUC lifetime checks
           | have nothing to do with the trait solver.
           | 
           | There's a new borrow checker however, but that's not going to
           | fix this either
        
         | nicklecompte wrote:
         | My biggest concern with Rust is the sloppiness around the
         | distinction between a "compiler bug" and a "hole in the type
         | system." This is more of a _specification bug_ even though Rust
         | doesn 't have a formal specification: the problem is the design
         | of the language itself, not that a Rust programmer wrote the
         | wrong thing in the source code:
         | https://counterexamples.org/nearly-universal.html?highlight=...
        
           | ggreg84 wrote:
           | > My biggest concern with Rust is the sloppiness around the
           | distinction between a "compiler bug" and a "hole in the type
           | system."
           | 
           | That bug is marked as I-unsound, which means that it
           | introduces a hole in the type system.
           | 
           | And so are all other similar bugs, i.e., your concern seems
           | to be unfounded, since you can actually click on the
           | I-unsound label, and view all current bugs of this kind (and
           | past closed ones as well!).
        
             | nicklecompte wrote:
             | Perhaps I should have said "hole in the type theory" to
             | clarify what I meant.
             | 
             | To be clear I wasn't trying to imply the rustc maintainers
             | were ignorant of the difference. I meant that Rust
             | programmers seem to treat fundamental design flaws in the
             | language as if they are temporary bugs in the compiler.
             | (e.g. the comment I was responding to) There's a big
             | difference between "this buggy program should not have
             | compiled but somehow rustc missed it" and "this buggy
             | program will compile because the Rust language has a design
             | flaw."
        
               | pcwalton wrote:
               | But it's not a fundamental design flaw in the language,
               | nor is it a "hole in the type theory". It's a compiler
               | bug. The compiler isn't checking function contravariance
               | properly. Miri catches the problem, while rustc doesn't.
        
               | nicklecompte wrote:
               | I believe it really is a flaw in the language, it's
               | impossible for _any_ compiler to check contravariance
               | properly in this edge case. I don 't think anything in
               | this link is incorrect:
               | https://counterexamples.org/nearly-
               | universal.html?highlight=... (and it seems the rustc
               | types team endorses this analysis)
               | 
               | I am not at all familiar with Miri. Does Miri consider a
               | slightly different dialect of Rust where implicit
               | constraints like this become explicit but inferred? Sort
               | of like this proposal from the GH issue:
               | https://github.com/rust-
               | lang/rust/issues/25860#issuecomment-... but the "where"
               | clause is inferred at compile time. If so I wouldn't call
               | that a "fix" so much as a partial mitigation, useful for
               | static analysis but not actually a solution to the
               | problem in rustc. I believe that inference problem is
               | undecidable in general and that rustc would need to do
               | something else.
        
               | anderskaseorg wrote:
               | In the language,                   fn foo<'a, 'b, T>(_:
               | &'a &'b (), v: &'b T) -> &'a T { v }
               | 
               | should be equivalent to                   fn foo<'a, 'b,
               | T>(_: &'a &'b (), v: &'b T) -> &'a T where 'b: 'a { v }
               | 
               | because the type &'a &'b is only well-formed if 'b: 'a.
               | However, in the implementation, only the first form where
               | the constraint is left implicit is subject to the bug:
               | the implicit constraint is incorrectly lost when 'static
               | is substituted for 'b. This is clearly an implementation
               | bug, not a language bug (insofar as there is a
               | distinction at all--ideally there would be a written
               | formal specification that we could point to, but I don't
               | think there's any disagreement in principle about what it
               | should say about this issue).
        
               | comex wrote:
               | You mean that Miri catches it at runtime, right? If so,
               | that hardly demonstrates anything about the difficulty or
               | lack thereof of fixing rustc's type checker, since Miri
               | is not a type checker and doesn't know anything about
               | "lifetimes" in the usual sense.
               | 
               | I agree that this isn't a "fundamental design flaw in the
               | language", but Miri is irrelevant to proving that.
        
               | nialv7 wrote:
               | Why is this distinction important? It's still something
               | you fix by changing what programs the compiler accepts or
               | rejects. Or were you trying to imply this is unfixable?
        
               | chatmasta wrote:
               | The distinction matters because any existing code that
               | breaks with the compiler fix was either relying on
               | "undefined behavior" (in the case of a compiler bug
               | incorrectly implementing the spec), so you can blame the
               | user, or it was relying on "defined behavior" (in the
               | case of a compiler bug correctly implementing a badly
               | designed spec), so you can't blame the user.
               | 
               | I suppose the end result is the same, but it might impact
               | any justification around whether the fix should be a
               | minor security patch or a major version bump and breaking
               | update.
        
               | estebank wrote:
               | Rust's backwards compatibility assurances explicitly
               | mention that breaking changes to fix unsoundness are
               | allowed. In practice the project would be careful to
               | avoid breaking more than strictly necessary for a fix.
               | 
               | In the case of user code that isn't unsound but breaks
               | with the changes to the compiler/language, that would be
               | breaking backwards compatibility, in which case there
               | might be a need to relegate the change to a new edition.
        
               | nialv7 wrote:
               | Well first of all, Rust doesn't even have a spec. And I
               | would also advocate for not blaming anyone, let's just
               | fix this bug ;)
        
               | nicklecompte wrote:
               | Probably better to be maximally pedantic here:
               | 
               | - Assume our language has a specification, even if it's
               | entirely in your head
               | 
               | - a "correct" program is a program that is 100%
               | conformant to the specification
               | 
               | - an "incorrect" program is a program which violates the
               | specification in some way
               | 
               | Let's say we have a compiler that compiles _correct_
               | programs with 100% accuracy, but occasionally compiles
               | _incorrect_ programs instead of erroring out. If the
               | language specification is fine but the compiler
               | implementation has a bug, then fixing the compiler does
               | not affect the compilation behavior of _correct_
               | programs. (Unless of course you introduce a new
               | implementation-level bug.) But if the language
               | specification has a bug, then this does not hold: the
               | specification has to change to fix the bug, and it is
               | likely that at least some formerly correct programs would
               | no longer obey this new specification.
               | 
               | So this is true:
               | 
               | > It's still something you fix by changing what programs
               | the compiler accepts or rejects
               | 
               | But in one case you are only changing what _incorrect_
               | programs the compiler accepts, and in the other you are
               | also changing the _correct_ programs the compiler
               | accepts. It 's much more serious.
        
               | lmm wrote:
               | > Or were you trying to imply this is unfixable?
               | 
               | If it's been known since 2015 and not fixed, that's
               | pretty suggestive.
        
             | layer8 wrote:
             | It's a consequence of not having a formal and formally-
             | proved type system.
        
       | Karellen wrote:
       | > GLWTS(Good Luck With That Shit) Public License
       | 
       | > The author has absolutely no fucking clue what the code in this
       | project does. It might just fucking work or not, there is no
       | third option.
       | 
       | lol
        
         | omoikane wrote:
         | Sounds like an updated version of WTFPL
         | 
         | https://en.wikipedia.org/wiki/WTFPL
        
       | infamouscow wrote:
       | How is an alternative Rust(tm) implementation supposed to
       | approach failures like this. Especially when the organization
       | that controls the name and branding has a death grip on things.
       | It's very easy for the foundation to just get their lawyers to
       | send you a cease and desist in the US.
       | 
       | As someone that relentlessly mocks hifalutin software engineering
       | in favor of practical solutions for humans, it seems highly
       | impractical, if not outright impossible for fully-fledged
       | alternative compiler to flourish in this ecosystem.
       | 
       | This is very stultifying. I can see why people ignored this
       | nonsense from the start, or moved to other languages.
        
         | steveklabnik wrote:
         | I don't know what you mean. This is a compiler bug? Nobody
         | claims that other compilers must also have the exact same bugs.
        
           | adastra22 wrote:
           | It is a compiler bug, yes.
        
             | steveklabnik wrote:
             | Sorry, I was typing the way I talk again, this doesn't
             | always come across well in text. Yes, thanks for making
             | sure that's known.
        
           | nicklecompte wrote:
           | It's really a bug in the design of Rust itself, not in the
           | implementation of rustc: https://counterexamples.org/nearly-
           | universal.html?highlight=... The fix needs to happen at the
           | level of type-theoretic computer science, not clever Rust
           | programming. And in particular, an alternate implementation
           | of Rust which fixes this bug _would have a different type
           | system_ than rustc, and arguably should be considered a
           | separate dialect of Rust (at least unless rustc is updated
           | accordingly).
        
             | steveklabnik wrote:
             | I think in the same way that you are frustrated because
             | people say "it's a compiler bug" too often, this feels like
             | going in the other direction too much. The higher order
             | bit, to me, is the "segfault in safe code means a bug"
             | stance that the overall project takes. Soundness holes
             | happen. Sometimes they take a while to transition away
             | from. Arguing that the compiler faithfully implements an
             | algorithm that causes bugs still means, from a higher
             | perspective, that the compiler has a bug: they have chosen
             | an inappropriate algorithm here.
             | 
             | There is no specification of the specific implementation
             | here. Rust could in fact (at least in theory, I am not an
             | expert on this specific problem) transition to a different
             | path here where the bug does not manifest. RFC 1214 is an
             | example of the Rust Project successfully doing this, and
             | hilariously enough, that situation is one of the things
             | that led to this one!
        
               | nicklecompte wrote:
               | No, the issue is NOT that they chose "an inappropriate
               | algorithm," they chose an inappropriate _design of the
               | language itself._ From the link [some typos might be mine
               | since I manually retyped some of the TeX symbols}:
               | 
               | > With constrained types, there are two different ways to
               | interpret a polymorphic type such as \forall a. C[a] ->
               | String:
               | 
               | > 1. "\forall a" really means "for all a" so the type
               | above is invalid since C[a] is not a valid type for all
               | a.
               | 
               | > 2. "\forall a" really means "for all a for which the
               | right hand side is valid," so the type above is valid,
               | but it can only be used for a = Int.
               | 
               | > ...
               | 
               | > Option (2) requires slightly less annotation by the
               | programmer, but it can be easy to lose track of the
               | implicit constraints on a. Rust chooses this option,
               | which led to a tricky bug.
               | 
               | And if you go on to read what this tricky bug is, it does
               | not involve any _incorrect_ implementations or even any
               | specific algorithm. It 's conflicting _requirements_ :
               | the design of co/contravariance of lifetimes in Rust
               | conflicts with the design of nearly-universal
               | quantification over types: one or the other has to be
               | changed in its core semantics, not merely patched with a
               | better algorithm.
               | 
               | ETA: My point is that an alternative compiler cannot
               | simultaneously solve this "compiler bug" and be
               | appropriately source-compatible with rustc. It seem like
               | they would either have a different syntax for type
               | quantification, or more stringent constraints on
               | lifetimes.
        
               | steveklabnik wrote:
               | It's clear we're not going to see eye to eye here.
               | "conflicting requirements" is a bug. It should be fixed.
               | It may be hard to fix. It may take a long time to fix.
               | That may mean "redesigning." Still a bug.
        
               | nicklecompte wrote:
               | I think we're not seeing "eye to eye" because you're not
               | actually responding to my comment! You seem to be
               | responding to something else. I said "it's really a bug
               | in the design of Rust itself" and you agree.
               | 
               | My point is that you said
               | 
               | > Nobody claims that other compilers must also have the
               | exact same bugs.
               | 
               | And that's true! But it's not relevant. Most people say
               | other compilers should have
               | 
               | 1) the same underlying type theory as rustc
               | 
               | 2) almost complete source-compatibility with rustc
               | 
               | If, say, "rustd" satisfies 1) and 2), then it's
               | guaranteed to have many of the same memory
               | vulnerabilities as rustc. The only way to fix these
               | vulnerabilities is to break 1) or 2), which is an awfully
               | steep price.
        
               | vlovich123 wrote:
               | FWIW C and C++ also have plenty of compiler-specific and
               | language errata due to unsoundness issues in the spec /
               | implementation bugs following the spec. I don't really
               | follow how an alternate Rust compiler would solve this
               | since a language errata needs to be fixed at the language
               | level & would impact all conforming compilers unless this
               | alternate Rust compiler basically forked the language, in
               | which case the Rust trademark is good as it lets people
               | disambiguate between the forks.
               | 
               | If it's a design issue, the Rust team is doing pretty
               | good on that front I think in terms of exploring new ways
               | of represting the type system (e.g. Polonius & the Trait
               | solver work that's moving forward).
               | 
               | Also, even if it somehow a new compiler somehow improved
               | soundness without forking the language, especially for a
               | language as complex as Rust, at best you're just picking
               | an alternate set of bugs. AFAICT the Rust team follows
               | best practices in terms of developing the code & managing
               | the people working on it, so it's hard to imagine an
               | alternate compiler team would outperform their progress
               | until the Rust project itself stagnates. Also, any
               | successful fork would likely start with rustc as the
               | basis anyway (the struggles and slow-going GCC is having
               | reimplementing Rust within GCC should exemplify why a
               | separate frontend isn't helpful).
        
         | woodruffw wrote:
         | I think they'd treat it like any other compiler bug. LLVM is
         | not bug-for-bug compatible with GCC, and doesn't attempt to be.
        
       | adastra22 wrote:
       | What's your shell prompt config that you screenshotted in the
       | README?
        
         | xal wrote:
         | looks like https://starship.rs/
        
       | hpb42 wrote:
       | Oh, cool. They implemented a `download_more_ram()` function![0]
       | 
       | Does it crash safely as well? I did not test it, I more than 640
       | KB of ram.
       | 
       | - [0] https://github.com/Speykious/cve-
       | rs/blob/d51f52dd64f148a086e...
        
       | foolswisdom wrote:
       | What a wonderful license! https://github.com/Speykious/cve-
       | rs/blob/main/LICENSE
        
         | poly_morphis wrote:
         | I could get behind that type of short, clear legalese.
        
         | yjftsjthsd-h wrote:
         | > 0. You just DO WHATEVER THE FUCK YOU WANT TO as long as you
         | NEVER LEAVE A FUCKING TRACE TO TRACK THE AUTHOR of the original
         | product to blame for or held responsible.
         | 
         | A thing of beauty^_^ I've seen a lot of licenses that require
         | attribution[0], so a license that explicitly demands that you
         | _not_ credit the author is a lovely twist:)
         | 
         | [0] Read: Nearly all of them; even permissive BSD-like licenses
         | usually(?) require that much.
        
       | saagarjha wrote:
       | Are you the safest because you're Rust? Or are you Rust because
       | you are the safest?
        
       | datadeft wrote:
       | The real question is: what is the chance that somebody runs into
       | this while implementing something common.
        
         | vacuity wrote:
         | It's not about frequency; it's about the possibility that just
         | one of these unsoundness bugs gets through to production and
         | screws things up. The whole point of memory safety languages is
         | that, unless you (or a dependency author) dives into the dark
         | arts of whatever language you're working in, you are
         | _guaranteed_ to not encounter use-after-free or null-pointer-
         | dereference. Practically, maybe such a bug gets patched
         | quickly, and no one exploits it as a vulnerability. In
         | hindsight, then, it wasn 't so bad. But you don't want to be
         | the one who is called at 2 AM because an impossible segfault
         | happened and wrecked the database.
        
       | fweimer wrote:
       | Without compiler bugs, on stock Linux, you can achieve the same
       | thing via /proc/self/mem. Rust makes this very easy because you
       | can get the raw address from safe code, so no guessing is
       | required which memory location to patch.
       | 
       | For the compiler bug, as someone who never strayed into those
       | regions of Rust programming, it's not clear to me how likely it
       | is that someone would write such code by accident and introduce a
       | memory safety issue into their program. I browsed the Github
       | issues, but couldn't find an indicator how people encountered
       | this in the first place.
        
         | jcmoyer wrote:
         | >Without compiler bugs, on stock Linux, you can achieve the
         | same thing via /proc/self/mem.
         | 
         | The documentation addresses this case specifically:
         | https://doc.rust-lang.org/stable/std/os/unix/io/index.html#p...
         | 
         | "Rust's safety guarantees only cover what the program itself
         | can do, and not what entities outside the program can do to it.
         | /proc/self/mem is considered to be such an external entity..."
        
       ___________________________________________________________________
       (page generated 2024-02-20 23:01 UTC)