[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
This commit is contained in:
Timm Bäder 2022-10-27 12:06:44 +02:00
parent 0dcfd0ce02
commit 99d3ead44c
4 changed files with 26 additions and 4 deletions

View File

@ -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();

View File

@ -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;
}

View File

@ -51,8 +51,10 @@ public:
// 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.

View File

@ -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;