Skip to content

Commit 4438640

Browse files
committed
P2795R5 Erroneous behaviour for uninitialized reads
1 parent fa7c7e5 commit 4438640

9 files changed

+187
-36
lines changed

source/basic.tex

+70-15
Original file line numberDiff line numberDiff line change
@@ -3723,26 +3723,49 @@
37233723
\end{note}
37243724
\indextext{object lifetime|)}
37253725

3726-
\rSec2[basic.indet]{Indeterminate values}
3726+
\rSec2[basic.indet]{Indeterminate and erroneous values}
37273727

37283728
\pnum
37293729
\indextext{value!indeterminate}%
37303730
\indextext{indeterminate value}%
37313731
When storage for an object with automatic or dynamic storage duration
3732-
is obtained, the object has an \defnadj{indeterminate}{value}, and if
3733-
no initialization is performed for the object, that object retains an
3734-
indeterminate value until that value is replaced\iref{expr.ass}.
3732+
is obtained,
3733+
the bytes comprising the storage for the object
3734+
have the following initial value:
3735+
\begin{itemize}
3736+
\item
3737+
If the object has dynamic storage duration, or
3738+
is the object associated with a variable or function parameter
3739+
whose first declaration is marked with
3740+
the \tcode{[[indeterminate]]} attribute\iref{dcl.attr.indeterminate},
3741+
the bytes have \defnadjx{indeterminate}{values}{value};
3742+
\item
3743+
otherwise, the bytes have erroneous values,
3744+
where each value is determined by the implementation
3745+
independently of the state of the program.
3746+
\end{itemize}
3747+
If no initialization is performed for an object (including subobjects),
3748+
such a byte retains its initial value
3749+
until that value is replaced\iref{dcl.init.general,expr.ass}.
3750+
If any bit in the value representation has an indeterminate value,
3751+
the object has an indeterminate value;
3752+
otherwise, if any bit in the value representation has an erroneous value,
3753+
the object has an erroneous value\iref{conv.lval}.
37353754
\begin{note}
37363755
Objects with static or thread storage duration are zero-initialized,
37373756
see~\ref{basic.start.static}.
37383757
\end{note}
37393758

37403759
\pnum
3741-
If an indeterminate value is produced by an evaluation,
3742-
the behavior is undefined except in the following cases:
3760+
Except in the following cases,
3761+
if an indeterminate value is produced by an evaluation,
3762+
the behavior is undefined, and
3763+
if an erroneous value is produced by an evaluation,
3764+
the behavior is erroneous and
3765+
the result of the evaluation is the value so produced but is not erroneous:
37433766
\begin{itemize}
37443767
\item
3745-
If an indeterminate value of
3768+
If an indeterminate or erroneous value of
37463769
unsigned ordinary character type\iref{basic.fundamental}
37473770
or \tcode{std::byte} type\iref{cstddef.syn}
37483771
is produced by the evaluation of:
@@ -3759,37 +3782,69 @@
37593782
\item
37603783
a discarded-value expression\iref{expr.context},
37613784
\end{itemize}
3762-
then the result of the operation is an indeterminate value.
3785+
then the result of the operation is an indeterminate value or
3786+
that errorneous value, respectively.
37633787
\item
3764-
If an indeterminate value of
3788+
If an indeterminate or erroneous value of
37653789
unsigned ordinary character type or \tcode{std::byte} type
37663790
is produced by the evaluation of
37673791
the right operand of a simple assignment operator\iref{expr.ass}
37683792
whose first operand is an lvalue of
37693793
unsigned ordinary character type or \tcode{std::byte} type,
3770-
an indeterminate value replaces
3794+
an indeterminate value or that erroneous value, respectively, replaces
37713795
the value of the object referred to by the left operand.
37723796
\item
3773-
If an indeterminate value of unsigned ordinary character type
3797+
If an indeterminate or erroneous value of unsigned ordinary character type
37743798
is produced by the evaluation of the initialization expression
37753799
when initializing an object of unsigned ordinary character type,
37763800
that object is initialized to an indeterminate
3777-
value.
3801+
value or that erroneous value, respectively.
37783802
\item
37793803
If an indeterminate value of
37803804
unsigned ordinary character type or \tcode{std::byte} type
37813805
is produced by the evaluation of the initialization expression
37823806
when initializing an object of \tcode{std::byte} type,
3783-
that object is initialized to an indeterminate value.
3807+
that object is initialized to an indeterminate value or
3808+
that erroneous value, respectively.
37843809
\end{itemize}
3810+
Converting an indeterminate or erroneous value of
3811+
unsigned ordinary character type or \tcode{std::byte} type
3812+
produces an indeterminate or erroneous value, respectively.
3813+
In the latter case,
3814+
the result of the conversion is the value of the converted operand.
37853815
\begin{example}
37863816
\begin{codeblock}
37873817
int f(bool b) {
3788-
unsigned char c;
3789-
unsigned char d = c; // OK, \tcode{d} has an indeterminate value
3818+
unsigned char *c = new unsigned char;
3819+
unsigned char d = *c; // OK, \tcode{d} has an indeterminate value
37903820
int e = d; // undefined behavior
37913821
return b ? d : 0; // undefined behavior if \tcode{b} is \tcode{true}
37923822
}
3823+
3824+
int g(bool b) {
3825+
unsigned char c;
3826+
unsigned char d = c; // no erroneous behavior, but \tcode{d} has an erroneous value
3827+
3828+
assert(c == d); // holds, both integral promotions have erroneous behavior
3829+
3830+
int e = d; // erroneous behavior
3831+
return b ? d : 0; // erroneous behavior if \tcode{b} is \tcode{true}
3832+
}
3833+
3834+
void h() {
3835+
int d1, d2;
3836+
3837+
int e1 = d1; // erroneous behavior
3838+
int e2 = d1; // erroneous behavior
3839+
3840+
assert(e1 == e2); // holds
3841+
assert(e1 == d1); // holds, erroneous behavior
3842+
assert(e2 == d1); // holds, erroneous behavior
3843+
3844+
std::memcpy(&d2, &d1, sizeof(int)); // no erroneous behavior, but \tcode{d2} has an erroneous value
3845+
assert(e1 == d2); // holds, erroneous behavior
3846+
assert(e2 == d2); // holds, erroneous behavior
3847+
}
37933848
\end{codeblock}
37943849
\end{example}
37953850

source/classes.tex

+2-2
Original file line numberDiff line numberDiff line change
@@ -5559,7 +5559,7 @@
55595559
is neither initialized nor
55605560
given a value
55615561
during execution of the \grammarterm{compound-statement} of the body of the constructor,
5562-
the member has an indeterminate value.
5562+
the member has an indeterminate or erroneous value\iref{basic.indet}.
55635563
\end{note}
55645564
\begin{example}
55655565
\begin{codeblock}
@@ -5575,7 +5575,7 @@
55755575
C() { } // initializes members as follows:
55765576
A a; // OK, calls \tcode{A::A()}
55775577
const B b; // error: \tcode{B} has no default constructor
5578-
int i; // OK, \tcode{i} has indeterminate value
5578+
int i; // OK, \tcode{i} has indeterminate or erroneous value
55795579
int j = 5; // OK, \tcode{j} has the value \tcode{5}
55805580
};
55815581
\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
@@ -9099,6 +9099,52 @@
90999099
\end{codeblock}
91009100
\end{example}
91019101

9102+
\rSec2[dcl.attr.indet]{Indeterminate storage}
9103+
\indextext{attribute!indeterminate}
9104+
9105+
\pnum
9106+
The \grammarterm{attribute-token} \tcode{indeterminate} may be applied
9107+
to the definition of a block variable with automatic storage duration or
9108+
to a \grammarterm{parameter-declaration} of a function declaration.
9109+
No \grammarterm{attribute-argument-clause} shall be present.
9110+
The attribute specifies
9111+
that the storage of an object with automatic storage duration
9112+
is initially indeterminate rather than erroneous\iref{basic.indet}.
9113+
9114+
\pnum
9115+
If a function parameter is declared with the \tcode{indeterminate} attribute,
9116+
it shall be so declared in the first declaration of its function.
9117+
If a function parameter is declared with
9118+
the \tcode{indeterminate} attribute in the first declaration of its function
9119+
in one translation unit and
9120+
the same function is declared without the \tcode{indeterminate} attribute
9121+
on the same parameter in its first declaration in another translation unit,
9122+
the program is ill-formed, no diagnostic required.
9123+
9124+
\pnum
9125+
\begin{note}
9126+
Reading from an uninitialized variable
9127+
that is marked \tcode{[[indeterminate]]} can cause undefined behavior.
9128+
\begin{codeblock}
9129+
void f(int);
9130+
void g() {
9131+
int x [[indeterminate]], y;
9132+
f(y); // erroneous behavior\iref{basic.indet}
9133+
f(x); // undefined behavior
9134+
}
9135+
9136+
struct T {
9137+
T() {}
9138+
int x;
9139+
};
9140+
int h(T t [[indeterminate]]) {
9141+
f(t.x); // undefined behavior when called below
9142+
return 0;
9143+
}
9144+
int _ = h(T());
9145+
\end{codeblock}
9146+
\end{note}
9147+
91029148
\rSec2[dcl.attr.likelihood]{Likelihood attributes}%
91039149
\indextext{attribute!likely}
91049150
\indextext{attribute!unlikely}

source/expressions.tex

+15-4
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,9 @@
674674

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

679682
\pnum
@@ -5270,7 +5273,7 @@
52705273
If the \grammarterm{expression} in a \grammarterm{noptr-new-declarator}
52715274
is present, it is implicitly converted to \tcode{std::size_t}.
52725275
\indextext{function!allocation}%
5273-
The \grammarterm{expression} is erroneous if:
5276+
The value of the \grammarterm{expression} is invalid if:
52745277
\begin{itemize}
52755278
\item
52765279
the expression is of non-class type and its value before converting to
@@ -5298,7 +5301,7 @@
52985301
number of elements to initialize.
52995302
\end{itemize}
53005303

5301-
If the \grammarterm{expression} is erroneous after converting to \tcode{std::size_t}:
5304+
If the value of the \grammarterm{expression} is invalid after converting to \tcode{std::size_t}:
53025305
\begin{itemize}
53035306
\item
53045307
if the \grammarterm{expression} is a potentially-evaluated core constant expression,
@@ -7480,7 +7483,7 @@
74807483
limits (see \ref{implimits});
74817484

74827485
\item
7483-
an operation that would have undefined behavior
7486+
an operation that would have undefined or erroneous behavior
74847487
as specified in \ref{intro} through \ref{cpp},
74857488
excluding \ref{dcl.attr.assume} and \ref{dcl.attr.noreturn};
74867489
\begin{footnote}
@@ -7895,7 +7898,7 @@
78957898

78967899
\item
78977900
if the value is an object of scalar type,
7898-
it does not have an indeterminate value\iref{basic.indet},
7901+
it does not have an indeterminate or erroneous value\iref{basic.indet},
78997902

79007903
\item
79017904
if the value is of pointer type, it contains
@@ -7931,6 +7934,14 @@
79317934
constexpr int r = h(); // OK
79327935
constexpr auto e = g(); // error: a pointer to an immediate function is
79337936
// not a permitted result of a constant expression
7937+
7938+
struct S {
7939+
int x;
7940+
constexpr S() {}
7941+
};
7942+
int i() {
7943+
constexpr S s; // error: \tcode{s.x} has erroneous value
7944+
}
79347945
\end{codeblock}
79357946
\end{example}
79367947

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.
@@ -893,6 +904,20 @@
893904
requirement on the implementation executing that program with that input
894905
(not even with regard to operations preceding the first undefined
895906
operation).
907+
If the execution contains an operation specified as having erroneous behavior,
908+
the implementation is permitted to issue a diagnostic and
909+
is permitted to terminate the execution
910+
at an unspecified time after that operation.
911+
912+
\pnum
913+
\recommended
914+
An implementation should issue a diagnostic when such an operation is executed.
915+
\begin{note}
916+
An implementation can issue a diagnostic
917+
if it can determine that erroneous behavior is reachable
918+
under an implementation-specific set of assumptions about the program behavior,
919+
which can result in false positives.
920+
\end{note}
896921

897922
\pnum
898923
\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 $u4 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)