@@ -362,8 +362,8 @@ In memory, it would look something like this:
362
362
``` bash
363
363
Memory:
364
364
[00][00][00][00][00][00][00][00]
365
- ^^^^^^^^ first 4 bytes = float f
366
- ^^^^^^^^^^^^^ rest 4 bytes = padding / start of double d
365
+ ^^^^^^ ^^^^^^^^ first 4 bytes = float f
366
+ ^ ^^^^^^^^^^^^^ rest 4 bytes = padding / start of double d
367
367
368
368
Result:
369
369
- Full 8 bytes cleared to 0
@@ -403,8 +403,8 @@ In memory, it would look something like this:
403
403
``` bash
404
404
Memory:
405
405
[00][00][00][00][?? ][?? ][?? ][?? ]
406
- ^^^^^^^^ first 4 bytes = float f
407
- ^^^^^^^^^^^^^ remaining 4 bytes = untouched
406
+ ^^^^^^ ^^^^^^^^ first 4 bytes = float f
407
+ ^ ^^^^^^^^^^^^^ remaining 4 bytes = untouched
408
408
409
409
Result:
410
410
- First 4 bytes (float f) zeroed.
@@ -494,8 +494,10 @@ mov [rax], rcx # copy full 8 bytes
494
494
495
495
Essentially, Clang is zero'ing the 4 byte float, but then it goes ahead and
496
496
` memset ` 's the rest of the union resulting in behavior similar to the older
497
- versions of GCC. It is almost as if the two compiler teams switched opinions on
498
- how this should be implemented!
497
+ versions of GCC. I am guessing this is to make sure the entire memory region
498
+ is zeroed out. TO me, it is almost as if the two compiler teams switched
499
+ opinions on how this should be implemented with GCC now only clearing the first
500
+ member, and Clang now clearing out the entire region.
499
501
500
502
For anyone who wants to verify this, I created some godbolt links.
501
503
@@ -505,10 +507,10 @@ For anyone who wants to verify this, I created some godbolt links.
505
507
## Where GCC Breaks Historical Behavior
506
508
507
509
So here is where we get to the main point of the issue. For over a decade, C
508
- devs have expected ` {0} ` to fully clear unions. Type punning is allowed in the
509
- newer C standards, and compilers have gone to great lengths to try to maintain
510
- memory safety by adhering to expected behavior, even if it is undefined or
511
- unspecified.
510
+ devs have expected ` {0} ` to fully clear unions. Type punning appears to be
511
+ allowed, at least to some degree, in the newer C standards, and compilers have
512
+ gone to great lengths to try to maintain memory safety by adhering to expected
513
+ behavior, even if it is undefined or unspecified.
512
514
513
515
The latest change in GCC's handling of this breaks what I consider to be
514
516
historical behavior, and it might lead to some interesting bugs that begin to
@@ -529,11 +531,13 @@ I completely understand why the GNU GCC team is allowed to do this given how
529
531
the spec reads. Many GCC devs claim that
530
532
[ type punning via unions is undefined] ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118141#c13 ) .
531
533
There's also no such thing as truly historical behavior in the spec. However,
532
- there are certain things programmers rely on to be valid, even if they aren't
533
- well-defined. This is one of those cases where I think the compiler team might
534
- want to re-evaluate their decision, or at the very least present a solid
535
- argument as to why they are breaking away from a historical behavior that many
536
- of us have come to rely on, even if it was considered UB.
534
+ there are certain assumptions programmers rely on to be valid, for better or
535
+ for worse, even if they aren't well-defined. I really do believe this is one of
536
+ those cases where I think the compiler team might want to re-evaluate their
537
+ decision on making this flag-defined behavior instead of default behavior, or
538
+ at the very least present a solid argument as to why they are shifting away
539
+ from a historical behavior that many of us have come to rely on, even if it
540
+ was considered UB.
537
541
538
542
## Further Reading
539
543
0 commit comments