Standard C is not suitable for writing kernels anymore due to all the ridiculous hostile interpretions of the standard (mainly typed based aliasing rules).
I mean you can't even write an allocator in standard C.
Both sides are true IMO. The kernel isn't capable of being written totally in standards compliant C, and it'd probably be better off if that fact wasn't used as carte blanche to write non standards compliant code where it doesn't provide a tangible benefit.
> 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.
You can't implement `malloc()` in C because the pointers it returns are defined to be pointers to different objects, and if you can see the implementation of `malloc` then you know it's returning pointers to the same object (the page it gets from mmap/sbrk). There's no functionality in C to actually do what it says except for the function itself.
My understanding is that this is covered by the "effective type" language in both C99 and C11[1].
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.
This does not "yield a pointer to an object disjoint from any other object". So it only works if the implementation is not visible to callers and they can pretend it's compliant.
Huh? My version never returns a pointer to space that was already allocated because it never deallocates anything. So the objects are ALWAYS disjoint from every other object. Or are you concerned that they are aliased with the static 'data_storage' char array?
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.
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.
> So the objects are ALWAYS disjoint from every other object. Or are you concerned that they are aliased with the static 'data_storage' char array?
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.
Then in this case the portability offered by C is false. Could be an equally valid approach to place the required behavior into separate modules written with an assembler.