zlacker

[parent] [thread] 89 comments
1. layer8+(OP)[view] [source] 2022-10-02 15:41:34
Please correct me if I’m wrong, but Rust also has no built-in mechanism to statically determine “this code won’t ever panic”, and thus with regards to Linux kernel requirements isn’t safer in that aspect than C. To the contrary, Rust is arguably less safe in that aspect than C, due to the general Rust practice of panicking upon unexpected conditions.
replies(6): >>pornel+z1 >>jrochk+42 >>gerane+i2 >>jmilli+s2 >>dcsomm+03 >>stjohn+Hy
2. pornel+z1[view] [source] 2022-10-02 15:49:45
>>layer8+(OP)
Lack of a non-hacky no-panic guarantee is a pain. That would be like a no-segfault guarantee in C.

But Rust's situation is still safer, because Rust can typically prevent more errors from ever becoming a run-time issue, e.g. you may not even need to use array indexing at all if you use iterators. You have a guarantee that references are never NULL, so you don't risk nullptr crash, etc.

Rust panics are safer, because they reliably happen instead of an actually unsafe operation. Mitigations in C are usually best-effort and you may be lucky/unlucky to silently corrupt memory.

Panics are a problem for uptime, but not for safety (in the sense they're not exploitable for more than DoS).

In the long term crashing loud and clear may be better for reliability. You shake out all the bugs instead of having latent issues that corrupt your data.

replies(2): >>layer8+27 >>hegels+88
3. jrochk+42[view] [source] 2022-10-02 15:52:48
>>layer8+(OP)
> but Rust also has no built-in mechanism to statically determine “this code won’t ever panic”,

My intuition says that's the Halting Problem, so not actually possible to implement perfectly? https://en.wikipedia.org/wiki/Halting_problem

replies(5): >>jmilli+t3 >>im3w1l+H3 >>skybri+X3 >>pca006+b4 >>layer8+m4
4. gerane+i2[view] [source] 2022-10-02 15:54:35
>>layer8+(OP)
We cannot ensure that an arbitrary program halts by statically analyzing it. And it doesn’t have anything to do with the language of choice.

https://en.m.wikipedia.org/wiki/Halting_problem

replies(2): >>layer8+Q2 >>roywig+l6
5. jmilli+s2[view] [source] 2022-10-02 15:55:49
>>layer8+(OP)
Rust doesn't have an official `#[never_panic]` annotation, but there's a variety of approaches folks use. Static analysis (Clippy) can get you pretty far. My favorite trick is to link a no_std binary with no panic handler, and see if it has a linker error. No linker error = no calls to panic handler = no panics.

Note that Rust is easier to work with than C here, because although the C-like API isn't shy about panicking where C would segfault, it also inherits enough of the OCaml/Haskell/ML idiom to have non-panic APIs for pretty much any major operation. Calling `saturating_add()` instead of `+` is verbose, but it's feasible in a way that C just isn't unless you go full MISRA.

replies(2): >>ajross+Xe >>pdimit+Zp
◧◩
6. layer8+Q2[view] [source] [discussion] 2022-10-02 15:58:20
>>gerane+i2
Proof assistants, which I expect to eventually merge with programming languages, can be used to restrict the set of programs you write to those where you can statically prove all properties you expect the program to hold. It’s not much different from what diligent programmers have always done in their head (with, of course, much more room for error).

The fact that arbitrary programs are undecidable is a red herring here.

replies(2): >>yonixw+ij >>gerane+vI
7. dcsomm+03[view] [source] 2022-10-02 15:59:00
>>layer8+(OP)
> ... the general Rust practice of panicking upon unexpected conditions

What makes you say this? From the sample I've seen, Rust programs are far more diligent about handling errors (not panicking: either returning error or handling it explicitly) than C or Go programs due to the nature of wrapped types like Option<T> and Result<T, E>. You can't escape handling the error, and panicking potential is very easy to see and lint against with clippy in the code.

replies(1): >>layer8+N3
◧◩
8. jmilli+t3[view] [source] [discussion] 2022-10-02 16:01:40
>>jrochk+42
If you were to define a subset of Rust's standard library (core + alloc + std) that does not contain the `panic!` macro, and excluded all functionality that needed to panic, then safe Rust could be proven to never panic (because it can't).

That's different than solving the halting problem. You're not trying to prove it halts, you're just trying to prove it doesn't halt in a specific way, which is trivial to prove if you first make it impossible.

replies(1): >>gpm+M8
◧◩
9. im3w1l+H3[view] [source] [discussion] 2022-10-02 16:02:45
>>jrochk+42
If you are fine with saying that stuff like this code may panic (and many people are fine with just that), then it's perfectly doable

    if false {
        panic!()
    }
Basically you'd prohibit any call to panic whether they may actually end up running or not.
replies(1): >>jrochk+Uz1
◧◩
10. layer8+N3[view] [source] [discussion] 2022-10-02 16:03:15
>>dcsomm+03
I’m referring to the fact that ubiquitous functions like unwrap() panic if the programmer has made an error. Guarding against such panics is outside of the scope of Rust-the-language, and has to be handled through external means. There are linters for C as well.
replies(4): >>Velila+c6 >>hegels+f7 >>stjohn+tB >>tomjak+DX
◧◩
11. skybri+X3[view] [source] [discussion] 2022-10-02 16:04:12
>>jrochk+42
That's different. You can't perfectly detect all infinite loops in a language that allows arbitrary loops. This also means you can't perfectly detect unreachable code.

But determining that a function (such as panic) is never called because there are no calls to it is pretty easy.

◧◩
12. pca006+b4[view] [source] [discussion] 2022-10-02 16:05:29
>>jrochk+42
No, panic is not halting, you just need some static check to check that you never call some functions that can panic in your code. Essentially it is just checking if some code (panic) might be reachable, if it is not, it will never panic (but it can still do other crazy things).

Note that we can only check for maybe, because in general we don't know if some code in the middle will somehow execute forever and never reach the panic call after it.

replies(1): >>roywig+s8
◧◩
13. layer8+m4[view] [source] [discussion] 2022-10-02 16:06:22
>>jrochk+42
See https://news.ycombinator.com/item?id=33057059.
◧◩◪
14. Velila+c6[view] [source] [discussion] 2022-10-02 16:15:56
>>layer8+N3
I think I prefer Rust's way of doing things. Just last night I used the Vec! macro incorrectly putting in a comma instead of a semi-colon and despite the program compiling correctly, it immediately panicked with an OOB error. With C it would have been a lot harder to even notice a bug little alone track it down.
replies(1): >>layer8+u7
◧◩
15. roywig+l6[view] [source] [discussion] 2022-10-02 16:16:33
>>gerane+i2
You can prove that a machine can't ever write "1" to the tape if you just look at the state machine and see that none of the rules write a 1 to the tape. Since no rules ever write 1, no possible execution could.

Working out whether it will write 1 to the tape in general is undecidable, but in certain cases (you've just banned states that write 1) it's trivial.

If all of the state transitions are valid (a transition to a non-existing state is a halt) then the machine can't get into a state that will transition into a halt, so it can't halt. That's a small fraction of all the machines that won't halt, but it's easy to tell when you have one of this kind by looking at the state machine.

replies(2): >>yonixw+Ej >>gerane+cF
◧◩
16. layer8+27[view] [source] [discussion] 2022-10-02 16:20:52
>>pornel+z1
One has to be careful about words. When Rust (or Linux) is used in (say) a vehicle or in a nuclear power plant, panicking certainly has immediate safety implications.
replies(2): >>pornel+E7 >>avgcor+1a
◧◩◪
17. hegels+f7[view] [source] [discussion] 2022-10-02 16:22:01
>>layer8+N3
Linters can catch panics, linters for C won't catch memory issues which is what rust prevents.
replies(1): >>layer8+h9
◧◩◪◨
18. layer8+u7[view] [source] [discussion] 2022-10-02 16:23:09
>>Velila+c6
Right. My personal opinion is that exceptions provide a better trade-off between catching bugs and still allowing the chance of graceful shutdown or recovery.
replies(2): >>Velila+W9 >>stjohn+yB
◧◩◪
19. pornel+E7[view] [source] [discussion] 2022-10-02 16:23:39
>>layer8+27
But it can still be safer - e.g. a panic can trigger an emergency stop instead of silently overwriting the "go full throttle" variable.
replies(1): >>mike_h+dd
◧◩
20. hegels+88[view] [source] [discussion] 2022-10-02 16:25:53
>>pornel+z1
I think you're missing the point Linus made. Panicking is safer from a memory safety perspective, but it's not from a kernel perspective. You'll lose all the file changes that are not saved, you'll risk having disk written in a bad state which can be catastrophic, etc.
replies(3): >>pornel+qa >>lifthr+gb >>zozbot+Xg
◧◩◪
21. roywig+s8[view] [source] [discussion] 2022-10-02 16:27:25
>>pca006+b4
Even if it is halting, you can sometimes statically detect if a Turing machine never halts. Just look through the state machine and see if any states will transition to a halt; if none of them do, the machine will loop forever. This is not a very large fraction of machines that loop forever, but if you're writing a machine and want to be absolutely sure it won't halt, just don't put in any states that halt.
◧◩◪
22. gpm+M8[view] [source] [discussion] 2022-10-02 16:29:01
>>jmilli+t3
> If you were to define a subset of Rust's standard library (core + alloc + std) that does not contain the `panic!` macro, and excluded all functionality that needed to panic, then safe Rust could be proven to never panic (because it can't).

Not quite, because stack overflows can cause panics independent of any actual invocation of the panic macro.

You need to either change how stack overflows are handled as well, or you need to do some static analysis of the stack size as well.

Both are possible (while keeping rust turing complete), so it's still not like the halting problem.

replies(1): >>jmilli+zb
◧◩◪◨
23. layer8+h9[view] [source] [discussion] 2022-10-02 16:30:55
>>hegels+f7
Linters like Splint [0] (predating Rust) can do that for C. I’m not saying that Rust’s built-in approach isn’t better, but please be careful about what exactly you claim.

[0] http://splint.org/

replies(2): >>dcsomm+Mc >>hegels+Vn1
◧◩◪◨⬒
24. Velila+W9[view] [source] [discussion] 2022-10-02 16:33:37
>>layer8+u7
In my case it wouldn't have raised an exception though, it would have just been UB.

It's not like there's not exceptions in Rust though. The error handling is thorough to a fault when it's used. Unwrap is just a shortcut to say "I know there might be bad input, I don't want to handle it right now, just let me do it and I'll accept the panic."

replies(1): >>layer8+fc
◧◩◪
25. avgcor+1a[view] [source] [discussion] 2022-10-02 16:34:30
>>layer8+27
And a perfect, bug-free ballistic rocket program is unsafe in the sense that it is efficient at causing damage.

Rust’s “safety” has always meant what the Rust team meant by that term. There’s no gotcha to be found here except if you can find some way that Rust violates its own definition of the S-word.

This submission is not really about safety. It’s a perfectly legitimate concern that Rust likes to panic and that panicking is inappropriate for Linux. That isn’t about safety per se.

“Safety“ is a very technical term in the PL context and you just end up endlessly bickering if you try to torture the term into certain applications. Is it safer to crash immediately or to continue the program in a corrupted state? That entirely depends on the application and the domain, so it isn’t a useful distinction to make in this context.

EDIT: The best argument one could make from this continue-can-be-safer perspective is that given two PLs, the one that lets you abstract over this decision (to panic or to continue in a corrupted state, preferably with some out of band error reporting) is safer. And maybe C is safer than Rust in that regard (I wouldn’t know).

replies(2): >>layer8+tb >>goto11+lR1
◧◩◪
26. pornel+qa[view] [source] [discussion] 2022-10-02 16:36:37
>>hegels+88
I understand his point. I just disagree, and prefer a different tradeoff.

Yes, a kernel panic will cause disruption when it happens. But that will also give a precise error location, which makes reporting and fixing of the root cause easier. It could be harder to pinpoint of the code rolled forward in broken state.

It will cause loss of unsaved data when it happens, but OTOH it will prevent corrupted data from being persisted.

replies(2): >>wtalli+oe >>stjohn+eA
◧◩◪
27. lifthr+gb[view] [source] [discussion] 2022-10-02 16:40:58
>>hegels+88
Panic corresponds to a potential logic bug. If you have a logic bug, you already risk its consequences even if the panic didn't happen. As long as panic can be caught (and in Rust, it's indeed the case) it is safer than the alternative.
replies(1): >>hegels+fq1
◧◩◪◨
28. layer8+tb[view] [source] [discussion] 2022-10-02 16:41:42
>>avgcor+1a
That’s exactly my point. Rust’s definition of safety is a very specific one, and one has to be careful about what it actually implies in the context where Rust is employed. “Safety” isn’t a well-defined term for PL in general. “Soundness” is.
replies(2): >>avgcor+pj >>UncleM+fx
◧◩◪◨
29. jmilli+zb[view] [source] [discussion] 2022-10-02 16:41:57
>>gpm+M8
In a Rust defined without `panic!`, a stack overflow would not be able to panic. What would probably happen is the process would just die, like C.
◧◩◪◨⬒⬓
30. layer8+fc[view] [source] [discussion] 2022-10-02 16:45:39
>>Velila+W9
By exceptions, I’m referring to languages with exceptions as a dedicated language construct with automatic stack unwinding, and preferably without UB (e.g. Java or C#). Rust doesn’t have exceptions in that sense.
replies(1): >>dureui+zp
◧◩◪◨⬒
31. dcsomm+Mc[view] [source] [discussion] 2022-10-02 16:49:18
>>layer8+h9
Interesting that despite tools like Splint, 70% of high severity security vulns, including in well staffed projects like Chrome and Windows, are due to memory unsafety. The false negatives of security analysis tools are significant and are the very reason Rust got developed.
replies(1): >>layer8+Ud
◧◩◪◨
32. mike_h+dd[view] [source] [discussion] 2022-10-02 16:51:18
>>pornel+E7
Yes, or jumping to the "emergency stop" routine can instead trigger "go full throttle" because the jump address has been corrupted.

Or in an actual vehicle, the "emergency stop" (if that means just stomping on the brakes) can flip the car and kill its passengers.

replies(1): >>stjohn+9B
◧◩◪◨⬒⬓
33. layer8+Ud[view] [source] [discussion] 2022-10-02 16:55:13
>>dcsomm+Mc
No, the reason Rust was developed (with regard to that aspect) was that the necessary static analysis is enforced by the compiler if it is built into the language, whereas otherwise (if not built in) it empirically doesn’t get a lot of adoption. There’s nothing Rust’s static analysis is doing that couldn’t be done with the same semantics using an external static analyzer and linter annotations.

The ideas of Rust weren’t new when Rust was developed. The actual integration into a new programming language beyond experimental status was, and the combination with ML-style functional programming.

◧◩◪◨
34. wtalli+oe[view] [source] [discussion] 2022-10-02 16:58:29
>>pornel+qa
> But that will also give a precise error location, which makes reporting and fixing of the root cause easier. It could be harder to pinpoint of the code rolled forward in broken state.

I think you must have missed out on how Linux currently handles these situations. It does not silently move on past the error; it prints a stack trace and CPU state to the kernel log before moving on. So you have all of the information you'd get from a full kernel panic, plus the benefit of a system that may be able to keep running long enough to save that kernel log to disk.

◧◩
35. ajross+Xe[view] [source] [discussion] 2022-10-02 17:01:28
>>jmilli+s2
> Static analysis (Clippy) can get you pretty far.

What's funny about this is that (while it's true!) it's exactly the argument that Rustaceans tend to reject out of hand when the subject is hardening C code with analysis tools (or instrumentation gadgets like ASAN/MSAN/fuzzing, which get a lot of the same bile).

In fact when used well, my feeling is that extra-language tooling has largely eliminated the practical safety/correctness advantages of a statically-checked language like rust, or frankly even managed runtimes like .NET or Go. C code today lives in a very different world than it did even a decade ago.

replies(6): >>jmilli+ch >>lifthr+Th >>j-krie+jl >>tialar+jr >>P5fRxh+431 >>pjmlp+KY3
◧◩◪
36. zozbot+Xg[view] [source] [discussion] 2022-10-02 17:12:08
>>hegels+88
Panic in Rust need not equate to a literal kernel panic. It can call an oops handler, which might manage to keep the system operational depending on where the failure occurred.
replies(1): >>hegels+3r1
◧◩◪
37. jmilli+ch[view] [source] [discussion] 2022-10-02 17:13:37
>>ajross+Xe
Analysis for memory safety is really hard. For >40 years there's been entire sub-industries focused just on analysis of C/C++ memory safety and it's nowhere near a solved problem. That's why Rust has `unsafe`, it's so the programmer has a way to encode logic that they believe is safe but aren't yet able to prove.

Analysis of panic-safety in Rust is comparatively easy. The set of standard library calls that can panic is finite, so if your tool just walks every call graph you can figure out whether panic is disproven or not.

replies(1): >>ajross+zi1
◧◩◪
38. lifthr+Th[view] [source] [discussion] 2022-10-02 17:18:13
>>ajross+Xe
While C/C++ has been made much safer by sanitizers, fuzzing and lints, they are:

- Only useful when actually being used, which is never the case. (Seriously, can we make at least ASAN the default?)

- Often costly to always turn them on (e.g. MSAN).

- Often requires restructuring or redesign to get the most out of them (especially fuzzing).

Rust's memory safety guarantee does not suffer from first two points, and the third point is largely amortized into the language learning cost.

replies(1): >>pjmlp+lZ3
◧◩◪
39. yonixw+ij[view] [source] [discussion] 2022-10-02 17:25:43
>>layer8+Q2
"Undecidable" Is way too close to your day2day program than you think: https://en.wikipedia.org/wiki/Rice%27s_theorem

I would like to learn otherwise, but even a React JS+HTML page is undecidable... its scope is limited by chrome V8 js engine (like a vm), but within that scope I don't think you can prove anything more. otherwise we could just make static analysis to check if it will leak passwords...

replies(1): >>layer8+Wl
◧◩◪◨⬒
40. avgcor+pj[view] [source] [discussion] 2022-10-02 17:26:18
>>layer8+tb
Memory safety is a well-defined term.
replies(1): >>layer8+uk
◧◩◪
41. yonixw+Ej[view] [source] [discussion] 2022-10-02 17:27:29
>>roywig+l6
"Print 1" is trivial according to this: https://en.wikipedia.org/wiki/Rice%27s_theorem.

But day to day programs are not trivial... as for your example, just switch it with this code: `print(gcd(user_input--,137))`... now it's quite more hard to "just ban some final states"

replies(3): >>joshua+Kx >>UncleM+Nx >>roywig+3y
◧◩◪◨⬒⬓
42. layer8+uk[view] [source] [discussion] 2022-10-02 17:30:54
>>avgcor+pj
I agree, but that isn’t the term that was used here, and Rust proponents usually mean more than memory safety by “safe” (like e.g. absence of UB).
replies(2): >>avgcor+fo >>veber-+l42
◧◩◪
43. j-krie+jl[view] [source] [discussion] 2022-10-02 17:35:29
>>ajross+Xe
The difference being that C is barely changed for the sake of backwards compatibility while the panicking in kernel space is a recognized problem with rust that is being actively worked on and will have a solution in the future.
◧◩◪◨
44. layer8+Wl[view] [source] [discussion] 2022-10-02 17:39:28
>>yonixw+ij
I’m not sure you understand Rice’s theorem correctly. It means that you can’t write an algorithm that takes an arbitrary program as input and tells you whether it fulfills a given nontrivial semantic property. But you can write an algorithm that can tell you for some subset of programs. So as a developer, if you restrict yourself to releasing programs for which the algorithm has halted and given you the desired answer, you are fine.

Depending on the semantic property to check for, writing such an algorithm isn’t trivial. But the Rust compiler for example does it for memory safety, for the subset of valid Rust programs that don’t use Unsafe.

replies(1): >>yonixw+Dm
◧◩◪◨⬒
45. yonixw+Dm[view] [source] [discussion] 2022-10-02 17:42:20
>>layer8+Wl
But isn't every program we write today (Rust, C++, Python, JS, etc.) raise up to the level of an "arbitrary program"? How do you find those "some subset of programs" that will halt by said algorithm?

The only sure way I can think of, is when you force your program to go through a more narrow non-turing algorithm. Like sending data through a network after Serialization. Where we could limit the De-Serialization process to be non Turing (json, yaml?).

Same for code, that uses non-turing API, like memory allocation in a dedicated per process space. Or rust "borrow" mechanics that the compiler enforces.

But my point is, everyday program are "arbitrary program" and not a red haring. Surly from the kernel perspective, which is Linus point imo.

replies(1): >>layer8+op
◧◩◪◨⬒⬓⬔
46. avgcor+fo[view] [source] [discussion] 2022-10-02 17:50:53
>>layer8+uk
Going through that thread (a few posts back) it seems that “Rust is safe” (as seen in this submission title) was stated first by Torvalds. It wasn’t mentioned first by a “Rust aficianado”. So you would really have to ask Torvalds what he meant. But his mentioning of it (and this submission) obviously alludes to “safe” claims by the Rust project. Which has always been memory safety.
replies(1): >>layer8+Vq
◧◩◪◨⬒⬓
47. layer8+op[view] [source] [discussion] 2022-10-02 17:57:09
>>yonixw+Dm
For the first question, see the second paragraph I added in my previous comment.

Regarding the second question, in the general case you have to guess or think hard, and proceed by trial and error. You notice that the analyzer takes more time than you’re willing to wait, so you stop it and try to change your program in order to fix that problem.

We already have that situation today, because the Rust type system is turing-complete. Meaning, the Rust compiler may in principle need an infinite amount of time to type-check a program. Normally the types used in actual programs don’t trigger that situation (and the compiler also may first run out of memory).

By the way, even if Rust’s type system wasn’t turing-complete, the kind of type inference it uses takes exponential time, which in practice is almost the same as the possibility of non-halting cases, because you can’t afford to wait a hundred or more years for your program to finish compiling.

> But my point is, everyday program are "arbitrary program"

No, most programs we write are from a very limited subset of all possible programs. This is because we already reason in our heads about the validity and suitability of our programs.

replies(1): >>yonixw+3r
◧◩◪◨⬒⬓⬔
48. dureui+zp[view] [source] [discussion] 2022-10-02 17:58:15
>>layer8+fc
But panics in rust are pretty much exceptions though?

The differences are they are actually meant to be used for exceptional situations ("assert violated => there's a bug in this program" or "out of memory, catastrophic runtime situation") and they are not typed (rather, the panic holds a type erased payload).

Other than that, it performs unwinding without UB, and is catchable[0]. I'm not seeing the technical difference?

[0]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html

replies(1): >>layer8+2s
◧◩
49. pdimit+Zp[view] [source] [discussion] 2022-10-02 18:00:47
>>jmilli+s2
> My favorite trick is to link a no_std binary with no panic handler, and see if it has a linker error. No linker error = no calls to panic handler = no panics.

Oh? How do you do that? Do you have a written guide handy? Very curious about this.

◧◩◪◨⬒⬓⬔⧯
50. layer8+Vq[view] [source] [discussion] 2022-10-02 18:05:58
>>avgcor+fo
I disagree that “safe” as used by the Rust community is always restricted to memory safety, see my parent comment.
◧◩◪◨⬒⬓⬔
51. yonixw+3r[view] [source] [discussion] 2022-10-02 18:06:23
>>layer8+op
> Regarding the second question, in the general case you have to guess or do trial and error.

> You notice that the analyzer takes more time than you’re willing to wait,

I see, thanks, didn't know about this feedback loop as I'm not a rust programmer. Still on my todo list to learn.

replies(1): >>layer8+it
◧◩◪
52. tialar+jr[view] [source] [discussion] 2022-10-02 18:07:46
>>ajross+Xe
Rust makes choices which drastically simplify the analysis problem.

The most obvious is mutable references. In Rust there can be either one mutable reference to an object or there may be any number of immutable references. So if we're thinking about this value here, V, and we're got an immutable reference &V so that we can examine V well... it's not changing, there are no mutable references to it by definition. The Rust language won't let us have &mut V the mutable reference at the same time &V exists and so it needn't ever account for that possibility†.

In C and C++ they break this rule all the time. It's really convenient, and it's not forbidden in C or C++ so why not. Well, now the analysis you wanted to do is incredibly difficult, so good luck with that.

† This also has drastic implications for an optimiser. Rust's optimiser can often trivially conclude that a= f(b); can't change b where a C or C++ optimiser is obliged to admit that actually it's not sure, we need to emit slower code in case b is just an alias for a.

replies(1): >>ajross+Uo1
◧◩◪◨⬒⬓⬔⧯
53. layer8+2s[view] [source] [discussion] 2022-10-02 18:13:46
>>dureui+zp
You’re probably right now that I’ve read up on it, I wasn’t previously aware of catch_unwind.
replies(1): >>dureui+Vs
◧◩◪◨⬒⬓⬔⧯▣
54. dureui+Vs[view] [source] [discussion] 2022-10-02 18:18:57
>>layer8+2s
Glad to be of service. Note that the idiomatic error handling in rust is still Result based rather than panic/catch_unwind based.

Nevertheless a long living application like, e.g., a webserver will catch panics coming from its subtasks (e.g., its request handlers) via catch_unwind

◧◩◪◨⬒⬓⬔⧯
55. layer8+it[view] [source] [discussion] 2022-10-02 18:21:04
>>yonixw+3r
I don’t think it actually happens in Rust in practice, or only very rarely. I was more talking about the hypothetical case for any static analysis of nontrivial program properties as in Rice’s theorem.
◧◩◪◨⬒
56. UncleM+fx[view] [source] [discussion] 2022-10-02 18:46:00
>>layer8+tb
> “Safety” isn’t a well-defined term for PL in general. “Soundness” is.

This is false. "Safety" and "Liveness" are terms used by the PL field to describe precise properties of programs and they have been used this way for like 50 years (https://en.wikipedia.org/wiki/Safety_and_liveness_properties). A "safety" property describes a guarantee that a program will never reach some form of unwanted state. A "liveness" property describes a guarantee that a program will eventually reach some form of wanted state. These terms would be described very early in a PL course.

replies(1): >>layer8+9W
◧◩◪◨
57. joshua+Kx[view] [source] [discussion] 2022-10-02 18:49:12
>>yonixw+Ej
Indeed, but panic is easier because in some ways checking if a program can panic is akin to checking if the program links the panic function.

And that's pretty easy to statically analyze.

◧◩◪◨
58. UncleM+Nx[view] [source] [discussion] 2022-10-02 18:49:19
>>yonixw+Ej
That's not what "trivial property" means w.r.t. Rice's Thm.

The point is that you can produce a perfectly working analysis method that is either sound or complete but not both. "Nowhere in the entire program does the call 'panic()' appear is a perfectly workable analysis - it just has false positives.

◧◩◪◨
59. roywig+3y[view] [source] [discussion] 2022-10-02 18:50:22
>>yonixw+Ej
Turing machines have a set of states and a transition function that governs how it moves between states. The transition function is a bunch of mappings like this:

    (input state, input symbol) --> (output state, output symbol, move left/right)
This is all static, so you can look at the transition table to see all the possible output symbols. If no transition has output symbol 1, then it never outputs 1. It doesn't matter how big the Turing machine is or what input it gets, it won't do it. This is basically trivial, but it's still a type of very simple static analysis that you can do. Similarly, if you don't have any states that halt, the machine will never halt.

This is like just not linking panic() into the program: it isn't going to be able to call it, no matter what else is in there.

60. stjohn+Hy[view] [source] 2022-10-02 18:55:10
>>layer8+(OP)
I think you're mixing up what a -kernel- rust programmer would do (but should know not to do) vs what rust "is", it's not the same. You have to enter a different mindset with the kernel, it will be a new hybrid of c context in the kernel and user-land programming.
◧◩◪◨
61. stjohn+eA[view] [source] [discussion] 2022-10-02 19:05:56
>>pornel+qa
On one embedded projected we had a separate debug chip could safely shutdown what might be dangerous circuits in the case of controller failure. The source code for that was much much much smaller than the controller and heavily vetted by mulitiple people. The small dedicated would initiate circuit shutdown on panic from the linux kernel on the controller. My point being is it's hard to know what happens after a panic, and logging and such is nice, but that may or may not be available, but being able to do some action as simple as sending a "panic" signal to a second dedicated processor to shut down critical systems in a controlled manner is nice. "Stop the world" can be very dangerous in some situations. There were even more independent backup failsafes on the potentially dangerous circuits as well, but redundancy is even more insurance something bad won't happen.
◧◩◪◨⬒
62. stjohn+9B[view] [source] [discussion] 2022-10-02 19:12:31
>>mike_h+dd
It's about the odds here. Nothing is 100% safe. Independent systems almost always provide backup safety incase the OS/embedded system fails. Thing like overcurrent detector, brown out detectors, speed governors, etc in case code does something as a result of running corrupted (or something similarly awful)
◧◩◪
63. stjohn+tB[view] [source] [discussion] 2022-10-02 19:13:59
>>layer8+N3
That's where linters and code reviews come in, you will never 100% prevent stupid coding, that's where review either automated and/or other coders and coding standards come in.
◧◩◪◨⬒
64. stjohn+yB[view] [source] [discussion] 2022-10-02 19:14:47
>>layer8+u7
exceptions would be awful in the kernel. I would be highly surprised if kernels like fuscia allow c++ exceptions.
◧◩◪
65. gerane+cF[view] [source] [discussion] 2022-10-02 19:41:20
>>roywig+l6
> Rust is arguably less safe in that aspect than C, due to the general Rust practice of panicking upon unexpected conditions

For context, this is OP's sentence that I responded to in particular. Ensuring safety [1] is way less trivial than looking for a call to "panic" in the state machine. You can remove the calls to "panic" and this alone does not make your program safer than the equivalent C code. It just makes it more kernel friendly.

[1] not only memory safety

◧◩◪
66. gerane+vI[view] [source] [discussion] 2022-10-02 20:03:00
>>layer8+Q2
> Rust is arguably less safe in that aspect than C, due to the general Rust practice of panicking upon unexpected conditions

For clarification, I responded to this in particular because "safety" is being conflated with "panicking" (bad for kernel). I reckoned "Unexpected conditions" means "arbitrary programs", hence my response, otherwise you could just remove the call to panic.

◧◩◪◨⬒⬓
67. layer8+9W[view] [source] [discussion] 2022-10-02 21:31:48
>>UncleM+fx
What I mean is that there is no universal definition of which properties are safety properties. In principle, you can define any property you can formally reason about as a safety property. Therefore, whenever you talk about safety, you first have to define which properties you mean by that.

In the context of Rust, there are a number of safety properties that Rust guarantees (modulo unsafe, FFI UB, etc.), but that set of safety properties is specific to Rust and not universal. For example, Java has a different set of safety properties, e.g. its memory model gives stronger guarantees than Rust’s.

Therefore, the meaning of “language X is safe” is entirely dependent on the specific language, and can only be understood by explicitly specifying its safety properties.

replies(2): >>avgcor+XX >>UncleM+R41
◧◩◪
68. tomjak+DX[view] [source] [discussion] 2022-10-02 21:41:34
>>layer8+N3
> that ubiquitous functions like unwrap() panic if the programmer has made an error.

You're not wrong but you chose a hilarious example. Unwrap's entire purpose is to turn unhandled errors into panics!

Array indexing, arithmetic (with overflow-checks enabled), and slicing are examples where it's not so obvious there be panic dragons. Library code does sometimes panic in cases of truly unrecoverable errors also.

◧◩◪◨⬒⬓⬔
69. avgcor+XX[view] [source] [discussion] 2022-10-02 21:43:56
>>layer8+9W
> Therefore, whenever you talk about safety, you first have to define which properties you mean by that.

Like “memory safety”?

replies(1): >>layer8+k21
◧◩◪◨⬒⬓⬔⧯
70. layer8+k21[view] [source] [discussion] 2022-10-02 22:14:36
>>avgcor+XX
For example. Rust has other safety properties beyond memory safety.
◧◩◪
71. P5fRxh+431[view] [source] [discussion] 2022-10-02 22:19:40
>>ajross+Xe
I've long been of the opinion that the rust community is missing the boat in a lot of respects.

Rust could do the external tooling better than any other language out there, but they're so focused on the _language_ preventing abuse that they've largely missed the boat.

◧◩◪◨⬒⬓⬔
72. UncleM+R41[view] [source] [discussion] 2022-10-02 22:32:22
>>layer8+9W
That's true for "soundness" too. Things aren't just "sound". They are sound with respect to something. So when you use "soundness" as a comparison against "safety", you'll have to understand how somebody could interpret your post in the way that I did.

Almost all discussion about Rust is in comparison to C and C++, by far the dominant languages for developing native applications. C and C++ are famously neither type-safe nor memory-safe and it becomes a pretty easy shorthand in discussions of Rust for "safety" to refer to these properties.

◧◩◪◨
73. ajross+zi1[view] [source] [discussion] 2022-10-03 00:18:58
>>jmilli+ch
> That's why Rust has `unsafe`, it's so the programmer has a way to encode logic that they believe is safe but aren't yet able to prove.

That's not the right way to characterize this. Rust has unsafe for code that is correct but that the compiler is unable to detect. Foreign memory access (or hardware MMIO) and cyclic data structures are the big ones, and those are well-specified, provable, verifiable regimes. They just don't fit within the borrow checker's world view.

Which is something I think a lot of Rust folks tend to gloss over: even at it's best, most maximalist interpretation, Rust can only verify "correctness" along axes it understands, and those aren't really that big a part of the problem area in practice.

replies(1): >>kaba0+eI2
◧◩◪◨⬒
74. hegels+Vn1[view] [source] [discussion] 2022-10-03 01:05:32
>>layer8+h9
Splint doesn't make C memory safe. What I meant is that it doesn't prevent the same problems that Rust does. Hence, you can add a linter to rust to prevent panics. You cannot add a linter to C to make it memory safe.
◧◩◪◨
75. ajross+Uo1[view] [source] [discussion] 2022-10-03 01:14:24
>>tialar+jr
That point would be stronger if Rust were showing up as faster than C compilers on this axis, and it isn't. In point of fact aliasing rules (which is what C calls the problem you're talking about) are very well travelled ground and the benefits and risks of -fno-strict-aliasing are well understood. Static analysis tools are in fact extremely good at this particular area of the problem. And of course at the level of emerging technologies, LTO makes this largely a non-issue because the compiler is able to see the aliasing opportunities at the level of global analysis. It doesn't need the programmer or the compiler to promise it an access is unaliased, it can just check and see.
replies(1): >>kaba0+EI2
◧◩◪◨
76. hegels+fq1[view] [source] [discussion] 2022-10-03 01:25:44
>>lifthr+gb
1. As far as i'm aware there's no way to reliably catch all panics. catch_unwind does not catch all panics. 2. The whole point is that consequences of a panic are worse than the consequences of memory corruption. That's how the kernel was designed. There was an explicit design decision not to kernel panic in every situation where a logic error occurs.
replies(1): >>lifthr+8D1
◧◩◪◨
77. hegels+3r1[view] [source] [discussion] 2022-10-03 01:32:36
>>zozbot+Xg
As far as I'm aware there's no way to reliably catch all panics. catch_unwind does not catch all panics. Handlers don't stop the program from terminating abruptly.
◧◩◪
78. jrochk+Uz1[view] [source] [discussion] 2022-10-03 02:46:29
>>im3w1l+H3
Fair. From the responses, clearly i didn't know what I was talking about, fair enough!

But ok, uninformed me would have guessed checking for that would be pretty straightforward in statically typed Rust. Is that something people want? Why isn't there a built-in mechanism to do it?

◧◩◪◨⬒
79. lifthr+8D1[view] [source] [discussion] 2022-10-03 03:23:50
>>hegels+fq1
There are tons of edge cases with panics, e.g. panic can trigger a destructor that can panic itself, or unwinding may cross a language boundary which may not be well defined, but to my knowledge `catch_unwind` does catch all panics as long as unwinding reliably works. That disclaimer in the `catch_unwind` documentation only describes the `panic = abort` case.

And I thought it was clear that kernel panic is different from Rust panic, which you don't seem to distinguish. Rust panic doesn't need to cause a kernel panic because it can be caught earlier.

replies(1): >>hegels+WG1
◧◩◪◨⬒⬓
80. hegels+WG1[view] [source] [discussion] 2022-10-03 04:11:43
>>lifthr+8D1
Obviously rust panic is not the same as a kernel panic. What you're taking for granted is that just because rust can catch a panic that it will. A simple overflow can cause a panic. When this happens, the panic might be caught before the kernel panics, but by then the program is probably already in an undefined state. It also might not be caught at all, and cause an actual kernel panic.
replies(1): >>lifthr+VJ1
◧◩◪◨⬒⬓⬔
81. lifthr+VJ1[view] [source] [discussion] 2022-10-03 04:47:14
>>hegels+WG1
The program is in a defined but undesirable state, both when panic occurred in Rust and when a "simple" uncontrolled overflow happened in C (provided that the compiler is configured to not treat it as an UB, otherwise it'd be worse). And anyone doing Rust-C interop already has to be conscious about the language boundary, which happens to be a perfect place to catch Rust panics.
◧◩◪◨
82. goto11+lR1[view] [source] [discussion] 2022-10-03 06:16:11
>>avgcor+1a
Linus' point is that safety means something different in kernel programming than in PL theory, and that Rust have to be safe according to kernel rules before it can be used for kernel programming.
◧◩◪◨⬒⬓⬔
83. veber-+l42[view] [source] [discussion] 2022-10-03 08:24:16
>>layer8+uk
absence of UB is literally memory safety.

Rust proponents mean exactly "memory safety" when they say rust is safe because that is the only safety rust guarantees.

◧◩◪◨⬒
84. kaba0+eI2[view] [source] [discussion] 2022-10-03 13:37:14
>>ajross+zi1
I don’t really get your comment - are you agreeing or disagreeing with parent? Because you seemingly say the same thing.

And continuing on parent’s comment, rust can only make its memory guarantees by restricting the set of programmable programs, while C and the like’s static analysis has to work on the whole set which is simply an undecidable problem. As soon as unsafe is in the picture, it becomes undecidable as well in Rust, in general.

replies(1): >>ajross+bo3
◧◩◪◨⬒
85. kaba0+EI2[view] [source] [discussion] 2022-10-03 13:39:06
>>ajross+Uo1
It’s not a problem, because compilers simply declare it as UB and don’t care about it. If you by accident did depend on that, your program will just get a nice, hard to debug bug.
◧◩◪◨⬒⬓
86. ajross+bo3[view] [source] [discussion] 2022-10-03 16:38:03
>>kaba0+eI2
The parent comment seemed to imply that using unsafe was a failing of the developer to prove to the compiler that the code is correct. And that's not right, unless you view thing like "doubly linked list" as incorrect code. Unsafe is for correct code that the compiler is unable to verify.
◧◩◪
87. pjmlp+KY3[view] [source] [discussion] 2022-10-03 19:06:04
>>ajross+Xe
Static analysis for C exists since 1979, date of lint's availability, the problem isn't lack of tooling, rather people actually using it.
replies(1): >>jstimp+bF7
◧◩◪◨
88. pjmlp+lZ3[view] [source] [discussion] 2022-10-03 19:08:42
>>lifthr+Th
> Seriously, can we make at least ASAN the default?

Android helps a bit into that sense,

https://source.android.com/docs/security/test/hwasan

◧◩◪◨
89. jstimp+bF7[view] [source] [discussion] 2022-10-04 20:29:45
>>pjmlp+KY3
I would assume that the things that lint could do you nowadays get by simply using -Wall -Wextra with gcc for example. While I haven't checked what a lint is required to do, but there have been plenty of situations in the past where I had to change my code in order to avoid triggering false positives from tests that run during normal compilation. For instance, there are tests that find accesses to potentially uninitialized variables.
replies(1): >>pjmlp+Nw9
◧◩◪◨⬒
90. pjmlp+Nw9[view] [source] [discussion] 2022-10-05 10:21:36
>>jstimp+bF7
If we are talking about the 1979 version, most likely.

If we are talking about products like PC-lint, Sonar qube, Coverity, the experience is much more than that.

[go to top]