Fun with UB in C: returning uninitialized floats

The average C/C++ programmer's intuition says that uninitialized variables are fine as long as you don't depend on their values.

A more experienced programmer probably suspects that uninitialized variables are fine as long as you don't access them. That is, computing c=a+b where b is uninitialized is not harmless even if you never use c. That's because the compiler could, say, optimize away the entire block of code surrounding c=a+b under the assumption that c=a+b, where b is proven to be always uninitialized, is always undefined behavior (UB). And if it's UB, the only way for the program to be correct is for this code to be unreachable anyway. And if it's unreachable, why waste instructions translating any of it?

However, the following code looks like it could potentially be OK, doesn't it?

float get(obj* v, bool* ok) {
  float c;
  if(v->valid) {
    *ok = true;
    c = v->a + v->b;
  else {
   *ok = false; //not ok, so don't expect anything from c
  return c;

Here you return an uninitialized c, which the caller shouldn't touch because *ok is false. As long as the caller doesn't, all is well, right?

Well, it turns out that even if the caller does nothing at all with the return value – ever, regardless of *ok – the program might bomb. That's because c could be initialized to a singaling NaN, and then say on x86, when the fstp instruction is used to basically just get rid of the return value, you get an exception. In release mode but not in debug mode, some of the time but not all the time. This gives you this warm, fuzzy WTF feeling when you stare at the disassembled code. "Why is there even a float here in the first place?!"

How much uninitialized data is shuffled around by real-world C programs? A lot, I wager – likely closer to 95% than to 5% of programs do this. Otherwise Valgrind would not go to all the trouble to not barf on uninitialized data until the last possible moment (that moment being when a branch is taken based on uninitialized data, or when it's passed to a system call; to not barf then would require some sort of a multiverse simulation approach for which there are not enough computing resources.)

Needless to say, most programs enjoying ("enjoying"?) Valgrind's (or rather memcheck's) conservative approach to error reporting were written neither in assembly which few use, nor in, I dunno, Java, which won't let you do this. They were written in C and C++, and most likely they invoke UB.

(Can you touch uninitialized data in C without triggering UB? I seriously don't know, I'm not a language lawyer. Being able to do this is actually occasionally useful for optimization. Integral types for instance don't have anything like signaling NaNs so at the assembly language level you should be fine. But at the C level the compiler might get needlessly clever if it manages to prove that the data is uninitialized. My own intuition is it can never prove squat about data passed by pointer because of aliasing and so I kinda assume that if I get a buffer pointing to some data and some of it is uninitialized I can do everything to it that I could in assembly. But I'm not sure.)

What a way to make a living.




#1 whitequark on 06.30.15 at 6:54 pm

Integral types actually have an equivalent of signaling NaN on IA64, which IIRC was taken into consideration by the C workgroup.

#2 Yossi Kreinin on 06.30.15 at 7:05 pm

Only in registers, right? It's not like they tag every 8b pixel in an image as "a number" as opposed to "not a number", do they? So there's a substantial grey area here in practice (int local[3] might land in registers whereas int local[256] probably won't, etc.), and say malloced ununitialized bytes are always OK. I wonder if the C standard left the option to touch these without getting hosed or did they "make it simple" and said theoretically you're hosed with any type, anywhere. (Intuitively I'd assume they did the latter…)

#3 FUZxxl on 07.01.15 at 9:42 am

Compilers don't need to use fstp to get rid of an FPU register. They can instead use the ffree ; fincstp combination or even the undocumented ffreep instruction for that.

#4 saarni on 07.01.15 at 10:36 am

As whitequark pointed out, integral values may have "signaling NaN" equivalents: trap representations.

"Any type (except unsigned char) may have trap representations, but no type is required to have them."

Hence reading uninitialized automatic storage integral variable may contain a trap.

#5 LG on 07.01.15 at 11:35 am

I'm not following, what would this trap representation look in like in practice? You mean that the compiler would generate an "int3" (or something like that) instead of the actual uninitialized int read?

#6 Mark on 07.01.15 at 1:06 pm

The real language lawyers hang out on Stack Overflow:

The short answer is that for once, C is saner than you would expect. If you ever take the address of a variable, and the type in question has no scary values like signaling NaNs, then the behavior is well defined: you merely have to contend with assembly-like behavior. (I did not know this five minutes ago! Your blog post made me learn something!) If you want a long answer, go read the top answer on Stack Overflow, or even the top. But the upshot of all this is that the following awesome trick is actually legal C:

For those who have not seen it and are wondering whether it's worth following the link: it's a very simple data structure that uses uninitialized memory to achieve O(1) time for an operation that a naïve implementation would use linear time for. (It's possible to get O(1) time without resorting to uninitialized memory by using a hash table, but that takes work to implement. This is easier to code and runs faster.)

#7 Matthew Fernandez on 07.01.15 at 2:14 pm

I suspect the answer to your final doubt depends on how clever your compiler is at inter-procedural analysis and how much visibility it has within the current translation unit. Of course this always triggers UB in the technical sense, so while you might get away with it you probably shouldn't do it.

#8 hudson on 07.01.15 at 9:42 pm

Minor typo: "c = v->a + b->b;" should probably be "c = v->a + v->b;"

#9 Yossi Kreinin on 07.02.15 at 8:36 am

Thanks – fixed

#10 Yossi Kreinin on 09.15.15 at 7:23 pm


#11 free gg hack on 05.15.19 at 5:58 pm

Respect to website author , some wonderful entropy.

#12 Thad Fulmore on 05.17.19 at 2:39 pm

Appreciate the site– extremely informative and lots to explore!

#13 strucid hacks on 05.28.19 at 10:30 am

Good Morning, google lead me here, keep up great work.

#14 Thad Bartone on 06.05.19 at 7:23 pm

I more or less share your opinion on this subject and look forward to upcoming posts and comments here at Keep up the good work!

#15 how to crack fortnite accounts on 06.17.19 at 5:53 am

I love reading through and I believe this website got some genuinely utilitarian stuff on it! .

#16 dig on 06.18.19 at 11:05 am

The use of uninitialized variables is similar to the use of uninitialized memory and can lead to the various kinds of errors in the course of program operation.

#17 nonsense diamond key generator on 06.21.19 at 9:22 am

Your article has proven useful to me.

#18 dissertations proofreading service go to this site on 06.27.19 at 3:44 pm

Unfortunately, most programs cannot be fully utilized due to the fact that we were completely unable to learn how to use all the necessary features.

#19 cryptotab hack script free download on 06.29.19 at 3:36 pm

Cheers, i really think i will be back to your site

#20 cheat fortnite download no wirus on 07.01.19 at 8:55 pm

Your website has proven useful to me.

#21 cyberhackid on 07.03.19 at 8:25 pm

Yeah bookmaking this wasn’t a risky decision outstanding post! .

#22 prison life hack download on 07.04.19 at 8:27 am

Great, yahoo took me stright here. thanks btw for post. Cheers!

#23 seo tools on 07.04.19 at 2:14 pm

Parasite backlink SEO works well :)

#24 subbot on 07.04.19 at 8:15 pm

You got yourself a new rader.

#25 open dego on 07.05.19 at 8:30 am

Found this on MSN and I’m happy I did. Well written website.

#26 Otis Suzuki on 07.06.19 at 10:19 am

The next phase of the puzzle is to decipher the order of the pyramid. This is your third secret clue! 517232125

#27 RebAbsola on 07.09.19 at 3:01 am

Cephalexin And Diabetes [url=]pastillas levitra[/url] Amoxicillin Good For Prosthesis

#28 ellen_betsy on 07.14.19 at 2:01 am

Thank you for the great read!

#29 Lesangent on 07.14.19 at 3:02 pm

Amoxicillin And Abnormal Menstual Cycles Kamagra Sabores Comprar Veterinary Keflex [url=]viagra[/url] Prix Xenical Espagne Cialis Hipertensos

#30 xxx latex online on 07.15.19 at 2:12 am

some great ideas this gave me!

#31 legalporno free on 07.16.19 at 12:04 am

great advice you give

#32 Valentin Wooster on 07.18.19 at 12:41 pm

Mr.s Fister, this message is your next bit of info. Feel free to message the agency at your earliest convenience. No further information until next transmission. This is broadcast #8277. Do not delete.

#33 victoria_june on 07.19.19 at 1:50 am

you are a great writer!

#34 Buy Drugs Online on 07.19.19 at 2:53 am

This blog is amazing! Thank you.

#35 date cougr on 07.23.19 at 10:44 pm

I am 43 years old and a mother this helped me!

#36 dawte cougar on 07.23.19 at 11:28 pm

I am 43 years old and a mother this helped me!

#37 dqte cougar on 07.23.19 at 11:45 pm

I am 43 years old and a mother this helped me!

#38 on 07.24.19 at 6:37 pm

Good post. I learn something totally new and challenging on websites I stumbleupon every day.

It’s always exciting to read content from other writers and
practice something from other web sites.

#39 on 07.24.19 at 7:52 pm

Hello there! I could have sworn I’ve been to your blog before but after browsing through some
of the posts I realized it’s new to me. Anyhow, I’m certainly
happy I discovered it and I’ll be book-marking it and checking back regularly!

#40 Lesangent on 07.26.19 at 12:45 am

Medicament Propecia Priligy Dapoxetina Italia [url=]viagra[/url] Finasteride Proscar Propecia Profile Propecia Sale Drugstore

Leave a Comment