And wouldn't it be nice to just make them keep one number! That's a size_t and a couple of cycles saved for every malloc()!
I will say, this is not some far-out niche idea of mine, it's basically universal for all "new" implementations of memory allocators to require exactly this information for deallocation. There's a reason Zig allocators take a slice and not a pointer [0], why std::pmr::polymorphic_allocator::deallocate takes a size [1] and why Rust allocators require it as well (in the layout param) [2]. It's just a better API design.
EDIT: for C++, the better reference is the Allocator named requirement, which the polymorphic allocator is just one example of. But you can see it there as well in the deallocate() method [3]
[0]: https://ziglang.org/documentation/master/std/#std.mem.Alloca...
[1]: https://en.cppreference.com/cpp/memory/polymorphic_allocator...
[2]: https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html#t...
You can make them keep basically zero numbers per allocation; most modern mallocs use size classes, and can pack objects of the same size class tightly with no metadata inbetween. (You still need some numbers per page/span and such.)