Make InterpreterException::diagnose virtual and return a boolean. Refactor inheritance chain for InterpreterException.
This commit is contained in:
parent
0153f63690
commit
4d41bd315f
@ -14,7 +14,7 @@ CLINGS := $(wildcard $(MODDIR)/lib/Interpreter/*.cpp) \
|
||||
$(wildcard $(MODDIR)/lib/TagsExtension/*.cpp) \
|
||||
$(wildcard $(MODDIR)/lib/Utils/*.cpp)
|
||||
CLINGO := $(call stripsrc,$(CLINGS:.cpp=.o))
|
||||
CLINGEXCEPO := $(call stripsrc,$(MODDIR)/lib/Interpreter/ExceptionRTTI.o)
|
||||
CLINGEXCEPO := $(call stripsrc,$(MODDIR)/lib/Interpreter/Exception.o)
|
||||
CLINGCOMPDH := $(call stripsrc,$(MODDIR)/lib/Interpreter/cling-compiledata.h)
|
||||
|
||||
CLINGDEP := $(CLINGO:.o=.d)
|
||||
|
@ -22,12 +22,16 @@ namespace clang {
|
||||
namespace cling {
|
||||
///\brief Base class for all interpreter exceptions.
|
||||
///
|
||||
class InterpreterException : public std::exception {
|
||||
class InterpreterException : public std::runtime_error {
|
||||
protected:
|
||||
clang::Sema* const m_Sema;
|
||||
public:
|
||||
InterpreterException(const std::string& Reason);
|
||||
InterpreterException(const char* What, clang::Sema* = nullptr);
|
||||
virtual ~InterpreterException() LLVM_NOEXCEPT;
|
||||
|
||||
virtual const char* what() const LLVM_NOEXCEPT;
|
||||
virtual void diagnose() const {}
|
||||
///\brief Return true if error was diagnosed false otherwise
|
||||
virtual bool diagnose() const;
|
||||
};
|
||||
|
||||
///\brief Exception that is thrown when a invalid pointer dereference is found
|
||||
@ -37,34 +41,27 @@ namespace cling {
|
||||
public:
|
||||
enum DerefType {INVALID_MEM, NULL_DEREF};
|
||||
private:
|
||||
clang::Sema* m_Sema;
|
||||
clang::Expr* m_Arg;
|
||||
clang::DiagnosticsEngine* m_Diags;
|
||||
DerefType m_Type;
|
||||
const clang::Expr* const m_Arg;
|
||||
const DerefType m_Type;
|
||||
public:
|
||||
InvalidDerefException(clang::Sema* S, clang::Expr* E, DerefType type);
|
||||
InvalidDerefException(clang::Sema* S, const clang::Expr* E, DerefType type);
|
||||
virtual ~InvalidDerefException() LLVM_NOEXCEPT;
|
||||
|
||||
const char* what() const LLVM_NOEXCEPT override;
|
||||
void diagnose() const override;
|
||||
bool diagnose() const override;
|
||||
};
|
||||
|
||||
///\brief Exception that pulls cling out of runtime-compilation (llvm + clang)
|
||||
/// errors.
|
||||
///
|
||||
/// If user code provokes an llvm::unreachable it will cause this exception
|
||||
/// to be thrown. Given that this is at the process's runtime and an
|
||||
/// interpreter error it inherits from InterpreterException and runtime_error.
|
||||
/// to be thrown.
|
||||
/// Note that this exception is *not* thrown during the execution of the
|
||||
/// user's code but during its compilation (at runtime).
|
||||
class CompilationException: public virtual InterpreterException,
|
||||
public virtual std::runtime_error {
|
||||
class CompilationException: public InterpreterException {
|
||||
public:
|
||||
CompilationException(const std::string& reason);
|
||||
CompilationException(const std::string& Reason);
|
||||
~CompilationException() LLVM_NOEXCEPT;
|
||||
|
||||
const char* what() const LLVM_NOEXCEPT override;
|
||||
|
||||
// Handle fatal llvm errors by throwing an exception.
|
||||
// Yes, throwing exceptions in error handlers is bad.
|
||||
// Doing nothing is pretty terrible, too.
|
||||
|
@ -55,7 +55,6 @@ add_cling_library(clingInterpreter OBJECT
|
||||
DynamicLookup.cpp
|
||||
DynamicExprInfo.cpp
|
||||
Exception.cpp
|
||||
ExceptionRTTI.cpp
|
||||
ExternalInterpreterSource.cpp
|
||||
ForwardDeclPrinter.cpp
|
||||
IncrementalExecutor.cpp
|
||||
|
@ -10,26 +10,95 @@
|
||||
|
||||
#include "cling/Interpreter/Exception.h"
|
||||
|
||||
#include "cling/Interpreter/InterpreterCallbacks.h"
|
||||
#include "cling/Interpreter/Interpreter.h"
|
||||
#include "cling/Utils/Validation.h"
|
||||
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "clang/Sema/SemaDiagnostic.h"
|
||||
|
||||
namespace cling {
|
||||
InvalidDerefException::InvalidDerefException(clang::Sema* S, clang::Expr* E,
|
||||
cling::InvalidDerefException::DerefType type)
|
||||
: m_Sema(S), m_Arg(E), m_Diags(&m_Sema->getDiagnostics()), m_Type(type) {}
|
||||
extern "C" {
|
||||
/// Throw an InvalidDerefException if the Arg pointer is invalid.
|
||||
///\param Interp: The interpreter that has compiled the code.
|
||||
///\param Expr: The expression corresponding determining the pointer value.
|
||||
///\param Arg: The pointer to be checked.
|
||||
///\returns void*, const-cast from Arg, to reduce the complexity in the
|
||||
/// calling AST nodes, at the expense of possibly doing a
|
||||
/// T* -> const void* -> const_cast<void*> -> T* round trip.
|
||||
void* cling_runtime_internal_throwIfInvalidPointer(void* Interp, void* Expr,
|
||||
const void* Arg) {
|
||||
|
||||
void InvalidDerefException::diagnose() const {
|
||||
const clang::Expr* const E = (const clang::Expr*)Expr;
|
||||
|
||||
// The isValidAddress function return true even when the pointer is
|
||||
// null thus the checks have to be done before returning successfully from the
|
||||
// function in this specific order.
|
||||
if (!Arg) {
|
||||
cling::Interpreter* I = (cling::Interpreter*)Interp;
|
||||
clang::Sema& S = I->getCI()->getSema();
|
||||
// Print a nice backtrace.
|
||||
I->getCallbacks()->PrintStackTrace();
|
||||
throw cling::InvalidDerefException(&S, E,
|
||||
cling::InvalidDerefException::DerefType::NULL_DEREF);
|
||||
} else if (!cling::utils::isAddressValid(Arg)) {
|
||||
cling::Interpreter* I = (cling::Interpreter*)Interp;
|
||||
clang::Sema& S = I->getCI()->getSema();
|
||||
// Print a nice backtrace.
|
||||
I->getCallbacks()->PrintStackTrace();
|
||||
throw cling::InvalidDerefException(&S, E,
|
||||
cling::InvalidDerefException::DerefType::INVALID_MEM);
|
||||
}
|
||||
return const_cast<void*>(Arg);
|
||||
}
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
InterpreterException::InterpreterException(const std::string& What) :
|
||||
std::runtime_error(What), m_Sema(nullptr) {}
|
||||
InterpreterException::InterpreterException(const char* What, clang::Sema* S) :
|
||||
std::runtime_error(What), m_Sema(S) {}
|
||||
|
||||
bool InterpreterException::diagnose() const { return false; }
|
||||
InterpreterException::~InterpreterException() LLVM_NOEXCEPT {}
|
||||
|
||||
|
||||
InvalidDerefException::InvalidDerefException(clang::Sema* S,
|
||||
const clang::Expr* E,
|
||||
DerefType type)
|
||||
: InterpreterException(type == INVALID_MEM ?
|
||||
"Trying to access a pointer that points to an invalid memory address." :
|
||||
"Trying to dereference null pointer or trying to call routine taking "
|
||||
"non-null arguments", S),
|
||||
m_Arg(E), m_Type(type) {}
|
||||
|
||||
InvalidDerefException::~InvalidDerefException() LLVM_NOEXCEPT {}
|
||||
|
||||
bool InvalidDerefException::diagnose() const {
|
||||
// Construct custom diagnostic: warning for invalid memory address;
|
||||
// no equivalent in clang.
|
||||
if (m_Type == cling::InvalidDerefException::DerefType::INVALID_MEM) {
|
||||
clang::DiagnosticsEngine& Diags = m_Sema->getDiagnostics();
|
||||
unsigned DiagID =
|
||||
m_Diags->getCustomDiagID(clang::DiagnosticsEngine::Warning,
|
||||
Diags.getCustomDiagID(clang::DiagnosticsEngine::Warning,
|
||||
"invalid memory pointer passed to a callee:");
|
||||
m_Diags->Report(m_Arg->getLocStart(), DiagID) << m_Arg->getSourceRange();
|
||||
Diags.Report(m_Arg->getLocStart(), DiagID) << m_Arg->getSourceRange();
|
||||
}
|
||||
else
|
||||
m_Sema->Diag(m_Arg->getLocStart(), clang::diag::warn_null_arg)
|
||||
<< m_Arg->getSourceRange();
|
||||
<< m_Arg->getSourceRange();
|
||||
return true;
|
||||
}
|
||||
|
||||
CompilationException::CompilationException(const std::string& Reason) :
|
||||
InterpreterException(Reason) {}
|
||||
|
||||
CompilationException::~CompilationException() LLVM_NOEXCEPT {}
|
||||
|
||||
void CompilationException::throwingHandler(void * /*user_data*/,
|
||||
const std::string& reason,
|
||||
bool /*gen_crash_diag*/) {
|
||||
throw cling::CompilationException(reason);
|
||||
}
|
||||
} // end namespace cling
|
||||
|
@ -1,88 +0,0 @@
|
||||
//--------------------------------------------------------------------*- C++ -*-
|
||||
// CLING - the C++ LLVM-based InterpreterG :)
|
||||
// author: Baozeng Ding <sploving1@gmail.com>
|
||||
// author: Vassil Vassilev <vasil.georgiev.vasilev@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 "cling/Interpreter/Exception.h"
|
||||
|
||||
#include "cling/Interpreter/InterpreterCallbacks.h"
|
||||
#include "cling/Interpreter/Interpreter.h"
|
||||
#include "cling/Utils/Validation.h"
|
||||
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
|
||||
extern "C" {
|
||||
/// Throw an InvalidDerefException if the Arg pointer is invalid.
|
||||
///\param Interp: The interpreter that has compiled the code.
|
||||
///\param Expr: The expression corresponding determining the pointer value.
|
||||
///\param Arg: The pointer to be checked.
|
||||
///\returns void*, const-cast from Arg, to reduce the complexity in the
|
||||
/// calling AST nodes, at the expense of possibly doing a
|
||||
/// T* -> const void* -> const_cast<void*> -> T* round trip.
|
||||
void* cling_runtime_internal_throwIfInvalidPointer(void* Interp, void* Expr,
|
||||
const void* Arg) {
|
||||
|
||||
clang::Expr* E = (clang::Expr*)Expr;
|
||||
|
||||
// The isValidAddress function return true even when the pointer is
|
||||
// null thus the checks have to be done before returning successfully from the
|
||||
// function in this specific order.
|
||||
if (!Arg) {
|
||||
cling::Interpreter* I = (cling::Interpreter*)Interp;
|
||||
clang::Sema& S = I->getCI()->getSema();
|
||||
// Print a nice backtrace.
|
||||
I->getCallbacks()->PrintStackTrace();
|
||||
throw cling::InvalidDerefException(&S, E,
|
||||
cling::InvalidDerefException::DerefType::NULL_DEREF);
|
||||
} else if (!cling::utils::isAddressValid(Arg)) {
|
||||
cling::Interpreter* I = (cling::Interpreter*)Interp;
|
||||
clang::Sema& S = I->getCI()->getSema();
|
||||
// Print a nice backtrace.
|
||||
I->getCallbacks()->PrintStackTrace();
|
||||
throw cling::InvalidDerefException(&S, E,
|
||||
cling::InvalidDerefException::DerefType::INVALID_MEM);
|
||||
}
|
||||
return const_cast<void*>(Arg);
|
||||
}
|
||||
}
|
||||
|
||||
namespace cling {
|
||||
// Pin vtable
|
||||
InterpreterException::~InterpreterException() LLVM_NOEXCEPT {}
|
||||
|
||||
const char* InterpreterException::what() const LLVM_NOEXCEPT {
|
||||
return "runtime_exception\n";
|
||||
}
|
||||
|
||||
InvalidDerefException::~InvalidDerefException() LLVM_NOEXCEPT {}
|
||||
|
||||
const char* InvalidDerefException::what() const LLVM_NOEXCEPT {
|
||||
// Invalid memory access.
|
||||
if (m_Type == cling::InvalidDerefException::DerefType::INVALID_MEM)
|
||||
return "Trying to access a pointer that points to an invalid memory address.";
|
||||
// Null deref.
|
||||
else
|
||||
return "Trying to dereference null pointer or trying to call routine taking non-null arguments";
|
||||
}
|
||||
|
||||
CompilationException::CompilationException(const std::string& reason) :
|
||||
std::runtime_error(reason) {}
|
||||
|
||||
CompilationException::~CompilationException() LLVM_NOEXCEPT {}
|
||||
|
||||
const char* CompilationException::what() const LLVM_NOEXCEPT {
|
||||
return std::runtime_error::what();
|
||||
}
|
||||
|
||||
void CompilationException::throwingHandler(void * /*user_data*/,
|
||||
const std::string& reason,
|
||||
bool /*gen_crash_diag*/) {
|
||||
throw cling::CompilationException(reason);
|
||||
}
|
||||
|
||||
} // end namespace cling
|
@ -129,16 +129,15 @@ namespace cling {
|
||||
Prompt.append(indent * 3, ' ');
|
||||
}
|
||||
}
|
||||
catch(InvalidDerefException& e) {
|
||||
e.diagnose();
|
||||
}
|
||||
catch(InterpreterException& e) {
|
||||
cling::errs() << ">>> Caught an interpreter exception!\n"
|
||||
<< ">>> " << e.what() << '\n';
|
||||
if (!e.diagnose()) {
|
||||
cling::errs() << ">>> Caught an interpreter exception!\n"
|
||||
<< ">>> " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
cling::errs() << ">>> Caught a std::exception!\n"
|
||||
<< ">>> " << e.what() << '\n';
|
||||
<< ">>> " << e.what() << '\n';
|
||||
}
|
||||
catch(...) {
|
||||
cling::errs() << "Exception occurred. Recovering...\n";
|
||||
|
Loading…
x
Reference in New Issue
Block a user