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:
parent
44891a9b46
commit
6b560aadba
108
lib/Interpreter/ASTNullDerefProtection.cpp
Normal file
108
lib/Interpreter/ASTNullDerefProtection.cpp
Normal 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
|
50
lib/Interpreter/ASTNullDerefProtection.h
Normal file
50
lib/Interpreter/ASTNullDerefProtection.h
Normal 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
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user