[clang] ee9bbfa - [clang][Interp] Make sure we free() allocated InitMaps
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 28 08:01:27 PDT 2022
Author: Timm Bäder
Date: 2022-10-28T17:00:15+02:00
New Revision: ee9bbfa5e6acaea6d2a116bc29b7086441f86b6a
URL: https://github.com/llvm/llvm-project/commit/ee9bbfa5e6acaea6d2a116bc29b7086441f86b6a
DIFF: https://github.com/llvm/llvm-project/commit/ee9bbfa5e6acaea6d2a116bc29b7086441f86b6a.diff
LOG: [clang][Interp] Make sure we free() allocated InitMaps
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
Added:
Modified:
clang/lib/AST/Interp/Descriptor.cpp
clang/lib/AST/Interp/InterpBlock.h
clang/lib/AST/Interp/Pointer.cpp
clang/lib/AST/Interp/Program.cpp
clang/lib/AST/Interp/Program.h
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp
index 34240ed4352d..55182ec383fa 100644
--- a/clang/lib/AST/Interp/Descriptor.cpp
+++ b/clang/lib/AST/Interp/Descriptor.cpp
@@ -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();
}
@@ -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) {
diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h
index e4e693dab093..9c0b5612b9fa 100644
--- a/clang/lib/AST/Interp/InterpBlock.h
+++ b/clang/lib/AST/Interp/InterpBlock.h
@@ -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;
diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index ad4e4e8a8a85..c7d9c3a5cd11 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -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();
@@ -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)
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index cca59bee1f20..8ad48976f33d 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -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.
diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
index 1a175d8b0f20..5123dde88c87 100644
--- a/clang/lib/AST/Interp/Program.h
+++ b/clang/lib/AST/Interp/Program.h
@@ -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.
More information about the cfe-commits
mailing list