cling/lib/Interpreter/TransactionUnloader.cpp
Axel Naumann 21f2c66a0f Delete globals before JIT deletes the module:
Fixes root-meta-execUnloading which shows
```==768591== Invalid read of size 8
==768591==    at 0x6EFB10E: llvm::ilist_node_base<false>::getNext() const (ilist_node_base.h:29)
==768591==    by 0x6FBF119: llvm::ilist_node_impl<llvm::ilist_detail::node_options<llvm::Function, false, false, void> >::getNext() (ilist_node.h:66)
==768591==    by 0x6FBED48: llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Function, false, false, void>, false, false>::operator++() (ilist_iterator.h:157)
==768591==    by 0x6FBEA20: llvm::simple_ilist<llvm::Function>::begin() (simple_ilist.h:117)
==768591==    by 0x6FBE40F: llvm::Module::begin() (Module.h:622)
==768591==    by 0x6FBE475: llvm::Module::functions() (Module.h:634)
==768591==    by 0x6FBE22F: cling::TransactionUnloader::unloadModule(llvm::Module*) (TransactionUnloader.cpp:175)
==768591==    by 0x6FBDF83: cling::TransactionUnloader::RevertTransaction(cling::Transaction*) (TransactionUnloader.cpp:126)
==768591==    by 0x6F90CD0: cling::Interpreter::unload(cling::Transaction&) (Interpreter.cpp:1553)
==768591==    by 0x6F90E25: cling::Interpreter::unload(unsigned int) (Interpreter.cpp:1574)
==768591==    by 0x721A9F2: cling::MetaSema::actOnUndoCommand(unsigned int) (MetaSema.cpp:186)
```
...
```
==768591==  Address 0x144b0ce0 is 32 bytes inside a block of size 800 free'd
==768591==    at 0x484399B: operator delete(void*, unsigned long) (vg_replace_malloc.c:935)
==768591==    by 0x6FBC7CA: std::default_delete<llvm::Module>::operator()(llvm::Module*) const (unique_ptr.h:95)
==768591==    by 0x6FBC82D: std::__uniq_ptr_impl<llvm::Module, std::default_delete<llvm::Module> >::reset(llvm::Module*) (unique_ptr.h:203)
==768591==    by 0x6FBC87E: std::unique_ptr<llvm::Module, std::default_delete<llvm::Module> >::reset(llvm::Module*) (unique_ptr.h:501)
==768591==    by 0x6FBC04E: std::unique_ptr<llvm::Module, std::default_delete<llvm::Module> >::operator=(decltype(nullptr)) (unique_ptr.h:434)
==768591==    by 0x70E60E7: llvm::orc::ThreadSafeModule::~ThreadSafeModule() (ThreadSafeModule.h:116)
==768591==    by 0x936EC79: llvm::orc::IRMaterializationUnit::~IRMaterializationUnit() (Layer.h:31)
==768591==    by 0x93707F5: llvm::orc::BasicIRLayerMaterializationUnit::~BasicIRLayerMaterializationUnit() (Layer.h:121)
==768591==    by 0x9370811: llvm::orc::BasicIRLayerMaterializationUnit::~BasicIRLayerMaterializationUnit() (Layer.h:121)
==768591==    by 0x6E91B45: std::default_delete<llvm::orc::MaterializationUnit>::operator()(llvm::orc::MaterializationUnit*) const (unique_ptr.h:95)
==768591==    by 0x6E8F9A3: std::unique_ptr<llvm::orc::MaterializationUnit, std::default_delete<llvm::orc::MaterializationUnit> >::~unique_ptr() (unique_ptr.h:396)
==768591==    by 0x935D3C3: llvm::orc::JITDylib::UnmaterializedInfo::~UnmaterializedInfo() (Core.h:1062)
==768591==    by 0x935D3DE: void std::_Destroy<llvm::orc::JITDylib::UnmaterializedInfo>(llvm::orc::JITDylib::UnmaterializedInfo*) (stl_construct.h:151)
==768591==    by 0x935D26B: void std::allocator_traits<std::allocator<void> >::destroy<llvm::orc::JITDylib::UnmaterializedInfo>(std::allocator<void>&, llvm::orc::JITDylib::UnmaterializedInfo*) (alloc_traits.h:648)
==768591==    by 0x935CBA0: std::_Sp_counted_ptr_inplace<llvm::orc::JITDylib::UnmaterializedInfo, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:613)
==768591==    by 0x6C39FCE: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:346)
==768591==    by 0x6C3CB36: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr_base.h:1071)
==768591==    by 0x6E98CED: std::__shared_ptr<llvm::orc::JITDylib::UnmaterializedInfo, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr_base.h:1524)
==768591==    by 0x6E98D09: std::shared_ptr<llvm::orc::JITDylib::UnmaterializedInfo>::~shared_ptr() (shared_ptr.h:175)
==768591==    by 0x932D614: llvm::DenseMapBase<llvm::DenseMap<llvm::orc::SymbolStringPtr, std::shared_ptr<llvm::orc::JITDylib::UnmaterializedInfo>, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr>, llvm::detail::DenseMapPair<llvm::orc::SymbolStringPtr, std::shared_ptr<llvm::orc::JITDylib::UnmaterializedInfo> > >, llvm::orc::SymbolStringPtr, std::shared_ptr<llvm::orc::JITDylib::UnmaterializedInfo>, llvm::DenseMapInfo<llvm::orc::SymbolStringPtr>, llvm::detail::DenseMapPair<llvm::orc::SymbolStringPtr, std::shared_ptr<llvm::orc::JITDylib::UnmaterializedInfo> > >::erase(llvm::orc::SymbolStringPtr const&) (DenseMap.h:307)
==768591==    by 0x931028D: llvm::orc::JITDylib::removeTracker(llvm::orc::ResourceTracker&) (Core.cpp:1510)
==768591==    by 0x9315060: llvm::orc::ExecutionSession::removeResourceTracker(llvm::orc::ResourceTracker&)::{lambda()#1}::operator()() const (Core.cpp:2155)
==768591==    by 0x93150D0: decltype(auto) llvm::orc::ExecutionSession::runSessionLocked<llvm::orc::ExecutionSession::removeResourceTracker(llvm::orc::ResourceTracker&)::{lambda()#1}>(llvm::orc::ExecutionSession::removeResourceTracker(llvm::orc::ResourceTracker&)::{lambda()#1}&&) (Core.h:1326)
==768591==    by 0x9315272: llvm::orc::ExecutionSession::removeResourceTracker(llvm::orc::ResourceTracker&) (Core.cpp:2152)
==768591==    by 0x93060FD: llvm::orc::ResourceTracker::remove() (Core.cpp:53)
==768591==    by 0x70F1D58: cling::IncrementalJIT::removeModule(cling::Transaction const&) (IncrementalJIT.cpp:151)
==768591==    by 0x6FBE6CF: cling::IncrementalExecutor::unloadModule(cling::Transaction const&) const (IncrementalExecutor.h:180)
==768591==    by 0x6FBDE5B: cling::TransactionUnloader::RevertTransaction(cling::Transaction*) (TransactionUnloader.cpp:119)
==768591==    by 0x6F90CD0: cling::Interpreter::unload(cling::Transaction&) (Interpreter.cpp:1553)
==768591==    by 0x6F90E25: cling::Interpreter::unload(unsigned int) (Interpreter.cpp:1574)
==768591==    by 0x721A9F2: cling::MetaSema::actOnUndoCommand(unsigned int) (MetaSema.cpp:186)
```
2022-12-09 08:44:20 +01:00

184 lines
6.7 KiB
C++

//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "TransactionUnloader.h"
#include "IncrementalExecutor.h"
#include "DeclUnloader.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Sema.h"
using namespace clang;
namespace cling {
bool TransactionUnloader::unloadDeclarations(Transaction* T,
DeclUnloader& DeclU) {
bool Successful = true;
for (Transaction::const_reverse_iterator I = T->rdecls_begin(),
E = T->rdecls_end(); I != E; ++I) {
const Transaction::ConsumerCallInfo& Call = I->m_Call;
const DeclGroupRef& DGR = (*I).m_DGR;
if (Call == Transaction::kCCIHandleVTable)
continue;
// The documentation for `ASTConsumer::HandleCXXImplicitFunctionInstantiation()`
// states that implicit function instantiations come through both
// `HandleCXXImplicitFunctionInstantiation` (before the body is intantiated)
// and `HandleTopLevelDecl` (after).
// Therefore, the same decl is duplicated in the transaction differing in the ConsumerCallInfo. `UnloadDecl()` should be called only once.
if (Call == Transaction::kCCIHandleCXXImplicitFunctionInstantiation)
continue;
// The non templated classes come through HandleTopLevelDecl and
// HandleTagDeclDefinition, this is why we need to filter.
if (Call == Transaction::kCCIHandleTagDeclDefinition) {
if (const CXXRecordDecl* D
= dyn_cast<CXXRecordDecl>(DGR.getSingleDecl()))
if (D->getTemplateSpecializationKind() == TSK_Undeclared)
continue;
}
if (Call == Transaction::kCCINone)
m_Interp->unload(*(*T->rnested_begin()));
for (DeclGroupRef::const_iterator
Di = DGR.end() - 1, E = DGR.begin() - 1; Di != E; --Di) {
// Get rid of the declaration. If the declaration has name we should
// heal the lookup tables as well
Successful = DeclU.UnloadDecl(*Di) && Successful;
#ifndef NDEBUG
assert(Successful && "Cannot handle that yet!");
#endif
}
}
assert(T->rnested_begin() == T->rnested_end()
&& "nested transactions mismatch");
return Successful;
}
bool TransactionUnloader::unloadFromPreprocessor(Transaction* T,
DeclUnloader& DeclU) {
bool Successful = true;
for (Transaction::const_reverse_macros_iterator MI = T->rmacros_begin(),
ME = T->rmacros_end(); MI != ME; ++MI) {
// Get rid of the macro definition
Successful = DeclU.UnloadMacro(*MI) && Successful;
#ifndef NDEBUG
assert(Successful && "Cannot handle that yet!");
#endif
}
return Successful;
}
bool TransactionUnloader::unloadDeserializedDeclarations(Transaction* T,
DeclUnloader& DeclU) {
//FIXME: Terrible hack, we *must* get rid of parseForModule by implementing
// a header file generator in cling.
bool Successful = true;
for (Transaction::const_reverse_iterator I = T->deserialized_rdecls_begin(),
E = T->deserialized_rdecls_end(); I != E; ++I) {
const DeclGroupRef& DGR = (*I).m_DGR;
for (DeclGroupRef::const_iterator
Di = DGR.end() - 1, E = DGR.begin() - 1; Di != E; --Di) {
// UnloadDecl() shall unload decls that came through `parseForModule()',
// but not those that came from the PCH.
Successful = DeclU.UnloadDecl(*Di) && Successful;
#ifndef NDEBUG
assert(Successful && "Cannot handle that yet!");
#endif
}
}
return Successful;
}
#ifndef NDEBUG
static bool isPracticallyEmptyModule(const llvm::Module* M) {
return M->empty() && M->global_empty() && M->alias_empty();
}
#endif
bool TransactionUnloader::RevertTransaction(Transaction* T) {
bool Successful = true;
if (getExecutor()) {
if (T->getState() == Transaction::kCommitted && !T->isNestedTransaction()) {
if (const llvm::Module *CompiledM = T->getCompiledModule())
Successful = unloadModule(const_cast<llvm::Module*>(CompiledM)) &&
Successful;
else
assert((!T->getModule() || isPracticallyEmptyModule(T->getModule()))
&& "Must have already compiled this module");
}
// getExecutor()->unloadModule() will free globals - so first run
// this->unloadModule().
if (llvm::Error Err = getExecutor()->unloadModule(*T)) {
llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "Unload: ");
Successful = false;
}
// Cleanup the module from unused global values.
// if (T->getModule()) {
// llvm::ModulePass* globalDCE = llvm::createGlobalDCEPass();
// globalDCE->runOnModule(*T->getModule());
// }
}
// Clean up the pending instantiations
m_Sema->PendingInstantiations.clear();
m_Sema->PendingLocalImplicitInstantiations.clear();
DeclUnloader DeclU(m_Sema, m_CodeGen, T);
Successful = unloadDeclarations(T, DeclU) && Successful;
Successful = unloadDeserializedDeclarations(T, DeclU) && Successful;
Successful = unloadFromPreprocessor(T, DeclU) && Successful;
#ifndef NDEBUG
//FIXME: Move the nested transaction marker out of the decl lists and
// reenable this assertion.
//size_t DeclSize = std::distance(T->decls_begin(), T->decls_end());
//if (T->getCompilationOpts().CodeGenerationForModule)
// assert (!DeclSize && "No parsed decls must happen in parse for module");
#endif
if (Successful)
T->setState(Transaction::kRolledBack);
else
T->setState(Transaction::kRolledBackWithErrors);
// Release the input_line_X file unless verifying diagnostics.
if (!m_Interp->getCI()->getDiagnosticOpts().VerifyDiagnostics)
m_Sema->getSourceManager().invalidateCache(T->getBufferFID());
return Successful;
}
bool TransactionUnloader::UnloadDecl(Decl* D) {
return cling::UnloadDecl(m_Sema, m_CodeGen, D);
}
bool
TransactionUnloader::unloadModule(llvm::Module* M) {
for (auto& Func: M->functions())
m_CodeGen->forgetGlobal(&Func);
for (auto& Glob: M->globals())
m_CodeGen->forgetGlobal(&Glob);
return true;
}
} // end namespace cling