News: 1770638822

  ARM Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life (Terry Pratchett, Jingo)

How the GNU C Compiler became the Clippy of cryptography

(2026/02/09)


FOSDEM 2026 The creators of security software have encountered an unlikely foe in their attempts to protect us: modern compilers.

Today's compilers boil down code into its most efficient form, but in doing so they can undo safety precautions.

"Modern software compilers are breaking our code," said [1]René Meusel , sharing his concerns in a FOSDEM [2]talk on February 1.

[3]

Meusel manages the [4]Botan cryptography library and is also a senior software engineer at Rohde & Schwarz Cybersecurity.

[5]

[6]

As the maintainer of Botan, Meusel is cognizant of all the different ways encryption can be foiled. It's not enough to get the math right. Your software also needs to encrypt and decrypt safely.

Writing code to execute this task can be trickier than some might imagine. And the compilers aren't helping.

Blocking the side channel

Meusel offered an example of the kind of problem he deals with implementing a simple login system.

The user types in a password, which gets checked against a database, character by character. Once the first character doesn't match, an error message is returned.

[7]

For a close observer trying to break in, the time it takes the system to return that error indicates how many letters of the guessed password the user has already entered correctly. A longer response time indicates more of the password has been guessed.

This side-channel leak has been used in the past to facilitate brute-force break-ins. It just requires a high-resolution clock that can tell the minuscule differences in response times.

Good thing cryptographers are a congenitally paranoid sort. They have already created preventive functions to equalize these response times to the user so they are not so revealing. These constant-time implementations "make the run time independent of the password," Meusel said.

Problem solved? Not if the compiler has its way

The GNU C compiler is excellent with reasoning about Boolean values. It may be too clever. Like Microsoft Clippy-level clever.

Meusel ran a constant-time implementation through GCC 15.2 (with -std=c++23 -O3).

[8]

The loop to check the character exits early when the character is correct, so GCC assumed the rest of the function wasn't needed. But the rest of the code that actually fixed the timing was jettisoned, and the side-channel vulnerability was exposed once again. Thanks, GCC.

Meusel didn't get into why C optimizers have it in for Boolean comparisons, but good C programmers know to fear the aggressive optimization of Boolean logic, which [9]can be hazardous to their finished products.

Boolean decisions mean branching, which is expensive for the hardware, so the compiler would just rather [10]turn your branchful code into branchless control-flow logic anyway, and that's cool, right?

Is that some Boolean logic you got there?

The trick is to hide the semantics of this little program from the compiler, Meusel advised.

The first step is to replace the Boolean value that the loop is given with a two-bit integer, and use some bit shift or bitwise operations to mask the input (Meusel supplies the requisite code in his talk, so check out [11]the slides for all the geeky goodness).

You would think this would do the job.

But GCC is smarter than that. It can see when you are trying to make a sneaky Boolean comparison.

So you need to apply an obfuscation function to both the input and the output. But not for any benefit to the program itself, but just because these are other values that the compiler could use "to screw us over," Meusel said.

And, finally, you need to throw the value through some inline assembly code that does absolutely nothing but return the same value. In effect it warns the compiler, which doesn't understand assembly, to not mess with these values however Boolean they may appear.

[12]Matrix is quietly becoming the chat layer for governments chasing digital sovereignty

[13]CentOS is coming to RISC-V soon if you have the kit

[14]GitHub ponders kill switch for pull requests to stop AI slop

[15]Oracle seeks to build bridges with MySQL developers

"That's how these things are done nowadays," he added.

The lot of the encryption coder

"Now you might say, 'Well, this is becoming kind of like intricate and very easy to do wrong' … and you wouldn't be wrong." Meusel said.

Can it be fair to require the average programmer to understand inline assembly, or any of these other inherently obtuse obfuscation techniques? Much less the maintainers of this software down the road? And how many more tokens would it cost for AI to wiggle through all these subterfuges?

But this is the lot of the cryptography library-coder, finding ways to shore up side-channel attacks while hiding the solutions from a ruthless compiler.

Other compilers no doubt have their own quirks as well. Who knows what horrors hide in the Intel C++ Compiler or Clang. And with each new generation of compilers come a new set of optimizations to contend with, Meusel lamented.

Know the terrain, travel in packs

There are a number of takeaways from Meusel's talk, the chief one being: maybe [16]just switch off the optimization button on GCC?

Nonetheless, compiler builders may want to consider factors other than code efficiency.

"They want to make your code fast, and they're really good at it, but they don't put any other qualitative requirements of your implementation into this consideration," Meusel said.

As one audience member suggested, perhaps one day a compiler could accept prompts that specify what areas of the code not to tinker with.

Until then, security software designers will need to keep in mind all the parts of the system they are designing, including the development tools that are used, and how they work.

For them, Meusel recommended [17]valgrind , an open source memory debugging tool. It can warn you, for instance, if your program is dependent on an undefined value.

Lastly, implementing security is hard, and not just because of the math involved. It's too hard to go alone. Don't roll your own; join a project instead, Meusel advised. ®

Get our [18]Tech Resources



[1] https://www.linkedin.com/in/reneme/

[2] https://fosdem.org/2026/schedule/event/EBZV7M-trust_the_math_fear_the_compiler_how_optimizations_undermine_cryptographic_softw/

[3] https://pubads.g.doubleclick.net/gampad/jump?co=1&iu=/6978/reg_security/front&sz=300x50%7C300x100%7C300x250%7C300x251%7C300x252%7C300x600%7C300x601&tile=2&c=2aYoSt8f-Pt9WePe5SnZWMQAAAA0&t=ct%3Dns%26unitnum%3D2%26raptor%3Dcondor%26pos%3Dtop%26test%3D0

[4] https://github.com/randombit/botan

[5] https://pubads.g.doubleclick.net/gampad/jump?co=1&iu=/6978/reg_security/front&sz=300x50%7C300x100%7C300x250%7C300x251%7C300x252%7C300x600%7C300x601&tile=4&c=44aYoSt8f-Pt9WePe5SnZWMQAAAA0&t=ct%3Dns%26unitnum%3D4%26raptor%3Dfalcon%26pos%3Dmid%26test%3D0

[6] https://pubads.g.doubleclick.net/gampad/jump?co=1&iu=/6978/reg_security/front&sz=300x50%7C300x100%7C300x250%7C300x251%7C300x252%7C300x600%7C300x601&tile=3&c=33aYoSt8f-Pt9WePe5SnZWMQAAAA0&t=ct%3Dns%26unitnum%3D3%26raptor%3Deagle%26pos%3Dmid%26test%3D0

[7] https://pubads.g.doubleclick.net/gampad/jump?co=1&iu=/6978/reg_security/front&sz=300x50%7C300x100%7C300x250%7C300x251%7C300x252%7C300x600%7C300x601&tile=4&c=44aYoSt8f-Pt9WePe5SnZWMQAAAA0&t=ct%3Dns%26unitnum%3D4%26raptor%3Dfalcon%26pos%3Dmid%26test%3D0

[8] https://pubads.g.doubleclick.net/gampad/jump?co=1&iu=/6978/reg_security/front&sz=300x50%7C300x100%7C300x250%7C300x251%7C300x252%7C300x600%7C300x601&tile=3&c=33aYoSt8f-Pt9WePe5SnZWMQAAAA0&t=ct%3Dns%26unitnum%3D3%26raptor%3Deagle%26pos%3Dmid%26test%3D0

[9] https://forums.anandtech.com/threads/why-are-aggressive-compiler-optimizations-dangerous.1216895/

[10] https://en.algorithmica.org/hpc/pipelining/branchless/

[11] https://fosdem.org/2026/events/attachments/EBZV7M-trust_the_math_fear_the_compiler_how_optimizations_undermine_cryptographic_softw/slides/267467/rmeusel_t_snpurvj.pdf

[12] https://www.theregister.com/2026/02/09/matrix_element_secure_chat/

[13] https://www.theregister.com/2026/02/05/centos_coming_to_riscv_soon/

[14] https://www.theregister.com/2026/02/03/github_kill_switch_pull_requests_ai/

[15] https://www.theregister.com/2026/01/30/oracle_mysql/

[16] https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

[17] https://valgrind.org/

[18] https://whitepapers.theregister.com/



A Non e-mouse

I'm surprised there isn't already a #pragma directive to say to the compiler: "Don't be clever here, just do as I say".

Dan 55

I'd have thought making every function and variable volatile for whatever it is you're trying to do would be enough to make the compiler not optimise out booleans, but not even then it seems.

Also, there is a #pragma GCC optimize ("-O0")... that didn't work either?

elsergiovolador

That is still unsafe. If they want certainty, they should provide assembly implementations for each architecture.

sitta_europea

"... they should provide assembly implementations for each architecture."

Came here to say the same thing.

there isn't already a #pragma directive

Bebu sa Ware

There is and I have had to use it for totally non crypto/security reasons (forcing ctor functions to run in static links.)

[gcc manual 6.62.15 Function Specific Option Pragmas]

#pragma GCC push_options

#pragma GCC optimize ("O0")

int sensitive (...) {

....

}

#pragma GCC pop_options

These attributes can also be applied with the function __attribute__() syntax as someone has also noted.

[6.31.1 Common Function Attributes]

mihares

-O3 is known to be dangerous, though.

Back in the days, it was a sure way to mess up the HEP simulations we were running.

chuckufarley

There is a section in the Gentoo handbook that specifically warns users against setting -O3 globally in the make.conf $CFLAGS. Linux From Scratch also warns against using it in their handbook. Even the GCC manual itself warns that -O3 can and will break some code because it is so aggressive.

Only one answer

steelpillow

GCAIC, the GNU Compiler AI-enhanced Collection

Re: Only one answer

Paul Herber

Is that collection on the blockchain?

Re: Only one answer

elsergiovolador

It's fully agentic and on-chain with zero trust.

Re: Only one answer

Joe W

... as a service....

Re: Only one answer

Yet Another Anonymous coward

For an extra monthly subscription fee

Re: Only one answer

Bran Muffin

And the look of real wood.

The problem here

Mishak

The problem here is that programmers are trying to get the compiler to do something it is not required to do - the C Standard defines an abstract machine that is used to execute the program, and any attempt to "force" it to do things is likely to fail. Temporal behaviour is not part of the specification, so there are no guarantees as to what will happen if the programmer is trying to write isochronic code (where the execution paths all take the same amount of time).

Any infeasible paths are likely to be removed during optimisation (which are effectively a set of mathematical transformations that are applied to the code), and "turning them off" may not remove all optimisation. Compilers are also free to "mess" with values, as long as the code behaves "as if" it was what was intended. For example, have a look at [1]this Compiler Explorer example that shows Clang "changing" the values of enum constants and "forgetting" to call an error handler (note that the code produced by Clang is fully Standard Conforming). Reducing the optimisation level to '0' does 'fix' the code (it is still broken, but the infeasibility and undefined behaviour to not manifest).

The example also shows a function that erases a password buffer before it is returned to the memory pool. The write operations used to erase the buffer are strictly unnecessary writes as the values written are never subsequently used as they are followed by a call to 'free' (and this did use to happen). However, compilers are now taking this sort of use case into consideration to help programmers - even when the behaviour is not required by the standard.

[1] https://godbolt.org/z/bMsevabdo

Optimizers optimize

The Mole

"Meusel ran a constant-time implementation through GCC 15.2 (with -std=c++23 -O3"

The -O3 is telling the compiler to to optimization and then he is complaining about it doing optimizations?

Most of the suggested options are, well dumb, they are trying to trick the optimizer with a hope that it won't get more intelligent in a later release, if you don't want the optimizer to optimize than the best thing to do is explicitly tell it not to - looks like that functionality exists by declaring the function with __attribute__((optimize("O0")))

Re: Optimizers optimize

GBE

"Meusel ran a constant-time implementation through GCC 15.2 (with -std=c++23 -O3"

The -O3 is telling the compiler to to optimization and then he is complaining about it doing optimizations?

Exactly. He told the compiler explicitly to do whatever it can to make the code run faster, and then bitches about the code running faster.

I've recently discovered a dangerous flaw in the design of my car! When I take my foot of that pedal and press it on that other pedal the car suddenly STOPS!! This could happen right in the middle of the freeway!!! People could be killed!!!! Something must be done — Think Of The Children!!!!!

That said, even when you "turn off" optimization with -O0, the C standard still allows the compiler to do anything it wants that still produces "correct behavior". The definition of "correct behavior" does NOT (and never has) included constant (or even predictable or consistent) execution times.

Anonymous Coward

Looping through each character is inefficient, especially with long keys / books for passwords. Wouldn't it be better to use a constant-time, cryptographically secure hash comparison?

Irongut

Also insecure because an attacker can try each character in turn untill they find the correct one.

Who is the security guy in the article and what are his credentials?

Can someone please explain to me ...

alain williams

We should not be comparing passwords character by character since we should not store passwords in clear text -- as it is a nightmare if/when some cracker gets hold of the password database.

We should store a hash or message digest of the password and when testing a candidate password hash/md it and compare that. Converting to a hash/md means reading *all* of the password and then comparing the result will give you no clue as to which pass of the candidate password is bad; so a timing attack will not work.

Anyway: the first step of authentication will be getting the password hash/md, very likely from a database. The time to access from a database will take vastly longer than character by character comparison.

So: I do not understand. Can someone please explain.

Thanks

Re: Can someone please explain to me ...

Anonymous Coward

@Alain_Williams

Yup......explanation is simple. Namely.....bad guys attended the FOSDEM talk........so the examples were MISDIRECTION!

Probably if legitimate programmers want THE REAL SCOOP on GNU C, they need to pay extra!

So.....not only misdirection, but a marketing ploy to get more revenue.

Is this paranoid enough? Probably not!

Re: Can someone please explain to me ...

chuckufarley

No need to pay extra when the source code is free.

Re: Can someone please explain to me ...

hrolf-kraki

Good point!

But getting the source code....and UNDERSTANDING the source code might be two different things!

Re: Can someone please explain to me ...

kmorwath

How do you compare hashes that doesn't fit wholly in a CPU register? And if the hash is stored as a string, and the code still does a string comparison?

Hashes do not allow to reconstruct the plain-text easily - but if you can probe a stored hash directly to find a match.... is not different than comparing a plain text password - the elapsed time will tell you how far you went.

Re: Can someone please explain to me ...

Claptrap314

This was clearly a simplified example. No one has done this particular thing for thirty years. Of course, no one has used O3 in this context since it came out, so maybe he is a time traveler?

'strict'

Chris Gray 1

It's been a long time, but doesn't Fortran have a rule that says something about evaluation inside parentheses cannot be moved outside of those parentheses? I believe it related to evaluation of expressions involving very small floating point values.

Because of that I long ago put a 'strict' construct into my Zed programming language. The intent is that stuff directly within the range of the construct must be executed as they appear. There were a couple of provisos needed, but something like this would seem to be more reliable and universal than things like setting the optimization level of an entire C function. Maybe for C30? (Kidding!)

sitta_europea

So ... security is hard?

Who'd have thought it?

"password, which gets checked against a database, character by character"

Bebu sa Ware

Hopefully only a straw man for this example otherwise I am not too sure I would want M. Meusel lurking in the vicinity of my code.

I assume (purely because I would leave this sort of coding to those that know how to do it safely) that the clear text password would be read into secure memory (mlocked/mprotected ?) in its entirety before being hashed etc and verified with the clear text obliterated at the earliest opportunity.

The timing for a successful verification would be contrived to be indistinguishable from a rejection (whether rejected on the basis of an invalid identity or incorrect password or whatever.)

This stuff is hard enough without having to worry about compilers' enthusiastic optimisations. Pehaps GCC might be augmented with a —Ocryptographic_sensitive flag, attribute or pragma to render the code deterministic with respect to timing with code generation skewed towards the security concerns.

"Hazardous" optimizations

Richard Tobin

"good C programmers know to fear the aggressive optimization of Boolean logic, which can be hazardous to their finished products". The optimizations described in the linked article are quite different from the problems facing cryptographers. The optimizations in the linked article are just wrong, and a compiler that does them is not conforming to the C standard. The problem for cryptographers is that they want to specify behaviour that isn't part of the C language, namely timing.

Anonymous Coward

As someone who spends a lot of time compiling of C into binary patches, I can say that GCC is a real pain in the ass, more than any other compiler. There are some optimizations and transformations it does to the code that can't be turned off. I use C as a kind of machine-independent assembly language and it's the perfect language for that purpose, with most simple straightforward compilers. But GCC always tries to be clever and abstract the code in the way that high-level languages do and the resulting code is often more instructions than necessary, more stack usage and generally reorganizing constructs in the most awkward way possible. I just want it to do what it's told and and turn a simple piece of C into a simple piece of assembler. I think the GCC developers have their heads in the high-level language world and don't understand the use-cases of embedded developers.

It is, of course, written in Perl. Translation to C is left as an
exercise for the reader. :-) -- Larry Wall in <7448@jpl-devvax.JPL.NASA.GOV>