27 ms·
Note that using this will likely violate strict aliasing due to using the void pointer returned as one type, freeing it, and then getting that same chunk again
by accelbred 2y ago
Note that using this will likely violate strict aliasing due to using the void pointer returned as one type, freeing it, and then getting that same chunk again and using it as another type. You'll probably want to compile with -fno-strict-aliasing to be safe.
A good reference on strict aliasing: https://gist.github.com/shafik/848ae25ee209f698763cffee272a58f8 https://gist.github.com/shafik/848ae25ee209f698763cffee272a5...
- leni536 2y agoThat's what allocators do. If C's object model doesn't allow users of the language to write their own allocators then that object model is broken. C++ relatively has fixes to allow allocators to work, it requires calls to std::launder.
- dwattttt 2y agoI understand the C standard hides such actions behind a wall of "this is the allocator", and expected the compiler authors to also be the allocator authors, allowing them to know when/how they can break such rules (in the context of their own compiler)
- unwind 2y agoNo, allocators are not magic (in that regard) in C. There is nothing out of the ordinary going on with an allocator, the parent comment is simply mistaken (as pointed out by another answer).
- dwattttt 2y agoAh, I see that it's because the char type never violates Strict Aliasing. I was wondering how you could define a type such as Chunk, yet hand out a pointer to it to a user who will cast it to some other type.
- SleepyMyroslav 2y agoWell the pool code fails to use char* type to write inside block of memory. If you look at 'pool_free' code you can see that it receives used block from user as 'ptr' then casts it to 'Chunk pointer' and writes to into Chunk member value of type 'Chunk pointer'. I had to change that line to memcpy when I did it last time around 15 years ago in C++ with GCC 4.something. In short if you are writing your own allocators you need either to disable strict aliasing like Linux does or do the dance of 'memcpy' when you access memory as 'internal allocator structures' right after it was used as user type. When it happened to me write was reordered and I observed code that writes into Chunk* next executed first and write of zeros into user type second.
- uecker 2y agoNote that C++ has different rules than C. C has type changing stores that do not require memcpy for allocated storage (i.e. no declared type). Older compilers have plenty of bugs related to TBAA though. Newer versions of GCC should be ok.
- pjmlp 2y agoWhich is why pointer provenance is an issue as well.
- alextingle 2y agoThere's no reason an allocator should ever trip over strict aliasing rules. malloc() returns an address. The user code writes a value, and then reads a value of the same type. No problem. Later, malloc() returns the same address. The user code writes a value of another type then reads a value of that same type. Again, no problem. There's no aliasing going on here. The act of writing a value of a different type tells the compiler that the lifetime of the previous object has ended. There's no special magic required. Strict aliasing is about situations where we write a value of one type, and then attempt to read a value of a different type from the same location. If you want to do that, then you have to be extremely cautious. But memory allocators don't do that, so it's not an issue. (Obviously just talking about C here, or POD in C++ terms. If you are dealing with C++ objects with destructors, then you have an extra layer of complexity to deal with, but again that's nothing to do with aliasing.)
- clairebyte 2y ago>The act of writing a value of a different type tells the compiler that the lifetime of the previous object has ended. afaik only memcpy has that magic property, so I think parent is almost correct. void *p = malloc(n); *(int *)p = 42; // ok, *p is now an int. //*(float *)p = 3.14f; // I think this is not allowed, p points to an int object, regular stores do not change effective type float x = 3.14f; memcpy(p, &x, sizeof(float)); // but this is fine, *p now has effective type float So in the new, pool_new: pool->chunk_arr[i].next = &pool->chunk_arr[i + 1]; This sets the effect type of the chunk block to 'Chunk' Later in pool_alloc: Chunk* result = pool->free_chunk; ... return result; result has effective type 'Chunk' In user code: int *x = pool_alloc(); *x = 42; // aliasing violation, *x has effective type 'Chunk' but tried to access it as an int* User code would need to look like this: int *x = pool_alloc(); memcpy(x, &(int){0}, sizeof(int)); // establish new effective type as 'int' // now we can do *x = 42;**
- bigpingo 2y agoAnd this is why type based alias analysis (TBAA) is insane and why projects like linux complies with fno-strict-aliasing. C should issue a defect report and get rid of that nonsense from the standard.
- deleted 2y ago[deleted]