Earlier quoted context omitted.
Say more about isoheaping and how it helps? Is this related to arena allocation? A quick search doesn't find anything on this. Thanks.
One heap per type. Here’s an allocator optimized for that use case. https://github.com/WebKit/WebKit/blob/main/Source/bmalloc/li...
Cake – C23 and Beyond (2023)
21–30 of 128 posts
Re: Cake – C23 and Beyond (2023)
#22I think that ownership for C is gross. It's hard to convert code to something like this. 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). 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?
Re: Cake – C23 and Beyond (2023)
#23Earlier quoted context omitted.
It’s hard to imagine that ownership composes all that well.
The real experience so far is the cake source itself.
FILE* open_file(const char* p) {
FILE* owner f = …
return f;
}
Now open_file callers would need to know that ownership is being returned which means that local variables would need to have the owner annotation propagated. That’s what I mean when I say it’s not composable - the ownership has to propagate fully throughout the codebase for a specific resource. Of course maybe you know better as this is just an initial glimpse on my part.Re: Cake – C23 and Beyond (2023)
#24Earlier quoted context omitted.
This doesn’t help for a lot of things, including some of the examples described in the article. For example trying to segregate file descriptors (or similar resource handles) to an isolated heap would be mostly worthless because a UAF through a “stale reference” would let you mess with a completely different file. In general the problem of figuring out which objects are safe to confuse with each other is very difficu…
Sure ownership protects against more things. But some coding patterns are impossible under it.
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.
Re: Cake – C23 and Beyond (2023)
#25Earlier quoted context omitted.
The analysis can be disabled or silenced in some functions. the "static state" also can be override. (see the realloc sample) Because this is C, the programmers can do wherever they want, but before it must do some negotiation with the static analysis.
I’d rather just have memory safety. 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.
Re: Cake – C23 and Beyond (2023)
#26Earlier quoted context omitted.
Sure ownership protects against more things. But some coding patterns are impossible under it.
> Sure ownership protects against more things. But some coding patterns are impossible under it. 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
#include
#include
#include
#include
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);
}Re: Cake – C23 and Beyond (2023)
#27> If this can be reasonably retrofitted to existing libraries and projects
That's the problem.
If you want to fool around in this space, consider revisiting C++ to Rust conversion. There's something called Corrode, which compiles C to a weird subset of Rust full of objects that implement C raw pointers. The output is verbose and unmaintainable. What's needed is something that can figure out how big things are and who owns what, possibly guessing, and generate appropriate ideomatic Rust. Now that LLMs are sort of working, that might be possible.
Can you ask Github Co-pilot to look at C code and answer the question "What is the length of the array 'buf' passed to this function"? That tells you how to express the array in a language where arrays have enforced lengths, whicn includes both C++ and Rust. With hints like that, ideomatic translation becomes possible. Bad guesses will result in programs that subscript out of range, which is caught at run time. But guesses should be correct most of the time, because C programmers tend to use the same idioms for arrays with lengths. Forms such as "int read(int fd, char* buf, size_t buf_l)" show up often.
Using LLMs to help with tightening up existing code might work.
Re: Cake – C23 and Beyond (2023)
#28Earlier quoted context omitted.
I’d rather just have memory safety. 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.
Everything related to safety is on my list. (the list is big) I think big problems can be broken down into smaller ones.
Re: Cake – C23 and Beyond (2023)
#29Earlier quoted context omitted.
The real experience so far is the cake source itself.
Not sure I agree with that premise as the cake source would have been written in a way to be compatible with ownership annotations from the get go vs retrofitting an existing codebase. Help me understand how something like this composes: FILE* open_file(const char* p) { FILE* owner f = … return f; } Now open_file callers would need to know that ownership is being returned which means that local variables would need t…
To fix we need to add qualifier owner at return type.
FILE* owner open_file(const char* p) {
FILE* owner f = …
return f;
}
Then when returning f , f is moved. Because f was moved the compiler will not complain at the end of scope of f.https://thradams.com/cake/playground.html?code=I2luY2x1ZGUgP...
Re: Cake – C23 and Beyond (2023)
#30If that's correct, then this is somewhat practically limited: either pre-existing codebases will need to be retrofitted with an essentially bespoke set of macros, or the compiler will need to be "fail open" by default. The tradeoffs between these two are hard (substantial developer pain versus being ineffective against the bulk of a compiled program's API surface).
(Also, this design appears to be for temporal safety only, not spatial safety. But again I might have missed something.)