> Not only that, mfree() receives the size of the object it is deallocating, <i>as it should</i>.<p>I've always thought that one of the biggest tiny mistakes in the history of this industry. It means, more or less, that you're forcing the memory allocator to keep track of these sizes when it shouldn't have to. There's virtually no sensible case where the person calling free() doesn't know the size of the allocation, so now we're keeping that book-keeping twice, in "user-space" and inside the memory allocator. Like, think about the cases when you'd call malloc:<p>* For allocating a single object of type T, the size is just `sizeof(T)`, so you can just pass that to free()<p>* For allocating an array of objects, the size is `count * sizeof(T)`, and I can't think of a single time where you DON'T know what `count` is. It's either statically sized (in which case it's just a constant), or if you have a dynamically growing array, you need to keep track of the reserved space to know when you reallocate. If nothing else, you need it for bounds-checking.<p>* For chunks of raw memory, you also presumably know when deallocating what the size of the raw memory you allocated is, for the same reasons as the previous point. Like, just having a raw char* pointer lying around with no size information is just terrible C practice.<p>If you truly don't know the size of your allocation (very hard to imagine when this would ever happen), you should be forced on the user-side to keep track of it somehow, not delegate that to the allocator.<p>It's a tiny amount of overhead, but it's for EVERY SINGLE MEMORY ALLOCATION since like 1975. Imagine how many times malloc() and free() has called since then! How much electricity, CPU usage, and memory has been wasted! It boggles the mind!
I think this is missing the forest for the trees. The potential savings of one extra size_t per allocation are miniscule compared to the overhead of using malloc() in the first place, with a potential syscall on every allocation. If you care about waste, you should ask for those pages from the OS directly, once at init, and use arenas.
> There's virtually no sensible case where the person calling free() doesn't know the size of the allocation<p>We already have enough memory-unsafety bugs going around without making free() more difficult to use correctly as well.
Don't worry, the allocator almost never dedicates actual heap space towards storing your allocation sizes. Instead, allocations get bucketed by size, and you can derive the size by working out which bucket the allocation is in. This is cheap and the bucketing is a good strategy anyway.
"void*" sadly exists, and there are a lot of edge cases.<p>I tried using TCMalloc with rustc, and it segfaulted. Rust knows the sizes of its allocations, but things can still go wrong at the allocator boundary.<p>Size should be an optimization hint, not a correctness requirement. Otherwise, it's just another security pitfall
I don't agree. Zig allocators require the size of the allocation (technically they take a slice, but a slice is ptr + size), as does the C++ polymorphic allocator, as does many allocator interfaces in many libraries (see for instance the allocator interface in Lua, my personal favorite C interface for memory allocation [0]). Clearly having it as a correctness requirement works just fine.<p>[0]: <a href="https://www.lua.org/manual/5.4/manual.html#lua_Alloc" rel="nofollow">https://www.lua.org/manual/5.4/manual.html#lua_Alloc</a>
> "void*" sadly exists<p>But _somewhere_ you need to know what it represents, otherwise it's useless.<p>> I tried using TCMalloc with rustc, and it segfaulted. Rust knows the sizes of its allocations, but things can still go wrong at the allocator boundary.<p>Things can go wrong, doesn't mean they will go wrong due to the reasons you're thinking of.