Path: csiph.com!weretis.net!feeder8.news.weretis.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.std.c Subject: Does reading an uninitialized object have undefined behavior? Date: Thu, 20 Jul 2023 22:16:01 -0700 Organization: None to speak of Lines: 83 Message-ID: <87zg3pq1ym.fsf@nosuchdomain.example.com> MIME-Version: 1.0 Content-Type: text/plain Injection-Info: dont-email.me; posting-host="2370f913b850030e0527dd0f7396627d"; logging-data="3293548"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18fwVdkCkH+Tmj2ymMo73PE" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:8aki8yKNElyLdN1U3vwilRAU1ME= sha1:23z1n6lZpxOJ11/InfvxON9VJ2E= Xref: csiph.com comp.std.c:6505 N3096 is the last public draft of the upcoming C23 standard. N3096 J.2 says: The behavior is undefined in the following circumstances: [...] (11) The value of an object with automatic storage duration is used while the object has an indeterminate representation (6.2.4, 6.7.10, 6.8). I'll use an `int` object in my example. Reading an object that holds a non-value representation has undefined behavior, but not all integer types have non-value representations -- and if an implementation has certain characteristics, we can reliably infer that int has no non-value representations (called "trap representations" in C99, C11, and C17). Consider this program: ``` #include int main(void) { int foo; if (sizeof (int) == 4 && CHAR_BIT == 8 && INT_MAX == 2147483647 && INT_MIN == -INT_MAX-1) { int bar = foo; } } ``` If the condition is true (as it is for many real-world implementations), then int has no padding bits and no trap representations. The object `foo` has an indeterminate representation when it's used to initialize `bar`. Since it cannot have a non-value representation, it has an unspecified value. If J.2(11) is correct, then the use of the value results in undefined behavior. But Annex J is non-normative, and as far as I can tell there is no normative text in the standard that says the behavior is undefined. 6.2.4 discusses storage duration. 6.7.10 discusses initialization; p11 implies that the representation of `foo` is indeterminate. It does not say 6.8 discusses statements and blocks, and repeats that "the representation of objects without an initializer becomes indeterminate". None of these discuss what happens when the value of an object with an indeterminate representation is used -- nor does any other text I found by searching the standard for "indeterminate representation". I see no relevant changes between C11 and C23 (except that C23 changes the term "trap representation" to "non-value representation"). I suggest there are three possible resolutions: 1. J.2(11) is correct and I've missed something (always a possibility, but so far nobody in comp.lang.c has come up with anything). 2. J.2(11) reflects the intent, and normative text somewhere else in the standard needs to be updated or added to make it clear that using the value of an object with automatic storage duration while the object has an indeterminate representation has undefined behavior. 3. J.2(11) is incorrect and needs to be modified or deleted. (This would also imply that compilers may not perform certain optimizations. I have no idea whether any compilers would actually be affected.) I'm going to post this to comp.std.c and email it to the C23 editors. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Will write code for food. void Void(void) { Void(); } /* The recursive call of the void */