From 4dd1ce8e56b4d391c8d85c90bcc0d3ae68a6134e Mon Sep 17 00:00:00 2001 From: Frederich Munch Date: Thu, 2 Feb 2017 12:44:32 -0500 Subject: [PATCH] Fix for Interpreter hanging on to states that can refer to a deleted llvm::Module. --- .../cling/Interpreter/ClangInternalState.h | 4 +++ lib/Interpreter/Interpreter.cpp | 31 +++++++++++++++++-- test/ErrorRecovery/StoredState.C | 19 ++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 test/ErrorRecovery/StoredState.C diff --git a/include/cling/Interpreter/ClangInternalState.h b/include/cling/Interpreter/ClangInternalState.h index c6159628..e9972ca8 100644 --- a/include/cling/Interpreter/ClangInternalState.h +++ b/include/cling/Interpreter/ClangInternalState.h @@ -81,6 +81,10 @@ namespace cling { const char* type = nullptr, bool verbose = false, const llvm::SmallVectorImpl* ignores = 0) const; + ///\brief Return the llvm::Module this state is bound too. + /// + const llvm::Module* getModule() const { return m_Module; } + static void printLookupTables(llvm::raw_ostream& Out, const clang::ASTContext& C); static void printIncludedFiles(llvm::raw_ostream& Out, const clang::SourceManager& SM); diff --git a/lib/Interpreter/Interpreter.cpp b/lib/Interpreter/Interpreter.cpp index f89d19e2..6e9fdece 100644 --- a/lib/Interpreter/Interpreter.cpp +++ b/lib/Interpreter/Interpreter.cpp @@ -314,10 +314,14 @@ namespace cling { } Interpreter::~Interpreter() { - if (m_Executor) - m_Executor->shuttingDown(); + // Do this first so m_StoredStates will be ignored if Interpreter::unload + // is called later on. for (size_t i = 0, e = m_StoredStates.size(); i != e; ++i) delete m_StoredStates[i]; + m_StoredStates.clear(); + + if (m_Executor) + m_Executor->shuttingDown(); if (CompilerInstance* CI = getCIOrNull()) getCI()->getDiagnostics().getClient()->EndSourceFile(); @@ -1177,6 +1181,29 @@ namespace cling { } void Interpreter::unload(Transaction& T) { + // Clear any stored states that reference the llvm::Module. + // Do it first in case + if (!m_StoredStates.empty()) { + const llvm::Module* const module = T.getModule(); + std::vector badStates; + for (unsigned i = 0, N = m_StoredStates.size(); i < N; ++i) { + if (m_StoredStates[i]->getModule() == module) { + badStates.push_back(i); + if (m_Opts.Verbose()) { + cling::errs() << "Unloading Transaction forced state '" + << m_StoredStates[i]->getName() + << "' to be destroyed\n"; + } + } + } + // Pop off the back so as not to recompute index. + // Should the user be warned in verbose mode? + for (std::vector::reverse_iterator it = badStates.rbegin(), + e = badStates.rend(); it != e; ++it) { + m_StoredStates.erase(m_StoredStates.begin()+(*it)); + } + } + if (InterpreterCallbacks* callbacks = getCallbacks()) callbacks->TransactionUnloaded(T); if (m_Executor) { // we also might be in fsyntax-only mode. diff --git a/test/ErrorRecovery/StoredState.C b/test/ErrorRecovery/StoredState.C new file mode 100644 index 00000000..2ad0f2bd --- /dev/null +++ b/test/ErrorRecovery/StoredState.C @@ -0,0 +1,19 @@ +//------------------------------------------------------------------------------ +// CLING - the C++ LLVM-based InterpreterG :) +// +// 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. +//------------------------------------------------------------------------------ + +// RUN: cat %s | %cling -v -Xclang -verify 2>&1 | FileCheck %s + +int i = 0; +.storeState "A" + +.undo +// CHECK: Unloading Transaction forced state 'A' to be destroyed + +// expected-no-diagnostics + +.q