But you could get most of the benefit by just isoheaping (strictly allocate different types in different heaps).
But you could get most of the benefit by just isoheaping (strictly allocate different types in different heaps).
Because this is C, the programmers can do wherever they want, but before it must do some negotiation with the static analysis.
If all you give me is half measures, then I’ll either just use plain old C/C++ or I’ll switch to a totally different language. Maybe one with a GC so I don’t have to please some ownership thingy.
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),
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 ownership and when folks say it's problemmatic the first answer is "oh just tell it to ignore your function". That doesn't sound like memory safety to me. It's nowhere near Rust in that regard.
Here is a blog post that explains this in more detail https://without.boats/blog/notes-on-a-smaller-rust/.
If you really care about writing robust programs then focus on improving your testing methodology rather than fixating on the programming language.
[1] https://steveklabnik.com/writing/memory-safety-is-a-red-herr...
Not saying we shouldn't change anything.
I am saying that adding ownership is't the change that's needed, since you won't be able to convert most C code to that regime.
I don't think it's a misconception. When I tried Rust I tried to implement a cyclic data structure but couldn't because there is no clear "owner" in a cyclic data structure. The "safe" solution recommended by the rustaceans was to use integer handles. So, instead of juggling pointers I was juggling integers which made the code harder to debug and find logic errors. At least when I was troubleshooting C I could rely on the debugger to break on a bad pointer, but finding where an integer became "bad" was more time consuming.
> When in my experience it changes the way you model programs.
Having to rearchitect my code to please the borrow checker gave me flashbacks to Java where I'd be forced to architect my code as a hierarchy of objects. In both languages you need design patterns and other work-arounds since both force a specific model onto your code whether it makes sense or not.
I've developed production code in C, C++, Rust, and several other languages. And while like pretty much everything, there are situations where it's not a good fit, I find that the solutions tend to be the most robust and require the least post release debugging in Rust. That's my personal experience. It's not hard data. And yes occasionally it's annoying to please the compiler, and if there were no trait constraints or borrow rules, those instances would be easier. But way more often in my experience the compiler complained because my initial solution had problems I didn't realize before. So for me, these situations have been about going from building it the way I wanted to -> compiler tells me I didn't consider an edge case -> changing the implementation and or design to account for that edge case. Also using one example, where Rust is notoriously hard and or un-ergonomic to use, and dismissing the entire language seems premature to me. For those that insist on learning Rust by implementing a linked list there is https://rust-unofficial.github.io/too-many-lists/.
Seems like you made a passive-aggressive presumption.
In Rust you're told that if it's impossible under ownership then you should find a different way to express it rather than trying to circumvent ownership. I guess it's different in C.
#include <ownership.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
struct node {
char * owner text;
struct node* owner next;
};
struct list {
struct node * owner head;
struct node * tail;
};
void list_append(struct list* list, struct node* owner node)
{
if (list->head == NULL) {
list->head = node;
}
else {
assert(list->tail->next == 0);
list->tail->next = node; //ZERO OVERHEAD
}
list->tail = node;
}
void list_destroy(struct list* obj_owner list)
{
struct node * owner p = list->head;
while (p) {
struct node * owner next = p->next;
free(p->text);
free(p);
p = next;
}
}
void list_print(const struct list* list)
{
const struct node * p = list->head;
while (p) {
printf("%s ", p->text);
p = p->next;
}
}
int main()
{
struct list list = {};
struct node * owner p = calloc(1, sizeof * p);
if (p) {
p->text = strdup("item1");
list_append(&list, p);
}
list_print(&list);
list_destroy(&list);
}Here’s an allocator optimized for that use case.
https://github.com/WebKit/WebKit/blob/main/Source/bmalloc/li...
The experience is similar to changing a header file to use a const argument where previously the argument was non-const. This change will propagate everywhere.
I also think a similar experience is converting JavaScript to typescript. The type system will complain before it stabilizes.
As in, running nothing but memory-safety-ified C code down to the syscall boundary?
The cake source itself is moving to another experimental feature that is nullable types.
Similar of C# https://learn.microsoft.com/en-us/dotnet/csharp/nullable-ref...
Can you elaborate on this? I've been reading up on memory allocation algorithms and most of them seem to favor segregation of blocks by element size instead. Are there additional benefits to coming up with a complex typing scheme for a custom memory allocation interface?
CVEs are gross. How do you prove your code is free from use-after-free and so on?