Kaz Kylheku said:
The behavior of accessing an uninitialized lvalue is undefined,
regardless of its effective type.
I'm willing to be convinced that that's correct, but I haven't been
yet.
An uninitialized object is ``indeterminately valued'', and access to such
a thing is right in the definition of undefined behavior.
In C90, but not in C99.
C90 3.16:
undefined behavior
Behavior, upon use of a nonportable or erroneous program
construct, of erroneous data, or of indeterminately valued
objects, for which this International Standard imposes no
requirements. Permissible undefined behavior ranges from ignoring
the situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of
a diagnostic message), to terminating a translation or execution
(with the issuance of a diagnostic message).
If a "shall" or "shall not" requirement that appears outside of a
constraint is violated. the behavior is undefined. Undefined
behavior is otherwise indicated in this International Standard by
the words undefined behavior or by the omission of any explicit
definition of behavior. There is no difterence in emphasis among
these three: they all describe behavior that is undefined.
C99 3.4.3:
undefined behavior
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard
imposes no requirements
NOTE Possible undefined behavior ranges from ignoring the
situation completely with unpredictable results, to behaving
during translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of
a diagnostic message), to terminating a translation or execution
(with the issuance of a diagnostic message).
EXAMPLE An example of undefined behavior is the behavior on
integer overflow.
I presume that the omission of "indeterminately valued objects" from
the C99 definition was deliberate.
And, as I read it, even the C90 definition doesn't necessarily imply
that accessing such a value UB; it does so only in cases where the
standard imposes no requirements. There are plenty of "nonportable
.... program construct(s)" whose use doesn't necessarily invoke UB.
And as long as I'm reading section 3:
C99 3.17.2:
indeterminate value
either an unspecified value or a trap representation
C99 3.17.3:
unspecified value
valid value of the relevant type where this International Standard
imposes no requirements on which value is chosen in any instance
NOTE An unspecified value cannot be a trap representation.
So, for a type that has no trap representations (e.g., int
on a system with CHAR_BIT*sizeof(int)==32, INT_MIN==-2**31,
INT_MAX==2**31-1), an indeterminate value must be an unspecified
value, which is *by definition" a "valid value". (C90 doesn't have
definitions for "indeterminate value" and "unspecified value".)
[snip]
Uninitialized auto objects: indeterminate.
Agreed.
Consequently, the machine can detect and diagnose accesses to
uninitialized memory even without the help of trap representations.
Certainly an implementation can issue whatever diagnostics it likes.
Valuable tools like Purify or Valgrind are examples of implementations
(or implementation components) which have this capability.
If a compiled C program is run on Valgrind, it is running on no less
of a conforming implementation, even though its uses of
uninitialized memory (even of character type) are now diagnosed.
If my interpretation of the C99 definitions is correct, then this
program:
#include <stdio.h>
#include <limits.h>
int main(void)
{
int indeterminate;
if (sizeof(int) * CHAR_BIT == 16 &&
INT_MIN == -INT_MAX - 1 &&
INT_MAX == +32767)
{
indeterminate;
}
printf("Hello, world\n");
return 0;
}
is strictly conforming, even given the possible access of an
indeterminate object; an implementation may issue any compile-time
warnings it likes, but the program must print "Hello, world" at run
time.
Of course the information whether or not memory is uninitialized has
to be stored somewhere. It doesn't have to be in the form of a trap
representation; it can be in a database which is stored elsewhere,
which can be queried about the properties and state of any piece of
memory, using the address as the key.
Agreed. The question is what an implementation may do with that
information.