[clang] 99d3ead - [clang][Interp] Protect Record creation against infinite recursion
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 10 23:38:36 PST 2022
Author: Timm Bäder
Date: 2022-11-11T08:38:06+01:00
New Revision: 99d3ead44cfb21dca24c63a0b0731eaad54b491e
URL: https://github.com/llvm/llvm-project/commit/99d3ead44cfb21dca24c63a0b0731eaad54b491e
DIFF: https://github.com/llvm/llvm-project/commit/99d3ead44cfb21dca24c63a0b0731eaad54b491e.diff
LOG: [clang][Interp] Protect Record creation against infinite recursion
This happens only in error cases, but we need to handle it anyway.
Differential Revision: https://reviews.llvm.org/D136831
Added:
Modified:
clang/lib/AST/Interp/ByteCodeStmtGen.cpp
clang/lib/AST/Interp/Program.cpp
clang/lib/AST/Interp/Program.h
clang/test/AST/Interp/records.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index a6aa8d88622a..19cdc2a00888 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -98,7 +98,8 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
if (const auto Ctor = dyn_cast<CXXConstructorDecl>(F)) {
const RecordDecl *RD = Ctor->getParent();
const Record *R = this->getRecord(RD);
- assert(R);
+ if (!R)
+ return false;
for (const auto *Init : Ctor->inits()) {
const Expr *InitExpr = Init->getInit();
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index 8ad48976f33d..3014062f37f4 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -221,6 +221,11 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
return It->second;
}
+ // We insert nullptr now and replace that later, so recursive calls
+ // to this function with the same RecordDecl don't run into
+ // infinite recursion.
+ Records.insert({RD, nullptr});
+
// Number of bytes required by fields and base classes.
unsigned BaseSize = 0;
// Number of bytes required by virtual base.
@@ -294,7 +299,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
std::move(VirtBases), VirtSize, BaseSize);
- Records.insert({RD, R});
+ Records[RD] = R;
return R;
}
diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
index 3e3843e71a4a..8ff7e49f7044 100644
--- a/clang/lib/AST/Interp/Program.h
+++ b/clang/lib/AST/Interp/Program.h
@@ -51,8 +51,10 @@ class Program final {
// Records might actually allocate memory themselves, but they
// are allocated using a BumpPtrAllocator. Call their desctructors
// here manually so they are properly freeing their resources.
- for (auto RecordPair : Records)
- RecordPair.second->~Record();
+ for (auto RecordPair : Records) {
+ if (Record *R = RecordPair.second)
+ R->~Record();
+ }
}
/// Marshals a native pointer to an ID for embedding in bytecode.
diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index f49a6736c135..63e957a9d045 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -133,6 +133,20 @@ constexpr C RVOAndParams(const C *c) {
constexpr C RVOAndParamsResult = RVOAndParams(&c);
#endif
+class Bar { // expected-note {{definition of 'Bar' is not complete}} \
+ // ref-note {{definition of 'Bar' is not complete}}
+public:
+ constexpr Bar(){}
+ constexpr Bar b; // expected-error {{cannot be constexpr}} \
+ // expected-error {{has incomplete type 'const Bar'}} \
+ // ref-error {{cannot be constexpr}} \
+ // ref-error {{has incomplete type 'const Bar'}}
+};
+constexpr Bar B; // expected-error {{must be initialized by a constant expression}} \
+ // expected-error {{failed to evaluate an expression}} \
+ // ref-error {{must be initialized by a constant expression}}
+constexpr Bar *pb = nullptr;
+
constexpr int locals() {
C c;
c.a = 10;
More information about the cfe-commits
mailing list