Skip to content

Commit a7cea86

Browse files
jensmaurertkoeppe
authored andcommitted
P2795R5 Erroneous behaviour for uninitialized reads
1 parent cc1f872 commit a7cea86

9 files changed

+187
-36
lines changed

source/basic.tex

+70-15
Original file line numberDiff line numberDiff line change
@@ -3744,26 +3744,49 @@
37443744
\end{note}
37453745
\indextext{object lifetime|)}
37463746

3747-
\rSec2[basic.indet]{Indeterminate values}
3747+
\rSec2[basic.indet]{Indeterminate and erroneous values}
37483748

37493749
\pnum
37503750
\indextext{value!indeterminate}%
37513751
\indextext{indeterminate value}%
37523752
When storage for an object with automatic or dynamic storage duration
3753-
is obtained, the object has an \defnadj{indeterminate}{value}, and if
3754-
no initialization is performed for the object, that object retains an
3755-
indeterminate value until that value is replaced\iref{expr.ass}.
3753+
is obtained,
3754+
the bytes comprising the storage for the object
3755+
have the following initial value:
3756+
\begin{itemize}
3757+
\item
3758+
If the object has dynamic storage duration, or
3759+
is the object associated with a variable or function parameter
3760+
whose first declaration is marked with
3761+
the \tcode{[[indeterminate]]} attribute\iref{dcl.attr.indet},
3762+
the bytes have \defnadjx{indeterminate}{values}{value};
3763+
\item
3764+
otherwise, the bytes have erroneous values,
3765+
where each value is determined by the implementation
3766+
independently of the state of the program.
3767+
\end{itemize}
3768+
If no initialization is performed for an object (including subobjects),
3769+
such a byte retains its initial value
3770+
until that value is replaced\iref{dcl.init.general,expr.ass}.
3771+
If any bit in the value representation has an indeterminate value,
3772+
the object has an indeterminate value;
3773+
otherwise, if any bit in the value representation has an erroneous value,
3774+
the object has an erroneous value\iref{conv.lval}.
37563775
\begin{note}
37573776
Objects with static or thread storage duration are zero-initialized,
37583777
see~\ref{basic.start.static}.
37593778
\end{note}
37603779

37613780
\pnum
3762-
If an indeterminate value is produced by an evaluation,
3763-
the behavior is undefined except in the following cases:
3781+
Except in the following cases,
3782+
if an indeterminate value is produced by an evaluation,
3783+
the behavior is undefined, and
3784+
if an erroneous value is produced by an evaluation,
3785+
the behavior is erroneous and
3786+
the result of the evaluation is the value so produced but is not erroneous:
37643787
\begin{itemize}
37653788
\item
3766-
If an indeterminate value of
3789+
If an indeterminate or erroneous value of
37673790
unsigned ordinary character type\iref{basic.fundamental}
37683791
or \tcode{std::byte} type\iref{cstddef.syn}
37693792
is produced by the evaluation of:
@@ -3780,37 +3803,69 @@
37803803
\item
37813804
a discarded-value expression\iref{expr.context},
37823805
\end{itemize}
3783-
then the result of the operation is an indeterminate value.
3806+
then the result of the operation is an indeterminate value or
3807+
that errorneous value, respectively.
37843808
\item
3785-
If an indeterminate value of
3809+
If an indeterminate or erroneous value of
37863810
unsigned ordinary character type or \tcode{std::byte} type
37873811
is produced by the evaluation of
37883812
the right operand of a simple assignment operator\iref{expr.ass}
37893813
whose first operand is an lvalue of
37903814
unsigned ordinary character type or \tcode{std::byte} type,
3791-
an indeterminate value replaces
3815+
an indeterminate value or that erroneous value, respectively, replaces
37923816
the value of the object referred to by the left operand.
37933817
\item
3794-
If an indeterminate value of unsigned ordinary character type
3818+
If an indeterminate or erroneous value of unsigned ordinary character type
37953819
is produced by the evaluation of the initialization expression
37963820
when initializing an object of unsigned ordinary character type,
37973821
that object is initialized to an indeterminate
3798-
value.
3822+
value or that erroneous value, respectively.
37993823
\item
38003824
If an indeterminate value of
38013825
unsigned ordinary character type or \tcode{std::byte} type
38023826
is produced by the evaluation of the initialization expression
38033827
when initializing an object of \tcode{std::byte} type,
3804-
that object is initialized to an indeterminate value.
3828+
that object is initialized to an indeterminate value or
3829+
that erroneous value, respectively.
38053830
\end{itemize}
3831+
Converting an indeterminate or erroneous value of
3832+
unsigned ordinary character type or \tcode{std::byte} type
3833+
produces an indeterminate or erroneous value, respectively.
3834+
In the latter case,
3835+
the result of the conversion is the value of the converted operand.
38063836
\begin{example}
38073837
\begin{codeblock}
38083838
int f(bool b) {
3809-
unsigned char c;
3810-
unsigned char d = c; // OK, \tcode{d} has an indeterminate value
3839+
unsigned char *c = new unsigned char;
3840+
unsigned char d = *c; // OK, \tcode{d} has an indeterminate value
38113841
int e = d; // undefined behavior
38123842
return b ? d : 0; // undefined behavior if \tcode{b} is \tcode{true}
38133843
}
3844+
3845+
int g(bool b) {
3846+
unsigned char c;
3847+
unsigned char d = c; // no erroneous behavior, but \tcode{d} has an erroneous value
3848+
3849+
assert(c == d); // holds, both integral promotions have erroneous behavior
3850+
3851+
int e = d; // erroneous behavior
3852+
return b ? d : 0; // erroneous behavior if \tcode{b} is \tcode{true}
3853+
}
3854+
3855+
void h() {
3856+
int d1, d2;
3857+
3858+
int e1 = d1; // erroneous behavior
3859+
int e2 = d1; // erroneous behavior
3860+
3861+
assert(e1 == e2); // holds
3862+
assert(e1 == d1); // holds, erroneous behavior
3863+
assert(e2 == d1); // holds, erroneous behavior
3864+
3865+
std::memcpy(&d2, &d1, sizeof(int)); // no erroneous behavior, but \tcode{d2} has an erroneous value
3866+
assert(e1 == d2); // holds, erroneous behavior
3867+
assert(e2 == d2); // holds, erroneous behavior
3868+
}
38143869
\end{codeblock}
38153870
\end{example}
38163871

source/classes.tex

+2-2
Original file line numberDiff line numberDiff line change
@@ -5505,7 +5505,7 @@
55055505
is neither initialized nor
55065506
given a value
55075507
during execution of the \grammarterm{compound-statement} of the body of the constructor,
5508-
the member has an indeterminate value.
5508+
the member has an indeterminate or erroneous value\iref{basic.indet}.
55095509
\end{note}
55105510
\begin{example}
55115511
\begin{codeblock}
@@ -5521,7 +5521,7 @@
55215521
C() { } // initializes members as follows:
55225522
A a; // OK, calls \tcode{A::A()}
55235523
const B b; // error: \tcode{B} has no default constructor
5524-
int i; // OK, \tcode{i} has indeterminate value
5524+
int i; // OK, \tcode{i} has indeterminate or erroneous value
55255525
int j = 5; // OK, \tcode{j} has the value \tcode{5}
55265526
};
55275527
\end{codeblock}

source/compatibility.tex

+2-2
Original file line numberDiff line numberDiff line change
@@ -2881,8 +2881,8 @@
28812881
\end{codeblock}
28822882

28832883
\rationale
2884-
This is to avoid erroneous function calls (i.e., function calls
2885-
with the wrong number or type of arguments).
2884+
This is to avoid function calls
2885+
with the wrong number or type of arguments.
28862886
\effect
28872887
Change to semantics of well-defined feature.
28882888
This feature was marked as ``obsolescent'' in C.

source/declarations.tex

+46
Original file line numberDiff line numberDiff line change
@@ -9189,6 +9189,52 @@
91899189
\end{codeblock}
91909190
\end{example}
91919191

9192+
\rSec2[dcl.attr.indet]{Indeterminate storage}
9193+
\indextext{attribute!indeterminate}
9194+
9195+
\pnum
9196+
The \grammarterm{attribute-token} \tcode{indeterminate} may be applied
9197+
to the definition of a block variable with automatic storage duration or
9198+
to a \grammarterm{parameter-declaration} of a function declaration.
9199+
No \grammarterm{attribute-argument-clause} shall be present.
9200+
The attribute specifies
9201+
that the storage of an object with automatic storage duration
9202+
is initially indeterminate rather than erroneous\iref{basic.indet}.
9203+
9204+
\pnum
9205+
If a function parameter is declared with the \tcode{indeterminate} attribute,
9206+
it shall be so declared in the first declaration of its function.
9207+
If a function parameter is declared with
9208+
the \tcode{indeterminate} attribute in the first declaration of its function
9209+
in one translation unit and
9210+
the same function is declared without the \tcode{indeterminate} attribute
9211+
on the same parameter in its first declaration in another translation unit,
9212+
the program is ill-formed, no diagnostic required.
9213+
9214+
\pnum
9215+
\begin{note}
9216+
Reading from an uninitialized variable
9217+
that is marked \tcode{[[indeterminate]]} can cause undefined behavior.
9218+
\begin{codeblock}
9219+
void f(int);
9220+
void g() {
9221+
int x [[indeterminate]], y;
9222+
f(y); // erroneous behavior\iref{basic.indet}
9223+
f(x); // undefined behavior
9224+
}
9225+
9226+
struct T {
9227+
T() {}
9228+
int x;
9229+
};
9230+
int h(T t [[indeterminate]]) {
9231+
f(t.x); // undefined behavior when called below
9232+
return 0;
9233+
}
9234+
int _ = h(T());
9235+
\end{codeblock}
9236+
\end{note}
9237+
91929238
\rSec2[dcl.attr.likelihood]{Likelihood attributes}%
91939239
\indextext{attribute!likely}
91949240
\indextext{attribute!unlikely}

source/expressions.tex

+15-4
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,9 @@
675675

676676
\item Otherwise, the object indicated by the glvalue is read\iref{defns.access},
677677
and the value contained in the object is the prvalue result.
678+
If the result is an erroneous value\iref{basic.indet} and
679+
the bits in the value representation are not valid for the object's type,
680+
the behavior is undefined.
678681
\end{itemize}
679682

680683
\pnum
@@ -5299,7 +5302,7 @@
52995302
If the \grammarterm{expression} in a \grammarterm{noptr-new-declarator}
53005303
is present, it is implicitly converted to \tcode{std::size_t}.
53015304
\indextext{function!allocation}%
5302-
The \grammarterm{expression} is erroneous if:
5305+
The value of the \grammarterm{expression} is invalid if:
53035306
\begin{itemize}
53045307
\item
53055308
the expression is of non-class type and its value before converting to
@@ -5327,7 +5330,7 @@
53275330
number of elements to initialize.
53285331
\end{itemize}
53295332

5330-
If the \grammarterm{expression} is erroneous after converting to \tcode{std::size_t}:
5333+
If the value of the \grammarterm{expression} is invalid after converting to \tcode{std::size_t}:
53315334
\begin{itemize}
53325335
\item
53335336
if the \grammarterm{expression} is a potentially-evaluated core constant expression,
@@ -7519,7 +7522,7 @@
75197522
limits (see \ref{implimits});
75207523

75217524
\item
7522-
an operation that would have undefined behavior
7525+
an operation that would have undefined or erroneous behavior
75237526
as specified in \ref{intro} through \ref{cpp},
75247527
excluding \ref{dcl.attr.assume} and \ref{dcl.attr.noreturn};
75257528
\begin{footnote}
@@ -7937,7 +7940,7 @@
79377940

79387941
\item
79397942
if the value is an object of scalar type,
7940-
it does not have an indeterminate value\iref{basic.indet},
7943+
it does not have an indeterminate or erroneous value\iref{basic.indet},
79417944

79427945
\item
79437946
if the value is of pointer type, it contains
@@ -7973,6 +7976,14 @@
79737976
constexpr int r = h(); // OK
79747977
constexpr auto e = g(); // error: a pointer to an immediate function is
79757978
// not a permitted result of a constant expression
7979+
7980+
struct S {
7981+
int x;
7982+
constexpr S() {}
7983+
};
7984+
int i() {
7985+
constexpr S s; // error: \tcode{s.x} has erroneous value
7986+
}
79767987
\end{codeblock}
79777988
\end{example}
79787989

source/intro.tex

+28-3
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,16 @@
253253
\definition{dynamic type}{defns.dynamic.type.prvalue}
254254
\defncontext{prvalue} \termref{defns.static.type}{static type}{} of the prvalue expression
255255

256+
\definition{erroneous behavior}{defns.erroneous}
257+
well-defined behavior that the implementation is recommended to diagnose
258+
\begin{defnote}
259+
Erroneous behavior is always the consequence of incorrect program code.
260+
Implementations are allowed, but not required,
261+
to diagnose it\iref{intro.compliance.general}.
262+
Evaluation of a constant expression\iref{expr.const}
263+
never exhibits behavior specified as erroneous in \ref{intro} through \ref{cpp}.
264+
\end{defnote}
265+
256266
\definition{expression-equivalent}{defns.expression.equivalent}
257267
\defncontext{library}
258268
\indexdefn{expression-equivalent}%
@@ -629,13 +639,13 @@
629639
\begin{defnote}
630640
Undefined behavior may be expected when
631641
this document omits any explicit
632-
definition of behavior or when a program uses an erroneous construct or erroneous data.
642+
definition of behavior or when a program uses an incorrect construct or invalid data.
633643
Permissible undefined behavior ranges
634644
from ignoring the situation completely with unpredictable results, to
635645
behaving during translation or program execution in a documented manner
636646
characteristic of the environment (with or without the issuance of a
637647
\termref{defns.diagnostic}{diagnostic message}{}), to terminating a translation or execution (with the
638-
issuance of a diagnostic message). Many erroneous program constructs do
648+
issuance of a diagnostic message). Many incorrect program constructs do
639649
not engender undefined behavior; they are required to be diagnosed.
640650
Evaluation of a constant expression\iref{expr.const} never exhibits behavior explicitly
641651
specified as undefined in \ref{intro} through \ref{cpp}.
@@ -721,7 +731,8 @@
721731
within its resource limits as described in \ref{implimits},
722732
accept and correctly execute
723733
\begin{footnote}
724-
``Correct execution'' can include undefined behavior, depending on
734+
``Correct execution'' can include undefined behavior
735+
and erroneous behavior, depending on
725736
the data being processed; see \ref{intro.defs} and~\ref{intro.execution}.
726737
\end{footnote}
727738
that program.
@@ -900,6 +911,20 @@
900911
requirement on the implementation executing that program with that input
901912
(not even with regard to operations preceding the first undefined
902913
operation).
914+
If the execution contains an operation specified as having erroneous behavior,
915+
the implementation is permitted to issue a diagnostic and
916+
is permitted to terminate the execution
917+
at an unspecified time after that operation.
918+
919+
\pnum
920+
\recommended
921+
An implementation should issue a diagnostic when such an operation is executed.
922+
\begin{note}
923+
An implementation can issue a diagnostic
924+
if it can determine that erroneous behavior is reachable
925+
under an implementation-specific set of assumptions about the program behavior,
926+
which can result in false positives.
927+
\end{note}
903928

904929
\pnum
905930
\indextext{conformance requirements}%

source/lib-intro.tex

+3-3
Original file line numberDiff line numberDiff line change
@@ -1939,10 +1939,10 @@
19391939
\pnum
19401940
A value-initialized object of type \tcode{P} produces the null value of the type.
19411941
The null value shall be equivalent only to itself. A default-initialized object
1942-
of type \tcode{P} may have an indeterminate value.
1942+
of type \tcode{P} may have an indeterminate or erroneous value.
19431943
\begin{note}
1944-
Operations involving
1945-
indeterminate values can cause undefined behavior.
1944+
Operations involving indeterminate values can cause undefined behavior, and
1945+
operations involving erroneous values can cause erroneous behavior\iref{basic.indet}.
19461946
\end{note}
19471947

19481948
\pnum

source/threads.tex

+1-1
Original file line numberDiff line numberDiff line change
@@ -8376,7 +8376,7 @@
83768376
\pnum
83778377
\begin{note}
83788378
It is the user's responsibility to ensure that waiting threads
8379-
do not erroneously assume that the thread has finished if they experience
8379+
do not incorrectly assume that the thread has finished if they experience
83808380
spurious wakeups. This typically requires that the condition being waited
83818381
for is satisfied while holding the lock on \tcode{lk}, and that this lock
83828382
is not released and reacquired prior to calling \tcode{notify_all_at_thread_exit}.

source/utilities.tex

+20-6
Original file line numberDiff line numberDiff line change
@@ -18865,13 +18865,27 @@
1886518865
If there are multiple such values, which value is produced is unspecified.
1886618866
A bit in the value representation of the result is indeterminate if
1886718867
it does not correspond to a bit in the value representation of \tcode{from} or
18868-
corresponds to a bit of an object that is not within its lifetime or
18868+
corresponds to a bit
18869+
for which the smallest enclosing object is not within its lifetime or
1886918870
has an indeterminate value\iref{basic.indet}.
18870-
For each bit in the value representation of the result that is indeterminate,
18871-
the smallest object containing that bit has an indeterminate value;
18872-
the behavior is undefined unless that object is
18873-
of unsigned ordinary character type or \tcode{std::byte} type.
18874-
The result does not otherwise contain any indeterminate values.
18871+
A bit in the value representation of the result is erroneous
18872+
if it corresponds to a bit
18873+
for which the smallest enclosing object has an erroneous value.
18874+
For each bit $b$ in the value representation of the result
18875+
that is indeterminate or erroneous,
18876+
let $u$ be the smallest object containing that bit enclosing $b$.
18877+
\begin{itemize}
18878+
\item
18879+
If $u$ is of unsigned ordinary character type or \tcode{std::byte} type,
18880+
$u$ has an indeterminate value
18881+
if any of the bits in its value representation are indeterminate, or
18882+
otherwise has an erroneous value.
18883+
\item
18884+
Otherwise, if $b$ is indeterminate, the behavior is undefined.
18885+
\item
18886+
Otherwise, the behaviour is erroneous, and the result is as specified above.
18887+
\end{itemize}
18888+
The result does not otherwise contain any indeterminate or erroneous values.
1887518889

1887618890
\pnum
1887718891
\remarks

0 commit comments

Comments
 (0)