Live data from Hacker News

Cake – C23 and Beyond (2023)

thradams.com

21–30 of 128 posts

Re: Cake – C23 and Beyond (2023)

#21

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...

The ownership works for non pointers. We can have integers (handles) that are owners. This allow custom allocators for instance. The concept of owner is some value that works as reference to an object and manages its lifetime.

Re: Cake – C23 and Beyond (2023)

#22

I 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?

No benefits other than safety.

Re: Cake – C23 and Beyond (2023)

#23

Earlier quoted context omitted.

It’s hard to imagine that ownership composes all that well.

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 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)

#24

Earlier 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.

> 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)

#25

Earlier 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.

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)

#26

Earlier 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.

It works in both ways. We can just tell the compiler to ignore some function. We can be also creative writing the code that at same time is good and makes the static analysis happy. A good sample is linked lists.

    #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
C safety addons like this (there have been many) is that they don't prevent extracting raw pointers from controlled pointers. Optional memory safety isn't.

> 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)

#28

Earlier 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.

I don't think it's very compelling to convert C code to a thing that gives you a safety half-measure. You'll still have security bugs, so it'll just feel like theatre.

Re: Cake – C23 and Beyond (2023)

#29

Earlier 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…

This code will not compile because we cannot return owner as non owner.

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)

#30
I might be missing something, but this seems to require ownership annotations on all functions, e.g. a compatible and correct prototype for `fclose` to correctly note that the owned `FILE *` is moved into the call.

If 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.)

Post reply on HN