Live data from Hacker News

Cake – C23 and Beyond (2023)

thradams.com

111–120 of 128 posts

Re: Cake – C23 and Beyond (2023)

#111

Earlier quoted context omitted.

let p: Box = Box::new(X { ... }); let x2 = X { ... }; // Moves x2 into the same memory as the first X. // The first X is automatically dropped as part of this assignment. // Also consumes x2 so x2 is not available any more. *p = x2; // Drops the X that was originally assigned to x2 and then moved into p. drop(p); // No need, nor is it possible, to destroy x2.

Thanks for the rust sample. It looks very similar. Can the allocator be customized? As I said I am not Rust specialist. Also, in my understanding is that in Rust, sometimes a dynamic state is created when the object may or may not be moved. In cake ownership this needs to me explicit ( and the destructor is not generated) I also had a look at Rust in lifetime annotations. This concept may be necessary but I am avoidi…

>Can the allocator be customized?

`Box` is the type of an owning pointer that uses the default global allocator, and `Box` is the type of an owning pointer that uses an allocator of type `A`. The latter is unstable, ie it can only be used in nightly Rust.

(Also the fact that the latter changes the type means a large part of existing third-party code as well as a bunch of code in libstd itself becomes unusable if you want to use a type-level custom allocator because they only work with `Box`. But that's a different discussion...)

>An object Y pointed by pY must live longer than object X.

Yes, the py field in Rust would use a reference type instead of a pointer, and the reference would need to have a lifetime annotation, and the compiler would work to prevent the situation you describe:

    struct X { py: &'a Y }

    let y = Y { ... };
    let x = X { py: &y };
    drop(y); // error: y is borrowed by x so it cannot be moved.
But to be clear, the `'a` lifetime syntax is not what's making this work. What's making this work is that the compiler tracks the lifetimes of references in general. This works in the same way even though there are no lifetime annotations:

    let y: String = "a".to_owned();
    let x = &y;
    drop(y); // error: y is borrowed by x so it cannot be moved.
    do_something_with(x);
The explicit lifetime annotations are just for a) readability, and b) because sometimes you want to name them to be able to express relationships between them. Eg if two lifetimes 'a and 'b are in play and you want to express that 'a is at least as long as 'b, then you have to write a `'a: 'b` bound. In many cases they can be omitted and the compiler infers them automatically.

Re: Cake – C23 and Beyond (2023)

#112
post #53

Earlier quoted context omitted.

huh? There are also security bugs in Rust, so it is theatre as well? Pointer ownership could eliminate a class of bugs. And such an approach can be combined with run-time checks for bounds and signed overflow, and then you have a memory-safe C more or less (some minor pieces are still missing, but nothing essential),

Memory safety is what we should be aiming for. I don't personally like Rust, I believe Rust achieves this. In Rust, if you don't use the unsafe escape hatch, then your bugs are at worst logic bugs. There won't be any kind of weirdness like that you got some math wrong in an array access and now all of a sudden an attacker can make your program execute arbitrary code. On the other hand, this Cake thing just adds some…

Rust does the same thing, though? If you are having trouble pleasing the compiler, you can use unsafe to get around it. Of course, the Rust people are a lot more active at telling you that what you wanted was actually wrong and bad, but it's essentially the same position.

Re: Cake – C23 and Beyond (2023)

#113

Earlier quoted context omitted.

Thanks for the rust sample. It looks very similar. Can the allocator be customized? As I said I am not Rust specialist. Also, in my understanding is that in Rust, sometimes a dynamic state is created when the object may or may not be moved. In cake ownership this needs to me explicit ( and the destructor is not generated) I also had a look at Rust in lifetime annotations. This concept may be necessary but I am avoidi…

>Can the allocator be customized? `Box ` is the type of an owning pointer that uses the default global allocator, and `Box ` is the type of an owning pointer that uses an allocator of type `A`. The latter is unstable, ie it can only be used in nightly Rust. (Also the fact that the latter changes the type means a large part of existing third-party code as well as a bunch of code in libstd itself becomes unusable if yo…

(question about rust.. this is not implemented in cake yet)

Let's say I have to objects on the heap. A and B. A have a "view" to B.

Then we put a prompt for the user. (or dynamic condition) "Which object do you want to delete first A or B?" Then user select B. How this can be checked at compile time?

Re: Cake – C23 and Beyond (2023)

#114

Earlier quoted context omitted.

> Fundamentally, if you write a wrapper around memory management that keeps track of allocated resources, much in the same way how rust includes some runtime code during compilation for memory safety, you gain the same functionality. Can you substantiate that? There are commonly employed tracking allocators, such as ASAN that can catch certain kinds of UB, and UBSAN other, and with special interpreters you can catch…

>so this part "same way how rust includes some runtime code during compilation for memory safety" is factually wrong. RefCell includes runtime code. Fundamentally, because of Rice Theorem, the compiler cannot predict the state of memory at all points in time, so runtime checks are needed. >Can you substantiate that? I mean, double free relies on using free() twice. Mempool malloc()'s once, and free()'s once at exit.…

Is anyone using this at scale and having success with avoiding all memory safety problems, just use mempool trust me bro. I made a copy of the thing the mempool pointer points to and that wasn't zeroed by free, I now have UAF, just use mempool trust me bro. I was using C for performance, I now have double pointer indirection everywhere, just use mempool trust me bro. I went out-of-bounds, just use mempool trust me bro. I violated strict aliasing, just use mempool trust me bro. I violated pointer provenance, just use mempool trust me bro. My program uses more than one thread, just use mempool trust me bro.

LOL

Re: Cake – C23 and Beyond (2023)

#115

Earlier quoted context omitted.

Memory safety is what we should be aiming for. I don't personally like Rust, I believe Rust achieves this. In Rust, if you don't use the unsafe escape hatch, then your bugs are at worst logic bugs. There won't be any kind of weirdness like that you got some math wrong in an array access and now all of a sudden an attacker can make your program execute arbitrary code. On the other hand, this Cake thing just adds some…

Rust does the same thing, though? If you are having trouble pleasing the compiler, you can use unsafe to get around it. Of course, the Rust people are a lot more active at telling you that what you wanted was actually wrong and bad, but it's essentially the same position.

No, it's not the same position, because you can write a lot of Rust code without ever using unsafe.

Re: Cake – C23 and Beyond (2023)

#116

Earlier quoted context omitted.

>Can the allocator be customized? `Box ` is the type of an owning pointer that uses the default global allocator, and `Box ` is the type of an owning pointer that uses an allocator of type `A`. The latter is unstable, ie it can only be used in nightly Rust. (Also the fact that the latter changes the type means a large part of existing third-party code as well as a bunch of code in libstd itself becomes unusable if yo…

(question about rust.. this is not implemented in cake yet) Let's say I have to objects on the heap. A and B. A have a "view" to B. Then we put a prompt for the user. (or dynamic condition) "Which object do you want to delete first A or B?" Then user select B. How this can be checked at compile time?

The code path that drops B will not compile unless that code path drops A first. It doesn't matter if that code path is in response to user input or not. Again, as I said, the point is that the compiler tracks the lifetime of all references. In this case A contains a reference to B, so any code that drops B without dropping A will not compile.

Re: Cake – C23 and Beyond (2023)

#117
post #52

Earlier quoted context omitted.

> If you are talking about a very naive version of mempool, then you are correct, but thats why I said a good implementation. No true Scotsman. > The whole point of a good mempool is that you malloc once, and only call free when you exit the program. The data structures for memory allocation will never get corrupted. And the memory pool will never release chunk twice cause it keeps tracks of allocated chunks. Then yo…

Its not about comparing implementations, its about the fact that a correct mempool implementation solves the problem without need for complex borrow checkers. For example, in that implementation, you request memory from a mempool, it returns a chunk-struct with the pointer to allocated memory, the size of the chunk, and optionally some convenience functions for safe access (making sure that the pointer is not increme…

> You can of course write code that bypasses all those checks, but in Rust, thats equivalent to using unsafe when you wanna be lazy.

The difference is that most of the Rust ecosystem is set up to allow you to not use unsafe. Whereas whenever you use a library in C, you need to pass it a pointer, so bypassing these checks has to be routine. (Note that the article claims as a key merit that it's possible to add annotations to existing libraries)

> When you release the chunk, it zeros out the pointer in the chunk-struct. Now any access to it will cause a segfault.

Only if you're very lucky. Null pointer dereference is undefined behaviour, so it may cause a different thread to segfault on a seemingly unrelated line, or your program may silently continue with subtly corrupted state in memory, or...

> Also you could argue that Rust is better because instead of segfaulting, the check will be caught during compile time, which is true but only for fairly simple programs. Once you start using RefCells, you cannot guarantee everything during compile time.

Using RefCells should be (and, idiomatically, is) the exception rather than the rule. And incorrect use of RefCell results in a safe panic rather than undefined behaviour.

Re: Cake – C23 and Beyond (2023)

#118
post #98

Earlier quoted context omitted.

If you want to keep doing programming in a way you are already familiar with, and are not willing to change your way of thinking about programs, yes then it's a bad fit. If you want to write reliable programs, there is evidence that changing the way we think about and express programming problems, can have substantial effects on reliability.

You don't need a borrow checker to write reliable programs. If anything the Rust obsession with memory safety has been harmful since it detracts from general safety. But don't take my word for it, maybe consider what the co-author of The Rust Programming Language, 2nd edition has to say [1]. If you really care about writing robust programs then focus on improving your testing methodology rather than fixating on the p…

I said that it is necessary, but not sufficient. That does not mean it's a distraction: that means it is foundational.

Re: Cake – C23 and Beyond (2023)

#119
post #77

Earlier quoted context omitted.

> I think that ownership for C is gross CVEs are gross. How do you prove your code is free from use-after-free and so on?

Don't have to if I use isoheaps.

You can still use-after-free in an isoheap, you're just reusing a freed object of the same type.

Re: Cake – C23 and Beyond (2023)

#120
post #117

Earlier quoted context omitted.

Its not about comparing implementations, its about the fact that a correct mempool implementation solves the problem without need for complex borrow checkers. For example, in that implementation, you request memory from a mempool, it returns a chunk-struct with the pointer to allocated memory, the size of the chunk, and optionally some convenience functions for safe access (making sure that the pointer is not increme…

> You can of course write code that bypasses all those checks, but in Rust, thats equivalent to using unsafe when you wanna be lazy. The difference is that most of the Rust ecosystem is set up to allow you to not use unsafe. Whereas whenever you use a library in C, you need to pass it a pointer, so bypassing these checks has to be routine. (Note that the article claims as a key merit that it's possible to add annotat…

Null pointer dereference in the vast majority of cases will segfault. In the cases where it doesn't, thats fully on you for running some obscure os on some obscure hardware.

>Whereas whenever you use a library in C, you need to pass it a pointer,

When it comes to developing with Rust, any performance oriented project is necessarily going to have lots of unsafe for interacting with C libraries in the linux kernel in the same way that C code does.

As for comparison to fully safe Rust code outside the unsafes, you can largely accomplish analogous behavior in C with good mempool implementation. Or if you don't need to pass around huge amount of data, you can also do it by simply just never mallocing and using stack variables. There is still some things you have to worry about (using safe length bounded memory copy/move functions, using [type]* const pointer values to essentially make them act like references for function parameters, some other small things).

The point is Rust isn't the defacto standard for memory safety, and while it can exist as its own project, porting its semantics to other languages is not worth it.

Post reply on HN