←back to thread

GCC 15.1

(gcc.gnu.org)
270 points jrepinc | 8 comments | | HN request time: 1.062s | source | bottom
Show context
Calavar ◴[] No.43792948[source]
> {0} initializer in C or C++ for unions no longer guarantees clearing of the whole union (except for static storage duration initialization), it just initializes the first union member to zero. If initialization of the whole union including padding bits is desirable, use {} (valid in C23 or C++) or use -fzero-init-padding-bits=unions option to restore old GCC behavior.

This is going to silently break so much existing code, especially union based type punning in C code. {0} used to guarantee full zeroing and {} did not, and step by step we've flipped the situation to the reverse. The only sensible thing, in terms of not breaking old code, would be to have both {0} and {} zero initialize the whole union.

I'm sure this change was discussed in depth on the mailing list, but it's absolutely mind boggling to me

replies(14): >>43793036 #>>43793080 #>>43793121 #>>43793150 #>>43793166 #>>43794045 #>>43794558 #>>43796460 #>>43798312 #>>43798826 #>>43800132 #>>43800234 #>>43800932 #>>43800975 #
1. ryao ◴[] No.43793080[source]
> This is going to silently break so much existing code

How much code actually uses unions this way?

> especially union based type punning in C code

I have never done type punning via the GNU C compiler extension in a way that would break because of this. I always assign a value to it and then get out the value from a new type. Do you know of any code that does things differently to be affected by this?

replies(3): >>43793142 #>>43793164 #>>43793474 #
2. Calavar ◴[] No.43793142[source]
I would guess a lot. People aren't intimately familiar with the standard, and people are lazy when it comes to writing boilerplate like initialization code. And up until now, it just worked, so even a good test suite wouldn't catch it.

EDIT: I initially mentioned type punning for arithmetic, but this compiler change wouldn't affect that

replies(1): >>43793170 #
3. ndiddy ◴[] No.43793164[source]
> How much code actually uses unions this way?

I see this change caused Mbed-TLS to start failing its test suite when compiled with GCC 15: https://github.com/Mbed-TLS/mbedtls/issues/9814 (kinda scary since it's a security library). Hopefully other projects with less rigorous test suites aren't using {0} in that way. The Github issue mentions that Clang tried a similar optimization a while ago and backed it out after user complaints, so maybe the same thing will happen with GCC.

replies(1): >>43793184 #
4. ryao ◴[] No.43793170[source]
How would that be broken by this? The union will be zero initialized regardless because this change only affects situations where the union members are of different lengths, but for integer to float, the union members should always be the same length or bad things will happen.
replies(1): >>43793207 #
5. ryao ◴[] No.43793184[source]
GCC’s developers have a strong insistence on standards conformance (minus situations where they explicitly choose to deviate, like type punning in unions) over the status quo. We already went through a much more severe shift with strict aliasing enforcement by GCC and they never changed course. I do not expect this to be any different.
6. Calavar ◴[] No.43793207{3}[source]
I realized my mistake and I think I edited my comment a split second before you replied, but you're right. That particular type punning scenario wouldn't be affected by this change because 1) the members are the same size, so there's no padding bits 2) the specific union member is going to be initialized to the input parameter, not with the syntax sugar for aggregate zero initialization.
replies(1): >>43793266 #
7. ryao ◴[] No.43793266{4}[source]
Well, under your original version, I could see someone filling in bit fields in the float like the exponent and sign while leaving the mantissa zeroed, but given that the integer and float would be the same length, there is no section that would be left uninitialized by this change.

In order for this change to leave something uninitialized, you would need to have a member of the union after the first member that is longer than the first member. Code that does that and relies on {0} to zero the union seems incredibly rare to me.

8. ◴[] No.43793474[source]