Skip to content

Commit 71efd74

Browse files
committed
Destroy the interpreters when they are owned.
This should fix a longstanding issue with resource deallocation in CppInterOp.
1 parent 27d762d commit 71efd74

File tree

1 file changed

+53
-24
lines changed

1 file changed

+53
-24
lines changed

lib/CppInterOp/CppInterOp.cpp

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@
4848
#include "llvm/Support/Casting.h"
4949
#include "llvm/Support/CommandLine.h"
5050
#include "llvm/Support/Debug.h"
51+
#include "llvm/Support/ManagedStatic.h"
5152
#include "llvm/Support/raw_os_ostream.h"
5253

5354
#include <algorithm>
5455
#include <cassert>
56+
#include <deque>
5557
#include <iterator>
5658
#include <map>
5759
#include <memory>
@@ -84,20 +86,47 @@ using namespace std;
8486
struct InterpreterInfo {
8587
compat::Interpreter* Interpreter = nullptr;
8688
bool isOwned = true;
89+
InterpreterInfo(compat::Interpreter* I, bool O)
90+
: Interpreter(I), isOwned(O) {}
91+
92+
// Enable move constructors.
93+
InterpreterInfo(InterpreterInfo&& other) noexcept
94+
: Interpreter(other.Interpreter), isOwned(other.isOwned) {
95+
other.Interpreter = nullptr;
96+
other.isOwned = false;
97+
}
98+
InterpreterInfo& operator=(InterpreterInfo&& other) noexcept {
99+
if (this != &other) {
100+
// Delete current resource if owned
101+
if (isOwned)
102+
delete Interpreter;
103+
104+
Interpreter = other.Interpreter;
105+
isOwned = other.isOwned;
106+
107+
other.Interpreter = nullptr;
108+
other.isOwned = false;
109+
}
110+
return *this;
111+
}
87112

88-
// Valgrind complains about __cxa_pure_virtual called when deleting
89-
// llvm::SectionMemoryManager::~SectionMemoryManager as part of the dtor
90-
// chain of the Interpreter.
91-
// This might fix the issue https://reviews.llvm.org/D107087
92-
// FIXME: For now we just leak the Interpreter.
93-
~InterpreterInfo() = default;
113+
~InterpreterInfo() {
114+
if (isOwned)
115+
delete Interpreter;
116+
}
117+
118+
// Disable copy semantics (to avoid accidental double deletes)
119+
InterpreterInfo(const InterpreterInfo&) = delete;
120+
InterpreterInfo& operator=(const InterpreterInfo&) = delete;
94121
};
95-
static llvm::SmallVector<InterpreterInfo, 8> sInterpreters;
122+
123+
// std::deque avoids relocations and calling the dtor of InterpreterInfo.
124+
static llvm::ManagedStatic<std::deque<InterpreterInfo>> sInterpreters;
96125

97126
static compat::Interpreter& getInterp() {
98-
assert(!sInterpreters.empty() &&
127+
assert(!sInterpreters->empty() &&
99128
"Interpreter instance must be set before calling this!");
100-
return *sInterpreters.back().Interpreter;
129+
return *sInterpreters->back().Interpreter;
101130
}
102131
static clang::Sema& getSema() { return getInterp().getCI()->getSema(); }
103132
static clang::ASTContext& getASTContext() { return getSema().getASTContext(); }
@@ -2934,52 +2963,52 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
29342963
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
29352964
}
29362965

2937-
sInterpreters.push_back({I, /*isOwned=*/true});
2966+
sInterpreters->emplace_back(I, /*isOwned=*/true);
29382967

29392968
return I;
29402969
}
29412970

29422971
bool DeleteInterpreter(TInterp_t I /*=nullptr*/) {
29432972
if (!I) {
2944-
sInterpreters.pop_back();
2973+
sInterpreters->pop_back();
29452974
return true;
29462975
}
29472976

2948-
auto* found =
2949-
std::find_if(sInterpreters.begin(), sInterpreters.end(),
2977+
auto found =
2978+
std::find_if(sInterpreters->begin(), sInterpreters->end(),
29502979
[&I](const auto& Info) { return Info.Interpreter == I; });
2951-
if (found == sInterpreters.end())
2980+
if (found == sInterpreters->end())
29522981
return false; // failure
29532982

2954-
sInterpreters.erase(found);
2983+
sInterpreters->erase(found);
29552984
return true;
29562985
}
29572986

29582987
bool ActivateInterpreter(TInterp_t I) {
29592988
if (!I)
29602989
return false;
29612990

2962-
auto* found =
2963-
std::find_if(sInterpreters.begin(), sInterpreters.end(),
2991+
auto found =
2992+
std::find_if(sInterpreters->begin(), sInterpreters->end(),
29642993
[&I](const auto& Info) { return Info.Interpreter == I; });
2965-
if (found == sInterpreters.end())
2994+
if (found == sInterpreters->end())
29662995
return false;
29672996

2968-
if (std::next(found) != sInterpreters.end()) // if not already last element.
2969-
std::rotate(found, found + 1, sInterpreters.end());
2997+
if (std::next(found) != sInterpreters->end()) // if not already last element.
2998+
std::rotate(found, found + 1, sInterpreters->end());
29702999

29713000
return true; // success
29723001
}
29733002

29743003
TInterp_t GetInterpreter() {
2975-
if (sInterpreters.empty())
3004+
if (sInterpreters->empty())
29763005
return nullptr;
2977-
return sInterpreters.back().Interpreter;
3006+
return sInterpreters->back().Interpreter;
29783007
}
29793008

29803009
void UseExternalInterpreter(TInterp_t I) {
2981-
assert(sInterpreters.empty() && "sInterpreter already in use!");
2982-
sInterpreters.push_back(
3010+
assert(sInterpreters->empty() && "sInterpreter already in use!");
3011+
sInterpreters->push_back(
29833012
{static_cast<compat::Interpreter*>(I), /*isOwned=*/false});
29843013
}
29853014

0 commit comments

Comments
 (0)