Added support for dynamic sanity checking in

expressions.  Values used by the expression are
checked by validation functions which cause the
program to crash if the values are unsafe.

Major changes:

- Added IRDynamicChecks.[ch], which contains the
  core code related to this feature

- Modified CommandObjectExpression to install the
  validator functions into the target process.

- Added an accessor to Process that gets/sets the
  helper functions

llvm-svn: 112690
This commit is contained in:
Sean Callanan
2010-09-01 00:58:00 +00:00
parent 6aaebe877b
commit 6961e87847
7 changed files with 320 additions and 3 deletions

View File

@@ -0,0 +1,141 @@
//===-- IRDynamicChecks.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_IRDynamicChecks_h_
#define liblldb_IRDynamicChecks_h_
#include "llvm/Pass.h"
namespace llvm {
class BasicBlock;
class CallInst;
class Constant;
class Function;
class Instruction;
class Module;
class TargetData;
class Value;
}
namespace lldb_private
{
class ClangExpressionDeclMap;
class ClangUtilityFunction;
class ExecutionContext;
class Stream;
//----------------------------------------------------------------------
/// @class DynamicCheckerFunctions IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h"
/// @brief Encapsulates dynamic check functions used by expressions.
///
/// Each of the utility functions encapsulated in this class is responsible
/// for validating some data that an expression is about to use. Examples are:
///
/// a = *b; // check that b is a valid pointer
/// [b init]; // check that b is a valid object to send "init" to
///
/// The class installs each checker function into the target process and
/// makes it available to IRDynamicChecks to use.
//----------------------------------------------------------------------
class DynamicCheckerFunctions
{
public:
//------------------------------------------------------------------
/// Constructor
//------------------------------------------------------------------
DynamicCheckerFunctions ();
//------------------------------------------------------------------
/// Destructor
//------------------------------------------------------------------
~DynamicCheckerFunctions ();
//------------------------------------------------------------------
/// Install the utility functions into a process. This binds the
/// instance of DynamicCheckerFunctions to that process.
///
/// @param[in] error_stream
/// A stream to print errors on.
///
/// @param[in] exe_ctx
/// The execution context to install the functions into.
///
/// @return
/// True on success; false on failure, or if the functions have
/// already been installed.
//------------------------------------------------------------------
bool Install (Stream &error_stream,
ExecutionContext &exe_ctx);
std::auto_ptr<ClangUtilityFunction> m_valid_pointer_check;
};
//----------------------------------------------------------------------
/// @class IRDynamicChecks IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h"
/// @brief Adds dynamic checks to a user-entered expression to reduce its likelihood of crashing
///
/// When an IR function is executed in the target process, it may cause
/// crashes or hangs by dereferencing NULL pointers, trying to call Objective-C
/// methods on objects that do not respond to them, and so forth.
///
/// IRDynamicChecks adds calls to the functions in DynamicCheckerFunctions
/// to appropriate locations in an expression's IR.
//----------------------------------------------------------------------
class IRDynamicChecks : public llvm::ModulePass
{
public:
//------------------------------------------------------------------
/// Constructor
///
/// @param[in] checker_functions
/// The checker functions for the target process.
///
/// @param[in] func_name
/// The name of the function to prepare for execution in the target.
//------------------------------------------------------------------
IRDynamicChecks(DynamicCheckerFunctions &checker_functions,
const char* func_name = "___clang_expr");
//------------------------------------------------------------------
/// Destructor
//------------------------------------------------------------------
~IRDynamicChecks();
//------------------------------------------------------------------
/// Run this IR transformer on a single module
///
/// @param[in] M
/// The module to run on. This module is searched for the function
/// ___clang_expr, and that function is passed to the passes one by
/// one.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool runOnModule(llvm::Module &M);
//------------------------------------------------------------------
/// Interface stub
//------------------------------------------------------------------
void assignPassManager(llvm::PMStack &PMS,
llvm::PassManagerType T = llvm::PMT_ModulePassManager);
//------------------------------------------------------------------
/// Returns PMT_ModulePassManager
//------------------------------------------------------------------
llvm::PassManagerType getPotentialPassManagerType() const;
private:
std::string m_func_name; ///< The name of the function to add checks to
DynamicCheckerFunctions &m_checker_functions; ///< The checker functions for the process
};
}
#endif

View File

@@ -26,6 +26,7 @@
#include "lldb/Core/PluginInterface.h"
#include "lldb/Breakpoint/BreakpointSiteList.h"
#include "lldb/Expression/ClangPersistentVariables.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/ObjCObjectPrinter.h"
#include "lldb/Target/ThreadList.h"
@@ -1353,6 +1354,16 @@ public:
bool
IsRunning () const;
DynamicCheckerFunctions *GetDynamicCheckers()
{
return m_dynamic_checkers.get();
}
void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers)
{
m_dynamic_checkers.reset(dynamic_checkers);
}
//------------------------------------------------------------------
// lldb::ExecutionContextScope pure virtual functions
@@ -1405,6 +1416,7 @@ protected:
BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend
///< to insert in the target.
ClangPersistentVariables m_persistent_vars; ///< These are the persistent variables associated with this process for the expression parser.
std::auto_ptr<DynamicCheckerFunctions> m_dynamic_checkers; ///< The functions used by the expression parser to validate data that expressions use.
UnixSignals m_unix_signals; /// This is the current signal set for this process.
ConstString m_target_triple;
lldb::ABISP m_abi_sp;

View File

@@ -341,6 +341,8 @@
49A8A3A011D568A300AD3B68 /* ASTResultSynthesizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */; };
49A8A3A411D568BF00AD3B68 /* ASTResultSynthesizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */; };
49BB309611F79450001A4197 /* TaggedASTType.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BB309511F79450001A4197 /* TaggedASTType.h */; };
49CF982A122C70BD007A0B96 /* IRDynamicChecks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */; };
49CF9834122C718B007A0B96 /* IRDynamicChecks.h in Headers */ = {isa = PBXBuildFile; fileRef = 49CF9833122C718B007A0B96 /* IRDynamicChecks.h */; };
49D4FE831210B5FB00CDB854 /* ClangPersistentVariables.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */; };
49D4FE891210B61C00CDB854 /* ClangPersistentVariables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */; };
49D7072711B5AD03001AD875 /* ClangASTSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 49D7072611B5AD03001AD875 /* ClangASTSource.h */; };
@@ -933,6 +935,8 @@
49BB309511F79450001A4197 /* TaggedASTType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaggedASTType.h; path = include/lldb/Symbol/TaggedASTType.h; sourceTree = "<group>"; };
49BF48DC11ADF356008863BD /* ObjCObjectPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjCObjectPrinter.cpp; path = source/Target/ObjCObjectPrinter.cpp; sourceTree = "<group>"; };
49BF48E011ADF37D008863BD /* ObjCObjectPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCObjectPrinter.h; path = include/lldb/Target/ObjCObjectPrinter.h; sourceTree = "<group>"; };
49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRDynamicChecks.cpp; path = source/Expression/IRDynamicChecks.cpp; sourceTree = "<group>"; };
49CF9833122C718B007A0B96 /* IRDynamicChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRDynamicChecks.h; path = include/lldb/Expression/IRDynamicChecks.h; sourceTree = "<group>"; };
49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangPersistentVariables.h; path = include/lldb/Expression/ClangPersistentVariables.h; sourceTree = "<group>"; };
49D4FE871210B61C00CDB854 /* ClangPersistentVariables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangPersistentVariables.cpp; path = source/Expression/ClangPersistentVariables.cpp; sourceTree = "<group>"; };
49D7072611B5AD03001AD875 /* ClangASTSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangASTSource.h; path = include/lldb/Expression/ClangASTSource.h; sourceTree = "<group>"; };
@@ -1882,6 +1886,8 @@
49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */,
4911934B1226383D00578B7F /* ASTStructExtractor.h */,
491193501226386000578B7F /* ASTStructExtractor.cpp */,
49CF9833122C718B007A0B96 /* IRDynamicChecks.h */,
49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */,
49307AB111DEA4F20081F992 /* IRForTarget.h */,
49307AAD11DEA4D90081F992 /* IRForTarget.cpp */,
49DA743411DE6BB2006AEF7E /* IRToDWARF.h */,
@@ -2254,6 +2260,7 @@
49445E351225AB6A00C11A81 /* ClangUserExpression.h in Headers */,
4911934C1226383D00578B7F /* ASTStructExtractor.h in Headers */,
497C86C2122823F300B54702 /* ClangUtilityFunction.h in Headers */,
49CF9834122C718B007A0B96 /* IRDynamicChecks.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2308,7 +2315,6 @@
isa = PBXProject;
buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "lldb" */;
compatibilityVersion = "Xcode 3.1";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
en,
@@ -2713,6 +2719,7 @@
49445C2612245E3600C11A81 /* ClangExpressionParser.cpp in Sources */,
491193521226386000578B7F /* ASTStructExtractor.cpp in Sources */,
497C86BE122823D800B54702 /* ClangUtilityFunction.cpp in Sources */,
49CF982A122C70BD007A0B96 /* IRDynamicChecks.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -190,6 +190,27 @@ bool
CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream,
CommandReturnObject *result)
{
if (!m_exe_ctx.process)
{
error_stream.Printf ("Execution context doesn't contain a process");
return false;
}
if (!m_exe_ctx.process->GetDynamicCheckers())
{
DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
StreamString install_errors;
if (!dynamic_checkers->Install(install_errors, m_exe_ctx))
{
error_stream.Printf("Couldn't install dynamic checkers into the execution context: %s", install_errors.GetData());
return false;
}
m_exe_ctx.process->SetDynamicCheckers(dynamic_checkers);
}
ClangUserExpression user_expression (expr);
if (!user_expression.Parse (error_stream, m_exe_ctx))

View File

@@ -13,8 +13,10 @@
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Expression/ClangASTSource.h"
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRForTarget.h"
#include "lldb/Expression/IRToDWARF.h"
#include "lldb/Expression/RecordingMemoryManager.h"
@@ -409,6 +411,15 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_addr,
err.SetErrorString("Couldn't convert the expression to DWARF");
return err;
}
IRDynamicChecks ir_dynamic_checks(*exe_ctx.process->GetDynamicCheckers(), m_expr.FunctionName());
if (!ir_dynamic_checks.runOnModule(*module))
{
err.SetErrorToGenericError();
err.SetErrorString("Couldn't add dynamic checks to the expression");
return err;
}
}
m_jit_mm = new RecordingMemoryManager();

View File

@@ -37,7 +37,9 @@ using namespace lldb_private;
ClangUtilityFunction::ClangUtilityFunction (const char *text,
const char *name) :
m_function_text(text),
m_function_name(name)
m_function_name(name),
m_jit_begin(LLDB_INVALID_ADDRESS),
m_jit_end(LLDB_INVALID_ADDRESS)
{
}
@@ -56,7 +58,13 @@ ClangUtilityFunction::ClangUtilityFunction (const char *text,
bool
ClangUtilityFunction::Install (Stream &error_stream,
ExecutionContext &exe_ctx)
{
{
if (m_jit_begin != LLDB_INVALID_ADDRESS)
{
error_stream.PutCString("error: already installed\n");
return false;
}
////////////////////////////////////
// Set up the target and compiler
//

View File

@@ -0,0 +1,117 @@
//===-- IRDynamicChecks.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/ClangUtilityFunction.h"
#include "lldb/Core/Log.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Function.h"
#include "llvm/Module.h"
#include "llvm/Value.h"
using namespace llvm;
using namespace lldb_private;
static char ID;
static const char valid_pointer_check_text[] =
"extern \"C\" void "
"___clang_valid_pointer_check (unsigned char *ptr)"
"{"
"unsigned char val = *ptr;"
"}";
static const char valid_pointer_check_name[] =
"___clang_valid_pointer_check";
DynamicCheckerFunctions::DynamicCheckerFunctions ()
{
m_valid_pointer_check.reset(new ClangUtilityFunction(valid_pointer_check_text,
valid_pointer_check_name));
}
DynamicCheckerFunctions::~DynamicCheckerFunctions ()
{
}
bool
DynamicCheckerFunctions::Install(Stream &error_stream,
ExecutionContext &exe_ctx)
{
if (!m_valid_pointer_check->Install(error_stream, exe_ctx))
return false;
return true;
}
IRDynamicChecks::IRDynamicChecks(DynamicCheckerFunctions &checker_functions,
const char *func_name) :
ModulePass(&ID),
m_checker_functions(checker_functions),
m_func_name(func_name)
{
}
/* A handy utility function used at several places in the code */
static std::string
PrintValue(llvm::Value *V, bool truncate = false)
{
std::string s;
raw_string_ostream rso(s);
V->print(rso);
rso.flush();
if (truncate)
s.resize(s.length() - 1);
return s;
}
IRDynamicChecks::~IRDynamicChecks()
{
}
bool
IRDynamicChecks::runOnModule(llvm::Module &M)
{
lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str()));
if (!function)
{
if (log)
log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
return false;
}
llvm::Function::iterator bbi;
for (bbi = function->begin();
bbi != function->end();
++bbi)
{
}
return true;
}
void
IRDynamicChecks::assignPassManager(PMStack &PMS,
PassManagerType T)
{
}
PassManagerType
IRDynamicChecks::getPotentialPassManagerType() const
{
return PMT_ModulePassManager;
}