diff options
author | Liqiang Tao <taolq@outlook.com> | 2023-09-20 19:12:34 +0800 |
---|---|---|
committer | Liqiang Tao <taolq@outlook.com> | 2023-09-20 19:13:28 +0800 |
commit | 85ec68d69bca5ab9b150efc6dacb03c1696ea865 (patch) | |
tree | dabb380042ffeca7000120035e2516076a15a843 | |
parent | da26500aa82316f607ddc60e56982775d7f45cff (diff) | |
download | llvm-85ec68d69bca5ab9b150efc6dacb03c1696ea865.zip llvm-85ec68d69bca5ab9b150efc6dacb03c1696ea865.tar.gz llvm-85ec68d69bca5ab9b150efc6dacb03c1696ea865.tar.bz2 |
[IR] Fix a memory leak if Function::dropAllReferences() is followed by setHungoffOperand
This patch fixes a memory leak if Function::dropAllReferences() is followed by setHungoffOperand (e.g. setPersonality)
If NumUserOperands changes from 3 to 0 before calling allocHungoffUselist() to allocate memory,
the memory leaks which are allocated when NumUserOperands is changed from 0 to 3.
e.g.
```
llvm::Function* func = ...;
func->setPersonalityFn(foo); // (1). call allocHungoffUselist() to allocate memory for uses
func->deleteBody(); // (2). call dropAllReferences(), and it changes NumUserOperands from 3 to 0
// (3). at this point, NumUserOperands is 0, the next line will allocate memory by allocHungoffUselist()
func->setPersonalityFn(bar); // (4). call allocHungoffUselist(), so memory allocated in (1) leaks.
```
Reviewed By: dexonsmith, MaskRay
Differential Revision: https://reviews.llvm.org/D156618
-rw-r--r-- | llvm/include/llvm/IR/Function.h | 8 | ||||
-rw-r--r-- | llvm/lib/IR/Function.cpp | 24 |
2 files changed, 18 insertions, 14 deletions
diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h index 0feb536..692ef75 100644 --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -116,6 +116,8 @@ private: void clearArguments(); + void deleteBodyImpl(bool ShouldDrop); + /// Function ctor - If the (optional) Module argument is specified, the /// function is automatically inserted into the end of the function list for /// the module. @@ -667,7 +669,7 @@ public: /// the linkage to external. /// void deleteBody() { - dropAllReferences(); + deleteBodyImpl(/*ShouldDrop=*/false); setLinkage(ExternalLinkage); } @@ -882,7 +884,9 @@ public: /// function, dropping all references deletes the entire body of the function, /// including any contained basic blocks. /// - void dropAllReferences(); + void dropAllReferences() { + deleteBodyImpl(/*ShouldDrop=*/true); + } /// hasAddressTaken - returns true if there are any uses of this function /// other than direct calls or invokes to it, or blockaddress expressions. diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp index b1b8404..658aa67 100644 --- a/llvm/lib/IR/Function.cpp +++ b/llvm/lib/IR/Function.cpp @@ -518,15 +518,7 @@ void Function::stealArgumentListFrom(Function &Src) { Src.setValueSubclassData(Src.getSubclassDataFromValue() | (1 << 0)); } -// dropAllReferences() - This function causes all the subinstructions to "let -// go" of all references that they are maintaining. This allows one to -// 'delete' a whole class at a time, even though there may be circular -// references... first all references are dropped, and all use counts go to -// zero. Then everything is deleted for real. Note that no operations are -// valid on an object that has "dropped all references", except operator -// delete. -// -void Function::dropAllReferences() { +void Function::deleteBodyImpl(bool ShouldDrop) { setIsMaterializable(false); for (BasicBlock &BB : *this) @@ -537,10 +529,18 @@ void Function::dropAllReferences() { while (!BasicBlocks.empty()) BasicBlocks.begin()->eraseFromParent(); - // Drop uses of any optional data (real or placeholder). if (getNumOperands()) { - User::dropAllReferences(); - setNumHungOffUseOperands(0); + if (ShouldDrop) { + // Drop uses of any optional data (real or placeholder). + User::dropAllReferences(); + setNumHungOffUseOperands(0); + } else { + // The code needs to match Function::allocHungoffUselist(). + auto *CPN = ConstantPointerNull::get(PointerType::get(getContext(), 0)); + Op<0>().set(CPN); + Op<1>().set(CPN); + Op<2>().set(CPN); + } setValueSubclassData(getSubclassDataFromValue() & ~0xe); } |