7 ms·
I thought after Intel MPX we can all agree "memory safety" in modern languages is more about temporal stuff (i.e. use-after-free, etc) than bounds check, but ma
by rfoo 6y ago
I thought after Intel MPX we can all agree "memory safety" in modern languages is more about temporal stuff (i.e. use-after-free, etc) than bounds check, but maybe I'm wrong.
How does those runtime checks kill UAF?
- pron 6y ago> https://github.com/ziglang/zig/pull/5998 https://github.com/ziglang/zig/pull/5998 TBD :) But here's one way that's currently being tried: https://github.com/ziglang/zig/pull/5998 https://github.com/ziglang/zig/pull/5998
- littlestymaar 6y ago(Small copy past error here, you posted the same link twice.) Regarding https://github.com/ziglang/zig/pull/5998 https://github.com/ziglang/zig/pull/5998 here we're exactly in the realm of C, changing the allocator with a custom one with additional bookkeeping to check for memory management issues. But it tanks performances so you can't generally use it for production (and if you were in a situation were you'd do it anyway, you'd be better off with completely automatic memory management: AKA a GC).
- pron 6y agoNo, Zig is not in the realm of C. Zig gives you full memory safety that you can then selectively turn off. Why is it useful? For the same reason tests are useful even if they don't give you sound guarantees, and are still the primary way of achieving correctness, even in Haskell or Rust. C does not and cannot do this the same way as Zig does, because C cannot be made safe (well, it can, but that's a whole other can of worms) while Zig can. So you make Zig safe, test it, and then remove the guardrails from the performance-critical bits after you're satisfied with their correctness. Does it provide safety in the same manner Rust does? Absolutely not. Does it provide less correctness overall? Maybe, and maybe it provides more correctness, and maybe the same. It's hard to say without an empirical study. The problem is that sound guarantees often come at a cost -- for example, to language complexity and compilation speed -- that can have a negative effect on correctness.
- littlestymaar 6y ago> C does not and cannot do this the same way as Zig does Regarding the PR you just sent, I'd like to hear why you think it cannot be applied to C? > So you make Zig safe, test it, and then remove the guardrails from the performance-critical bits after you're satisfied with their correctness. This isn't safety… This is “we didn't find any memory issue while fuzzing the software” and you'd get the same guarantee: if your fuzzer didn't cause the memory issue, then it remains in your code in production, waiting to explode one day with some hard to debug Heisenbug that only occurs once in a million…
- pron 6y ago> Regarding the PR you just sent, I'd like to hear why you think it cannot be applied to C? I didn't mean that a safe allocator cannot be used in C; I meant that C cannot be made memory safe in its entirety as simply as Zig can. Why? Because C has pointer arithmetic while (safe) Zig doesn't, Zig has slices while C doesn't, and C has non-typesafe casts while safe Zig doesn't. > This isn't safety… This is “we didn't find any memory issue while fuzzing the software” and you'd get the same guarantee: No, it's not the same guarantee. Fuzzing a C program will not find all the undefined behaviour that fuzzing a Zig program can, for the reasons I mentioned. It is true that if you use unsafe Zig, i.e. turn off safety for a whole program or some sections of it, you lose the guarantees that safe Zig gives you, and unsafe Zig is indeed not safe (neither is unsafe Rust). But because of the way it's designed, Zig has a way of improving correctness even when safety is removed. This is a tradeoff for sure, but so are sound guarantees, that can have other negative effects on correctness.
- littlestymaar 6y ago> It is true that if you use unsafe Zig, i.e. turn off safety for a whole program or some sections of it, you lose the guarantees that safe Zig gives you, and unsafe Zig is indeed not safe Their is no such things as unsafe and safe Zig. All Zig is unsafe, but you can add additional runtime checks (disabled by default in optimized builds) that will slow down your program when used. Using a specific allocator to detect UAF is something you may do in development, but almost surely never in production. And without it your code isn't memory-safe. > Fuzzing a C program will not find all the undefined behaviour that fuzzing a Zig program can, for the reasons I mentioned. Zig will have less UB than C, but there will still be lurking UB in your programs no matter how long you test it. Consider the following snippet (on mobile, so this may have stupid syntax errors): test "this is UB, but the test won't show it" { const allocator = std.heap.page_allocator; var buf = try allocator.alloc(u8, 10); ohNo(allocator, 42, buf); allocator.free(bar); } fn ohNo(allocator: *Allocator, foo: const u8, bar: *u8) void { if (foo == 1337) { // double free awaiting to happen in production allocator.free(bar); } } If you never explicitly test the value “1337” during you debug session, you won't trigger the UB and you won't know it's here, then when you ship your optimized build in production, you'll ship a program with UB in it.