I mean you can't even write an allocator in standard C.
I mean you can't even write an allocator in standard C.
I might be missing something, but I don't believe this is true? The type aliasing rules have an explicit carve-out for `char *` aliases of other types, which is intended to solve this exact issue.
Similarly, C99 and C11 both allow aliasing through a union of pointers without violating the strict aliasing rule.
malloc itself is specified to return a void pointer, but the effective type established during assignment circumvents what would otherwise be UB via aliasing[2].
Edit: Specifically, the reasoning is:
1. Allocated objects have no declared type;
2. 6.5.6: Objects with no declared type have the type of their accessing lvalue
3. 6.5.7: Access of a stored value is valid for lvalue expressions that are type compatible with the effective type.
So there's no UB here. `malloc` itself doesn't need to know about the effective type produced by the lvalue, and C (at least C99 onwards) respects that type for strict aliasing purposes.
> The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object.
If the implementation of malloc is visible, then it can be inlined etc., and then you have to deal with the effects of this obviously not being true.
#include <stdlib.h> /* for size_t */
static char data_storage[10000000];
static char *nextp = data_storage;
void *malloc(size_t size)
{
void *p = nextp;
nextp += size;
return p;
}
void free(void *p){}More context around your quote:
> The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object.
https://port70.net/%7Ensz/c/c11/n1570.html#7.22.3
In context, I take that to mean that all allocated objects must be disjoint from one another throughout their lifetime. It wouldn't make sense otherwise.
Yes, plus if you call it twice it returns two pointers to the same object, because there's no way in C to create another "object". Of course, as long as the callers don't know this it's fine, but it would be a problem if eg you compile your custom malloc with ASAN/Valgrind and don't tell it that it's a malloc.
I think C++ partially addresses this with "placement new" but not sure how far.
How are you defining an object? This draft version of the C11 spec defines 'object' as a "region of data storage in the execution environment, the contents of which can represent values". https://port70.net/%7Ensz/c/c11/n1570.html#3.15
malloc is defined to return a pointer to a new "base object". But your code doesn't do that; you can see by reading it that it returns a pointer to `data_storage`. That means the UB conditions for using that pointer don't match the spec.
You could say it's supposed to magically work if the function is named `malloc`, but my understanding of all C implementations is they don't do that.
That is why I tend to always write ISO C instead of C.
And I'm not sure I understand why you're using the inability to describe certain actions as the reason why you use ISO C.
(A syscall is an example of "something you can only do because the implementation isn't visible to the caller" - it can violate aliasing that way.)
Also, my argument isn't about type aliasing, it's about UB on out of bounds pointers. Could be some other aliasing issues though.