Implement the null deref checker on AST level.

We need to throw an exception if null deref is done. If we continued to do that
generating IR it would be too difficult to get the exception semantics and
cleanups right. Thus we decided to do it on AST level and delegate to codegen
generate the concrete IR that we need.
This commit is contained in:
Baozeng Ding 2013-09-05 16:26:23 +02:00 committed by sftnight
parent 44891a9b46
commit 6b560aadba
3 changed files with 160 additions and 0 deletions

View File

@ -0,0 +1,108 @@
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author: Baozeng Ding <sploving1@gmail.com>
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------
#include "ASTNullDerefProtection.h"
#include "cling/Interpreter/Transaction.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Sema/Sema.h"
using namespace clang;
namespace cling {
ASTNullDerefProtection::ASTNullDerefProtection(clang::Sema* S)
: TransactionTransformer(S) {
}
ASTNullDerefProtection::~ASTNullDerefProtection()
{ }
bool ASTNullDerefProtection::isDeclCandidate(FunctionDecl * FDecl) {
if(m_NonNullArgIndexs.count(FDecl)) return true;
std::bitset<32> ArgIndexs;
for (specific_attr_iterator<NonNullAttr>
I = FDecl->specific_attr_begin<NonNullAttr>(),
E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I) {
NonNullAttr *NonNull = *I;
for (NonNullAttr::args_iterator i = NonNull->args_begin(),
e = NonNull->args_end(); i != e; ++i) {
ArgIndexs.set(*i);
}
}
if (ArgIndexs.any()) {
m_NonNullArgIndexs.insert(std::make_pair(FDecl, ArgIndexs));
return true;
}
return false;
}
void ASTNullDerefProtection::Transform() {
FunctionDecl* FD = getTransaction()->getWrapperFD();
if (!FD)
return;
CompoundStmt* CS = dyn_cast<CompoundStmt>(FD->getBody());
assert(CS && "Function body not a CompundStmt?");
Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext);
ASTContext* Context = &m_Sema->getASTContext();
DeclContext* DC = FD->getTranslationUnitDecl();
llvm::SmallVector<Stmt*, 4> Stmts;
SourceLocation SL = FD->getBody()->getLocStart();
for (CompoundStmt::body_iterator I = CS->body_begin(), EI = CS->body_end();
I != EI; ++I) {
CallExpr* CE = dyn_cast<CallExpr>(*I);
if (!CE) {
Stmts.push_back(*I);
continue;
}
if (FunctionDecl* FDecl = CE->getDirectCallee()) {
if(FDecl && isDeclCandidate(FDecl)) {
SourceLocation SL = CE->getLocStart();
decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl);
const std::bitset<32>& ArgIndexs = it->second;
Sema::ContextRAII pushedDC(*m_Sema, FDecl);
for (int index = 0; index < 32; ++index) {
if (!ArgIndexs.test(index)) continue;
DeclRefExpr* DRE
= dyn_cast<DeclRefExpr>(CE->getArg(index)->IgnoreImpCasts());
if (!DRE) continue;
ExprResult ER
= m_Sema->Sema::ActOnUnaryOp(S, SL, tok::exclaim, DRE);
IntegerLiteral* One = IntegerLiteral::Create(*Context,
llvm::APInt(32, 1), Context->IntTy, SL);
ExprResult Throw = m_Sema->ActOnCXXThrow(S, SL, One);
Decl* varDecl = 0;
Stmt* varStmt = 0;
Sema::FullExprArg FullCond(m_Sema->MakeFullExpr(ER.take()));
StmtResult IfStmt = m_Sema->ActOnIfStmt(SL, FullCond, varDecl,
Throw.get(), SL, varStmt);
Stmts.push_back(IfStmt.get());
}
}
}
Stmts.push_back(CE);
}
llvm::ArrayRef<Stmt*> StmtsRef(Stmts.data(), Stmts.size());
CompoundStmt* CSBody = new (*Context)CompoundStmt(*Context, StmtsRef,
SL, SL);
FD->setBody(CSBody);
DC->removeDecl(FD);
DC->addDecl(FD);
}
} // end namespace cling

View File

@ -0,0 +1,50 @@
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id: cb7241880ebcbba87b2ae16476c2812afd7ff571 $
// author: Baozeng Ding <sploving1@gmail.com>
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------
#ifndef CLING_AST_NULL_DEREF_PROTECTION_H
#define CLING_AST_NULL_DEREF_PROTECTION_H
#include "TransactionTransformer.h"
#include "clang/AST/Decl.h"
#include <bitset>
#include <map>
namespace clang {
class Sema;
class FunctionDecl;
class CallExpr;
}
namespace llvm {
class raw_ostream;
}
namespace cling {
typedef std::map<clang::FunctionDecl*, std::bitset<32> > decl_map_t;
class ASTNullDerefProtection : public TransactionTransformer {
private:
std::map<clang::FunctionDecl*, std::bitset<32> > m_NonNullArgIndexs;
bool isDeclCandidate(clang::FunctionDecl* FDecl);
public:
///\ brief Constructs the NullDeref AST Transformer.
///
///\param[in] S - The semantic analysis object.
///
ASTNullDerefProtection(clang::Sema* S);
virtual ~ASTNullDerefProtection();
virtual void Transform();
};
} // namespace cling
#endif // CLING_AST_NULL_DEREF_PROTECTION_H

View File

@ -7,6 +7,7 @@
#include "IncrementalParser.h"
#include "ASTDumper.h"
#include "ASTNodeEraser.h"
#include "ASTNullDerefProtection.h"
#include "AutoSynthesizer.h"
#include "DeclCollector.h"
#include "DeclExtractor.h"
@ -78,6 +79,7 @@ namespace cling {
m_ASTTransformers.push_back(new ASTDumper());
m_ASTTransformers.push_back(new DeclExtractor(TheSema));
m_ASTTransformers.push_back(new ReturnSynthesizer(TheSema));
m_ASTTransformers.push_back(new ASTNullDerefProtection(TheSema));
// Register the IR Transformers
m_IRTransformers.push_back(new IRDumper());