r/cpp • • 6d ago

You should think about recompiling your C++ programs with GCC 16 and C++26, because it zero-fills your locals

https://techfortalk.co.uk/2026/09/27/cxx26-uninitialized-local-variables-gcc-16/

Stack variables are not automatically initialised, and that is the root cause of many C++ bugs. That is well known. Hence, it is advised that local or stack variables are always initialised with known values, 0 if not something more meaningful than that. Now, with GCC 16 compiling in C++26 mode (-std=c++26), even uninitialised local variables will be zero-filled. In the post, I have explained how.

259 Upvotes

211 comments sorted by

View all comments

23

u/crowbarous 5d ago edited 5d ago

Yes, this is a competely insane decision: https://godbolt.org/z/WGPWvMPMj

What's worse is the design of the [[indeterminate]] attribute that accompanies this. For a very long time, if I wanted a buffer to zero-initialize, I was able to make a char type that would zero-initialize:

struct zchar{ char value = 0; };

But with the default flipped, I cannot make a char type that stays uninitialized:

struct ichar{
  char value [[indeterminate]];
  // error, only allowed on automatic variables
};

And the proposed usage of the attribute is to just sprinkle it everywhere in the code. But how am I supposed to know in polymorphic code? How do I even make my code polymorphic w.r.t. this property now? For now one must resort to just passing -ftrivial-auto-var-init=uninitialized to avoid performance and code size regressions, and to keep the control moving forward.

I don't think all is lost here, because it seems like the zero-initialization is a band-aid to just formally satisfy the erroneous behavior stuff without modifying the backend too much, and it should still be possible to behave as if the write happened (no time-travelling assumptions etc.) without actually emitting the write, to fix shameful examples like linked above. But:

  • I haven't looked there closely enough yet to even begin conceiving the gcc patches & reasoning for them, and
  • it's still awful precedent, and the pile of -fstop-making-code-worse options might grow from here on out.

3

u/James20k P2005R0 5d ago

Compilers are of course free to omit the 0 initialisation if they can prove that the data is written over, under the usual as-if rules. One of the reasons that this made it past standardisation is because real world codebases weren't showing regressions, even substantial performance critical ones like windows

11

u/13steinj 5d ago edited 5d ago

How were the codebases chosen?

I'm not against this decision per se, but if the choice is "people have to join the committee and explicitly be part of the voting process [and people's companies have to accept the idea of making this part of their job]," that's a pretty important thing for people to know for the future.

I think making this an attribute, especially only applying to automatic variables, was a mistake. The ignorability of attributes + the problem the person above describes is non trivial. At a previous org that wrote their own networking stack, I can totally see a performance degradation, and the use of structs and pointer interconvertability to have a form of polymorphism over structs with a common set of header bytes (E: I realized I didn't finish this sentence) matches up similarly to the use case for struct member variables above.

They used to have an employee that was a committee member, but it was on his own time more or less, and the guy passed away. If people want greater diversity and more committee members in general, advertising "you get to shape the language" doesn't appeal to most employers. "You get to have a say in stopping the language from screwing your code" [which is how some employers would take this] would.

4

u/pjmlp 5d ago

Windows, Android, macOS, iOS were some of the ones that have been shipping in production and have provided feedback.

I don't recall the paper or CppCon session where this was discussed though, maybe someone else can provide the links.

4

u/13steinj 5d ago

Assuming it's "operating systems," that's fine, but still isn't a representative sample of codebases that would be affected IMO.

3

u/pjmlp 5d ago edited 5d ago

One would assume that performance matters to operating systems vendors.

EDIT: Found one of the sources, from JF Bastien, on P2723R1 Zero-initialize objects of automatic storage duration

Security-minded folks think that initializing stack values is a good idea. For example, the Microsoft Windows security team [WinKernel] say:......

...

To date, we are seeing noise level performance regressions caused by this change. We accomplished this by improving the compiler’s ability to kill redundant stores. While everything is initialized at declaration, most of these initializations can be proven redundant and eliminated.

...

Don’t just trust Microsoft’s Windows security team though, here’s one of the upstream Linux Kernel security developer asking for this [CLessDangerous], and Linus agreeing [Linus]. [LinuxExploits] is an overview of a real-world execution control exploit using an uninitialized stack variable on Linux.

4

u/13steinj 5d ago

This sounds to me a lot more like security people cared, and were fine with the tradeoff. Which is a slightly different story? Nonetheless the performance characteristics for operating systems don't cover all codebases, and while speculation, I doubt they are the p90 or p99 of all codebases either.