Skip to content

Commit cb7b10c

Browse files
authored
[clang][bytecode] Fail on mutable reads from revisited variables (#133064)
When revisiting a variable, we do that by simply calling visitDecl() for it, which means it will end up with the same EvalID as the rest of the evaluation - but this way we end up allowing reads from mutable variables. Disallow that.
1 parent 6ff3906 commit cb7b10c

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,18 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
602602
// In C++14 onwards, it is permitted to read a mutable member whose
603603
// lifetime began within the evaluation.
604604
if (S.getLangOpts().CPlusPlus14 &&
605-
Ptr.block()->getEvalID() == S.Ctx.getEvalID())
605+
Ptr.block()->getEvalID() == S.Ctx.getEvalID()) {
606+
// FIXME: This check is necessary because (of the way) we revisit
607+
// variables in Compiler.cpp:visitDeclRef. Revisiting a so far
608+
// unknown variable will get the same EvalID and we end up allowing
609+
// 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+
}
606615
return true;
616+
}
607617

608618
const SourceInfo &Loc = S.Current->getSource(OpPC);
609619
const FieldDecl *Field = Ptr.getField();
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -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

0 commit comments

Comments
 (0)