2013-07-13 16:27:53 +03:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
2013-07-27 21:11:21 +03:00
// author: Vassil Vassilev <vvasilev@cern.ch>
2013-07-13 16:27:53 +03:00
// author: Baozeng Ding <sploving1@gmail.com>
//------------------------------------------------------------------------------
# include "NullDerefProtectionTransformer.h"
# include "cling/Interpreter/Transaction.h"
# include "clang/AST/ASTContext.h"
# include "clang/AST/Decl.h"
# include "clang/AST/Mangle.h"
2013-07-27 21:11:21 +03:00
# include "clang/Sema/Sema.h"
# include "clang/Sema/SemaDiagnostic.h"
2013-07-13 16:27:53 +03:00
# include "llvm/IR/Module.h"
# include "llvm/IR/Constants.h"
# include "llvm/IR/IRBuilder.h"
# include "llvm/Support/raw_ostream.h"
# include "llvm/Support/InstIterator.h"
2013-07-18 14:23:48 +03:00
extern " C " {
int printf ( const char * . . . ) ;
int getchar ( void ) ;
2013-07-27 21:11:21 +03:00
bool shouldProceed ( void * S ) {
2013-07-18 14:23:48 +03:00
int input ;
2013-07-27 21:11:21 +03:00
clang : : Sema * Sem = ( clang : : Sema * ) S ;
clang : : DiagnosticsEngine & Diag = Sem - > getDiagnostics ( ) ;
Diag . Report ( Diag . getCurrentDiagLoc ( ) , clang : : diag : : warn_null_ptr_deref ) ;
2013-07-18 14:23:48 +03:00
input = getchar ( ) ;
getchar ( ) ;
if ( input = = ' y ' | | input = = ' Y ' ) return false ;
else return true ;
}
}
2013-07-27 21:11:21 +03:00
using namespace clang ;
2013-07-13 16:27:53 +03:00
namespace cling {
2013-07-27 21:11:21 +03:00
NullDerefProtectionTransformer : : NullDerefProtectionTransformer ( Sema * S )
: TransactionTransformer ( S ) , FailBB ( 0 ) , Builder ( 0 ) , Inst ( 0 ) { }
2013-07-13 16:27:53 +03:00
NullDerefProtectionTransformer : : ~ NullDerefProtectionTransformer ( )
{ }
void NullDerefProtectionTransformer : : Transform ( ) {
using namespace clang ;
FunctionDecl * FD = getTransaction ( ) - > getWrapperFD ( ) ;
if ( ! FD )
return ;
// Copied from Interpreter.cpp;
if ( ! m_MangleCtx )
m_MangleCtx . reset ( FD - > getASTContext ( ) . createMangleContext ( ) ) ;
std : : string mangledName ;
if ( m_MangleCtx - > shouldMangleDeclName ( FD ) ) {
llvm : : raw_string_ostream RawStr ( mangledName ) ;
switch ( FD - > getKind ( ) ) {
case Decl : : CXXConstructor :
//Ctor_Complete, // Complete object ctor
//Ctor_Base, // Base object ctor
//Ctor_CompleteAllocating // Complete object allocating ctor (unused)
m_MangleCtx - > mangleCXXCtor ( cast < CXXConstructorDecl > ( FD ) ,
Ctor_Complete , RawStr ) ;
break ;
case Decl : : CXXDestructor :
//Dtor_Deleting, // Deleting dtor
//Dtor_Complete, // Complete object dtor
//Dtor_Base // Base object dtor
m_MangleCtx - > mangleCXXDtor ( cast < CXXDestructorDecl > ( FD ) ,
Dtor_Deleting , RawStr ) ;
break ;
default :
m_MangleCtx - > mangleName ( FD , RawStr ) ;
break ;
}
RawStr . flush ( ) ;
} else {
mangledName = FD - > getNameAsString ( ) ;
}
// Find the function in the module.
2013-07-27 21:11:21 +03:00
llvm : : Function * F = getTransaction ( ) - > getModule ( ) - > getFunction ( mangledName ) ;
2013-07-13 16:27:53 +03:00
if ( F )
runOnFunction ( * F ) ;
}
llvm : : BasicBlock * NullDerefProtectionTransformer : : getTrapBB ( ) {
2013-07-27 21:11:21 +03:00
llvm : : Function * Fn = Inst - > getParent ( ) - > getParent ( ) ;
llvm : : Module * Md = Fn - > getParent ( ) ;
2013-07-13 16:27:53 +03:00
llvm : : LLVMContext & ctx = Fn - > getContext ( ) ;
2013-07-18 14:23:48 +03:00
llvm : : BasicBlock : : iterator PreInsertInst = Builder - > GetInsertPoint ( ) ;
2013-07-13 16:27:53 +03:00
FailBB = llvm : : BasicBlock : : Create ( ctx , " FailBlock " , Fn ) ;
2013-07-18 14:23:48 +03:00
Builder - > SetInsertPoint ( FailBB ) ;
2013-07-27 21:11:21 +03:00
std : : vector < llvm : : Type * > ArgTys ;
ArgTys . push_back ( llvm : : Type : : getInt8PtrTy ( ctx ) ) ;
llvm : : FunctionType * FTy
= llvm : : FunctionType : : get ( llvm : : Type : : getInt1Ty ( ctx ) , ArgTys , false ) ;
llvm : : Function * CallBackFn
= cast < llvm : : Function > ( Md - > getOrInsertFunction ( " shouldProceed " , FTy ) ) ;
void * SemaRef = ( void * ) m_Sema ;
// copied from JIT.cpp
llvm : : Constant * SemaRefCnt = 0 ;
llvm : : Type * constantIntTy = 0 ;
if ( sizeof ( void * ) = = 4 )
constantIntTy = llvm : : Type : : getInt32Ty ( ctx ) ;
else
constantIntTy = llvm : : Type : : getInt64Ty ( ctx ) ;
SemaRefCnt = llvm : : ConstantInt : : get ( constantIntTy , ( uintptr_t ) SemaRef ) ;
llvm : : Value * Arg = llvm : : ConstantExpr : : getIntToPtr ( SemaRefCnt ,
llvm : : Type : : getInt8PtrTy ( ctx ) ) ;
llvm : : CallInst * CI = Builder - > CreateCall ( CallBackFn , Arg ) ;
2013-07-18 14:23:48 +03:00
llvm : : Value * TrueVl = llvm : : ConstantInt : : get ( ctx , llvm : : APInt ( 1 , 1 ) ) ;
llvm : : Value * RetVl = CI ;
llvm : : ICmpInst * Cmp
= new llvm : : ICmpInst ( * FailBB , llvm : : CmpInst : : ICMP_EQ , RetVl ,
TrueVl , " " ) ;
llvm : : BasicBlock * HandleBB = llvm : : BasicBlock : : Create ( ctx , " HandleBlock " , Fn ) ;
llvm : : BranchInst : : Create ( HandleBB , Inst - > getParent ( ) , Cmp , FailBB ) ;
llvm : : ReturnInst : : Create ( Fn - > getContext ( ) , HandleBB ) ;
Builder - > SetInsertPoint ( PreInsertInst ) ;
2013-07-13 16:27:53 +03:00
return FailBB ;
}
void NullDerefProtectionTransformer : : instrumentLoadInst ( llvm : : LoadInst * LI ) {
llvm : : Value * Addr = LI - > getOperand ( 0 ) ;
2013-07-18 14:23:48 +03:00
if ( llvm : : isa < llvm : : GlobalVariable > ( Addr ) )
return ;
2013-07-13 16:27:53 +03:00
llvm : : PointerType * PTy = llvm : : cast < llvm : : PointerType > ( Addr - > getType ( ) ) ;
2013-07-27 21:11:21 +03:00
llvm : : Type * ElTy = PTy - > getElementType ( ) ;
2013-07-13 16:27:53 +03:00
if ( ! ElTy - > isPointerTy ( ) ) {
llvm : : BasicBlock * OldBB = LI - > getParent ( ) ;
llvm : : ICmpInst * Cmp
= new llvm : : ICmpInst ( LI , llvm : : CmpInst : : ICMP_EQ , Addr ,
llvm : : Constant : : getNullValue ( Addr - > getType ( ) ) , " " ) ;
llvm : : Instruction * Inst = Builder - > GetInsertPoint ( ) ;
llvm : : BasicBlock * NewBB = OldBB - > splitBasicBlock ( Inst ) ;
OldBB - > getTerminator ( ) - > eraseFromParent ( ) ;
llvm : : BranchInst : : Create ( getTrapBB ( ) , NewBB , Cmp , OldBB ) ;
}
}
void NullDerefProtectionTransformer : : instrumentStoreInst ( llvm : : StoreInst * SI ) {
llvm : : Value * Addr = SI - > getOperand ( 1 ) ;
2013-07-18 14:23:48 +03:00
if ( llvm : : isa < llvm : : GlobalVariable > ( Addr ) )
return ;
2013-07-13 16:27:53 +03:00
llvm : : PointerType * PTy = llvm : : cast < llvm : : PointerType > ( Addr - > getType ( ) ) ;
llvm : : Type * ElTy = PTy - > getElementType ( ) ;
if ( ! ElTy - > isPointerTy ( ) ) {
llvm : : BasicBlock * OldBB = SI - > getParent ( ) ;
llvm : : ICmpInst * Cmp
= new llvm : : ICmpInst ( SI , llvm : : CmpInst : : ICMP_EQ , Addr ,
llvm : : Constant : : getNullValue ( Addr - > getType ( ) ) , " " ) ;
llvm : : Instruction * Inst = Builder - > GetInsertPoint ( ) ;
llvm : : BasicBlock * NewBB = OldBB - > splitBasicBlock ( Inst ) ;
OldBB - > getTerminator ( ) - > eraseFromParent ( ) ;
llvm : : BranchInst : : Create ( getTrapBB ( ) , NewBB , Cmp , OldBB ) ;
}
}
bool NullDerefProtectionTransformer : : runOnFunction ( llvm : : Function & F ) {
llvm : : IRBuilder < > TheBuilder ( F . getContext ( ) ) ;
Builder = & TheBuilder ;
2013-07-27 21:11:21 +03:00
2013-07-13 16:27:53 +03:00
std : : vector < llvm : : Instruction * > WorkList ;
for ( llvm : : inst_iterator i = inst_begin ( F ) , e = inst_end ( F ) ; i ! = e ; + + i ) {
llvm : : Instruction * I = & * i ;
if ( llvm : : isa < llvm : : LoadInst > ( I ) | | llvm : : isa < llvm : : StoreInst > ( I ) )
WorkList . push_back ( I ) ;
}
for ( std : : vector < llvm : : Instruction * > : : iterator i = WorkList . begin ( ) ,
e = WorkList . end ( ) ; i ! = e ; + + i ) {
Inst = * i ;
Builder - > SetInsertPoint ( Inst ) ;
if ( llvm : : LoadInst * LI = llvm : : dyn_cast < llvm : : LoadInst > ( Inst ) ) {
instrumentLoadInst ( LI ) ;
} else if ( llvm : : StoreInst * SI = llvm : : dyn_cast < llvm : : StoreInst > ( Inst ) ) {
instrumentStoreInst ( SI ) ;
} else {
llvm_unreachable ( " unknown Instruction type " ) ;
}
}
return true ;
}
} // end namespace cling