Could an unchecked scanf call cause undefined behavior?

Does the below snippet cause undefined behavior on error?

#include <stdio.h>

int main() {
    int i;                      /* Indeterminate */
    if (scanf("%d", &i) == 1)   /* Initialize */
        printf("%d\n", i);      /* Success! Print read value */
    else
        printf("%d\n", i);      /* Input failed! Is printing `i` UB or not? */
    return 0;
}

      

What if scanf fails, is an accessible uninitialized variable?

EDIT
Moreover, if instead of scanf("%d", &i)

replacing my_initializer(&i)

:

int my_initializer(int *pi)
{
  double room_temp_degc = get_room_temp_in_degc();
  if(room_temp_degc < 12.0) {
    // Cool
    *pi = 42;
    return 1;
  } else {
    return 0;
  }
}

      

+3


source to share


1 answer


In the C90, it's UB.

For C99 and C11, this is technically not the case, but the output is undefined. It is even possible that the next next printf

will print a different value; uninitialized variables can change without explicit program action. Note, however, that an uninitialized variable can only be read if its address has been accepted *) (which is done here in the call scanf

). From n1570 6.3.2.1 p2:

If the value l denotes an object with an automatic storage time that could have been declared with a storage class register

(its address was never accepted), and that object is uninitialized (not declared with an initializer, and no assignment has been made to it prior to use), the behavior is undefined ...

In theory, this would allow something like

int n;
&n;
printf("%d\n", n);

      



But compilers can still reorder statements or allocate registers based on the assumption that the first read does not occur until the first write and ignores the free operator &n;

without side effects.

For any practical purpose, never read uninitialized values. First, there is no reason why you should want; secondly, even an undefined value allows for unexpected optimization: some thought the garbage value could be used to collect some entropy for random numbers, leading to really bad bugs in cryptographic software, see for example blog entry Xi Wang . For an even weirder example where an uninitialized value is odd after multiplying with 2, see this blog , for example (yes, indefinite time 2 is just indefinite, not even indefinite otherwise).

See also DR 260 .

*) The quoted paragraph is missing in C99, but this should be considered a defect in the standard and not a change in C11. C99 makes it technically definite (for machines without hook representations) to read any uninitialized variable (although their values ​​are still undefined and may still be displayed randomly, this just isn't UB).

With DR 338 , this was fixed, but not until C11. It was added to allow NaT

on the Titanium platform (which exists for registers, but not for values ​​in memory) even for integer types without hooks. I don't know if &n

the code above affects such a platform (by strict reading C11, it should be, but I would not rely on it).

+6


source







All Articles