Add support for mangling: How we can check regular C++ functions.

Indirect calls are still an issue.
This commit is contained in:
Baozeng Ding 2013-08-21 10:56:16 +02:00 committed by sftnight
parent 88cc4a1ed2
commit cc877954ae
3 changed files with 53 additions and 49 deletions

View File

@ -57,19 +57,20 @@ extern "C" {
using namespace clang;
namespace cling {
typedef std::map<llvm::StringRef, std::bitset<32> > nonnull_map_t;
typedef std::map<std::string, std::bitset<32> > nonnull_map_t;
// NonNullDeclFinder finds the function decls with nonnull attribute args.
class NonNullDeclFinder
: public RecursiveASTVisitor<NonNullDeclFinder> {
private:
Sema* m_Sema;
llvm::SmallVector<llvm::StringRef, 8> m_NonNullDeclNames;
llvm::OwningPtr<clang::MangleContext> m_MangleCtx;
llvm::SmallVector<std::string, 8> m_NonNullDeclNames;
nonnull_map_t m_NonNullArgIndexs;
public:
NonNullDeclFinder(Sema* S) : m_Sema(S) {}
const llvm::SmallVector<llvm::StringRef, 8>& getDeclNames() const {
const llvm::SmallVector<std::string, 8>& getDeclNames() const {
return m_NonNullDeclNames;
}
@ -77,6 +78,41 @@ namespace cling {
return m_NonNullArgIndexs;
}
std::string getMangledName(FunctionDecl* FD) {
// 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_Complete, RawStr);
break;
default :
m_MangleCtx->mangleName(FD, RawStr);
break;
}
RawStr.flush();
} else {
mangledName = FD->getNameAsString();
}
return mangledName;
}
// Deal with all the call expr in the transaction.
bool VisitCallExpr(CallExpr* TheCall) {
if (FunctionDecl* FDecl = TheCall->getDirectCallee()) {
@ -108,7 +144,7 @@ namespace cling {
if (ArgIndexs.any()) {
// Get the function decl's name.
llvm::StringRef FName = FDecl->getName();
std::string FName = getMangledName(FDecl);
// Store the function decl's name into the vector.
m_NonNullDeclNames.push_back(FName);
@ -133,39 +169,8 @@ namespace cling {
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_Complete, RawStr);
break;
default :
m_MangleCtx->mangleName(FD, RawStr);
break;
}
RawStr.flush();
} else {
mangledName = FD->getNameAsString();
}
NonNullDeclFinder Finder(m_Sema);
std::string mangledName = Finder.getMangledName(FD);
// Find the function in the module.
llvm::Function* F = getTransaction()->getModule()->getFunction(mangledName);
if (!F) return;
@ -174,8 +179,6 @@ namespace cling {
Builder = &TheBuilder;
runOnFunction(*F);
NonNullDeclFinder Finder(m_Sema);
// Find all the function decls with null attribute arguments.
for (size_t Idx = 0, E = getTransaction()->size(); Idx < E; ++Idx) {
Transaction::DelayCallInfo I = (*getTransaction())[Idx];
@ -185,13 +188,13 @@ namespace cling {
Finder.TraverseStmt((*J)->getBody());
}
const llvm::SmallVector<llvm::StringRef, 8>&
const llvm::SmallVector<std::string, 8>&
FDeclNames = Finder.getDeclNames();
if (FDeclNames.empty()) return;
llvm::Module* M = F->getParent();
for (llvm::SmallVector<llvm::StringRef, 8>::const_iterator
for (llvm::SmallVector<std::string, 8>::const_iterator
i = FDeclNames.begin(), e = FDeclNames.end(); i != e; ++i) {
const nonnull_map_t& ArgIndexs = Finder.getArgIndexs();
nonnull_map_t::const_iterator it = ArgIndexs.find(*i);
@ -363,7 +366,7 @@ namespace cling {
}
void NullDerefProtectionTransformer::handleNonNullArgCall(llvm::Module& M,
const llvm::StringRef& name, const std::bitset<32>& ArgIndexs) {
const std::string& name, const std::bitset<32>& ArgIndexs) {
// Get the function by the name.
llvm::Function* func = M.getFunction(name);

View File

@ -41,7 +41,7 @@ namespace cling {
void instrumentCallInst(llvm::Instruction* TheCall,
const std::bitset<32>& ArgIndexs);
void handleNonNullArgCall(llvm::Module& M,
const llvm::StringRef& FName,
const std::string& FName,
const std::bitset<32>& ArgIndexs);
public:

View File

@ -1,11 +1,12 @@
// RUN: cat %s | %cling -Xclang -verify | FileCheck %s
// XFAIL:*
// RUN: cat %s | %cling -Xclang -verify
// We must be able to handle cases where, there is a custom function that has
// attributes non-null arguments and we should be able to add a non-null arg
// attribute to a say library function.
// Qualified functions.
#include <stdio.h>
namespace custom_namespace {
void standaloneFunc(void* p, int q, float* s) __attribute__((nonnull(1,3))) { // expected-warning {{GCC does not allow nonnull attribute in this position on a function definition}}
if (!p || !s)
@ -27,9 +28,9 @@ int* p = new int(1);
float* f = new float(0.0);
const char* charNull = 0;
custom_namespace::standaloneFunc(pNull, 1, fNull);
custom_namespace::standaloneFunc(pNull, 1, f);
custom_namespace::standaloneFunc(p, 1, fNull);
custom_namespace::standaloneFunc(pNull, 1, fNull); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}
custom_namespace::standaloneFunc(pNull, 1, f); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}
custom_namespace::standaloneFunc(p, 1, fNull); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}
printf(charNull, ""); // expected-warning {{you are about to dereference null ptr, which probably will lead to seg violation. Do you want to proceed?[y/n]}}
.rawInput 1
@ -41,7 +42,7 @@ int trampoline() {
}
.rawInput 0
//CHECK-NOT: Must not be called with 0 args.
trampoline()
//trampoline()
//CHECK: (int) 1
.q