Skip to content

Commit

Permalink
[clang][Interp] Make sure we free() allocated InitMaps
Browse files Browse the repository at this point in the history
They get allocated when calling initialize() on a primitive array. And
they get free'd when the array is fully initialized. However, when that
never happens, they get leaked. Fix that by calling the destructor of
global variables.

Differential Revision: https://reviews.llvm.org/D136826
  • Loading branch information
tbaederr committed Oct 28, 2022
1 parent 38ffc89 commit ee9bbfa
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 3 deletions.
7 changes: 6 additions & 1 deletion clang/lib/AST/Interp/Descriptor.cpp
Expand Up @@ -39,6 +39,11 @@ static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {

template <typename T>
static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
InitMap *IM = *reinterpret_cast<InitMap **>(Ptr);
if (IM != (InitMap *)-1)
free(IM);

Ptr += sizeof(InitMap *);
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
reinterpret_cast<T *>(Ptr)[I].~T();
}
Expand Down Expand Up @@ -178,7 +183,7 @@ static BlockCtorFn getCtorArrayPrim(PrimType Type) {
}

static BlockDtorFn getDtorArrayPrim(PrimType Type) {
COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr);
TYPE_SWITCH(Type, return dtorArrayTy<T>);
}

static BlockMoveFn getMoveArrayPrim(PrimType Type) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/InterpBlock.h
Expand Up @@ -73,6 +73,12 @@ class Block final {
/*isActive=*/true, Desc);
}

// Invokes the Destructor.
void invokeDtor() {
if (Desc->DtorFn)
Desc->DtorFn(this, data(), Desc);
}

protected:
friend class Pointer;
friend class DeadBlock;
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/AST/Interp/Pointer.cpp
Expand Up @@ -143,7 +143,7 @@ bool Pointer::isInitialized() const {
Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray()) {
if (Pointee->IsStatic)
if (isStatic() && Base == 0)
return true;
// Primitive array field are stored in a bitset.
InitMap *Map = getInitMap();
Expand All @@ -164,7 +164,11 @@ void Pointer::initialize() const {

assert(Desc);
if (Desc->isArray()) {
if (Desc->isPrimitiveArray() && !Pointee->IsStatic) {
if (Desc->isPrimitiveArray()) {
// Primitive global arrays don't have an initmap.
if (isStatic() && Base == 0)
return;

// Primitive array initializer.
InitMap *&Map = getInitMap();
if (Map == (InitMap *)-1)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Program.cpp
Expand Up @@ -64,6 +64,7 @@ unsigned Program::createGlobalString(const StringLiteral *S) {
unsigned Sz = Desc->getAllocSize();
auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
/*isExtern=*/false);
G->block()->invokeCtor();
Globals.push_back(G);

// Construct the string in storage.
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/Interp/Program.h
Expand Up @@ -47,6 +47,13 @@ class Program final {
// here manually so they are properly freeing their resources.
for (auto RecordPair : Records)
RecordPair.second->~Record();

// Manually destroy all the blocks. They are almost all harmless,
// but primitive arrays might have an InitMap* heap allocated and
// that needs to be freed.
for (Global *G : Globals) {
G->block()->invokeDtor();
}
}

/// Marshals a native pointer to an ID for embedding in bytecode.
Expand Down

0 comments on commit ee9bbfa

Please sign in to comment.