21f2c66a0f
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) ```
184 lines
6.7 KiB
C++
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
|