Skip to content

Commit 11dd7d9

Browse files
authored
[clang][bytecode] Reject constexpr-unknown values from comparisons (#133701)
1 parent 9cdab16 commit 11dd7d9

File tree

4 files changed

+92
-41
lines changed

4 files changed

+92
-41
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,17 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
302302
TYPE_SWITCH(Ty, S.Stk.discard<T>());
303303
}
304304

305+
// FIXME: Instead of using this fairly expensive test, we should
306+
// just mark constexpr-unknown values when creating them.
307+
bool isConstexprUnknown(const Pointer &P) {
308+
if (!P.isBlockPointer())
309+
return false;
310+
if (P.isDummy())
311+
return false;
312+
const VarDecl *VD = P.block()->getDescriptor()->asVarDecl();
313+
return VD && VD->hasLocalStorage();
314+
}
315+
305316
bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
306317
if (Ptr.isDummy())
307318
return false;
@@ -607,11 +618,8 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
607618
// variables in Compiler.cpp:visitDeclRef. Revisiting a so far
608619
// unknown variable will get the same EvalID and we end up allowing
609620
// reads from mutable members of it.
610-
if (!S.inConstantContext()) {
611-
if (const VarDecl *VD = Ptr.block()->getDescriptor()->asVarDecl();
612-
VD && VD->hasLocalStorage())
613-
return false;
614-
}
621+
if (!S.inConstantContext() && isConstexprUnknown(Ptr))
622+
return false;
615623
return true;
616624
}
617625

clang/lib/AST/ByteCode/Interp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
173173
bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
174174
const FixedPoint &FP);
175175

176+
bool isConstexprUnknown(const Pointer &P);
177+
176178
enum class ShiftDir { Left, Right };
177179

178180
/// Checks if the shift operation is legal.
@@ -1062,6 +1064,11 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
10621064
}
10631065
}
10641066

1067+
if (!S.inConstantContext()) {
1068+
if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS))
1069+
return false;
1070+
}
1071+
10651072
if (Pointer::hasSameBase(LHS, RHS)) {
10661073
unsigned VL = LHS.getByteOffset();
10671074
unsigned VR = RHS.getByteOffset();
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -fcxx-exceptions -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -fcxx-exceptions -o - %s -fexperimental-new-constant-interpreter | FileCheck %s
3+
4+
5+
/// In the if expression below, the read from s.i should fail.
6+
/// If it doesn't, and we actually read the value 0, the call to
7+
/// func() will always occur, resuliting in a runtime failure.
8+
9+
struct S {
10+
mutable int i = 0;
11+
};
12+
13+
void func() {
14+
__builtin_abort();
15+
};
16+
17+
void setI(const S &s) {
18+
s.i = 12;
19+
}
20+
21+
int main() {
22+
const S s;
23+
24+
setI(s);
25+
26+
if (s.i == 0)
27+
func();
28+
29+
return 0;
30+
}
31+
32+
// CHECK: define dso_local noundef i32 @main()
33+
// CHECK: br
34+
// CHECK: if.then
35+
// CHECK: if.end
36+
// CHECK: ret i32 0
37+
38+
39+
/// Similarly, here we revisit the BindingDecl.
40+
struct F { int x; };
41+
int main2() {
42+
const F const s{99};
43+
const auto& [r1] = s;
44+
if (&r1 != &s.x)
45+
__builtin_abort();
46+
return 0;
47+
}
48+
// CHECK: define dso_local noundef i32 @_Z5main2v()
49+
// CHECK: br
50+
// CHECK: if.then
51+
// CHECK: if.end
52+
// CHECK: ret i32 0
53+
54+
/// The comparison here should work and return 0.
55+
class X {
56+
public:
57+
X();
58+
X(const X&);
59+
X(const volatile X &);
60+
~X();
61+
};
62+
extern X OuterX;
63+
X test24() {
64+
X x;
65+
if (&x == &OuterX)
66+
throw 0;
67+
return x;
68+
}
69+
70+
// CHECK: define dso_local void @_Z6test24v
71+
// CHECK-NOT: lpad
72+
// CHECK-NOT: eh.resume

clang/test/AST/ByteCode/codegen-mutable-read.cpp

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)