Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SVFBugRecoder and modify source loc format #1067

Merged
merged 13 commits into from
Apr 26, 2023
10 changes: 5 additions & 5 deletions svf-llvm/lib/LLVMUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
if (llvm::DbgDeclareInst *DDI = SVFUtil::dyn_cast<llvm::DbgDeclareInst>(DII))
{
llvm::DIVariable *DIVar = SVFUtil::cast<llvm::DIVariable>(DDI->getVariable());
rawstr << "ln: " << DIVar->getLine() << " fl: " << DIVar->getFilename().str();
rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" << DIVar->getFilename().str() << "\"";
break;
}
}
Expand All @@ -508,7 +508,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
File = inlineLoc->getFilename().str();
}
}
rawstr << "ln: " << Line << " cl: " << Column << " fl: " << File;
rawstr << "\"ln\": " << Line << ", \"cl\": " << Column << ", \"fl\": \"" << File << "\"";
}
}
else if (const Argument* argument = SVFUtil::dyn_cast<Argument>(val))
Expand Down Expand Up @@ -539,7 +539,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )

if(DGV->getName() == gvar->getName())
{
rawstr << "ln: " << DGV->getLine() << " fl: " << DGV->getFilename().str();
rawstr << "\"ln\": " << DGV->getLine() << ", \"fl\": \"" << DGV->getFilename().str() << "\"";
}

}
Expand All @@ -552,7 +552,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
}
else if (const BasicBlock* bb = SVFUtil::dyn_cast<BasicBlock>(val))
{
rawstr << "basic block: " << bb->getName().str() << " " << getSourceLoc(bb->getFirstNonPHI());
rawstr << "\"basic block\": " << bb->getName().str() << ", \"location\": " << getSourceLoc(bb->getFirstNonPHI());
}
else if(LLVMUtil::isConstDataOrAggData(val))
{
Expand Down Expand Up @@ -584,7 +584,7 @@ const std::string LLVMUtil::getSourceLocOfFunction(const Function* F)
if (llvm::DISubprogram *SP = F->getSubprogram())
{
if (SP->describes(F))
rawstr << "in line: " << SP->getLine() << " file: " << SP->getFilename().str();
rawstr << "\"ln\": " << SP->getLine() << ", \"file\": \"" << SP->getFilename().str() << "\"";
}
return rawstr.str();
}
Expand Down
2 changes: 0 additions & 2 deletions svf/include/SABER/FileChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ class FileChecker : public LeakChecker
}
/// Report file/close bugs
void reportBug(ProgSlice* slice);
void reportNeverClose(const SVFGNode* src);
void reportPartialClose(const SVFGNode* src);
};

} // End namespace SVF
Expand Down
2 changes: 0 additions & 2 deletions svf/include/SABER/LeakChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ class LeakChecker : public SrcSnkDDA
/// Report leaks
//@{
virtual void reportBug(ProgSlice* slice) override;
void reportNeverFree(const SVFGNode* src);
void reportPartialLeak(const SVFGNode* src);
//@}

/// Validate test cases for regression test purpose
Expand Down
1 change: 1 addition & 0 deletions svf/include/SABER/ProgSlice.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class ProgSlice
}
/// Evaluate final condition
std::string evalFinalCond() const;
Set<std::string> evalFinalCondSet() const;
//@}

protected:
Expand Down
5 changes: 3 additions & 2 deletions svf/include/SABER/SrcSnkDDA.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
#ifndef SRCSNKANALYSIS_H_
#define SRCSNKANALYSIS_H_


#include "Util/GraphReachSolver.h"
#include "Graphs/SVFGOPT.h"
#include "SABER/ProgSlice.h"
#include "SABER/SaberSVFGBuilder.h"
#include "Util/GraphReachSolver.h"
#include "Util/SVFBugReport.h"

namespace SVF
{
Expand Down Expand Up @@ -77,6 +77,7 @@ class SrcSnkDDA : public CFLSrcSnkSolver
SaberSVFGBuilder memSSA;
SVFG* svfg;
PTACallGraph* ptaCallGraph;
SVFBugReport report; /// Bug Reporter

public:

Expand Down
301 changes: 301 additions & 0 deletions svf/include/Util/SVFBugReport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
//===- SVFBugReport.h -- Base class for statistics---------------------------------//
//
// SVF: Static Value-Flow Analysis
//
// Copyright (C) <2013-> <Yulei Sui>
//

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
//===----------------------------------------------------------------------===//

//
// Created by JoelYang on 2023/4/19.
//

#ifndef SVF_BUGRECODER_H
#define SVF_BUGRECODER_H

#include <vector>
#include "SVFIR/SVFValue.h"
#include "SVFIR/SVFVariables.h"
#include "SVFIR/SVFStatements.h"
#include "Graphs/ICFGNode.h"
#include <string>
#include <map>
#include "Util/cJSON.h"
#include <set>

namespace SVF{

/*!
* Bug Detector Recoder
*/


class GenericEvent{
public:
enum EventType{Branch, Caller, CallSite, Loop};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add "SourceInst'' event


protected:
EventType eventType;

public:
inline GenericEvent(EventType eventType): eventType(eventType){ };
virtual ~GenericEvent() = default;

inline EventType getEventType() const { return eventType; }
virtual const std::string getEventDescription() const = 0;
virtual const std::string getFuncName() const = 0;
virtual const std::string getEventLoc() const = 0;
};

class BranchEvent: public GenericEvent{
/// branch statement and branch condition true or false
protected:
const BranchStmt *branchStmt;
std::string description;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove description and make it retrievable in getEventDescription


public:
inline BranchEvent(const BranchStmt *branchStmt): GenericEvent(GenericEvent::Branch), branchStmt(branchStmt){ }

inline BranchEvent(const BranchStmt *branchStmt, std::string description):
GenericEvent(GenericEvent::Branch), branchStmt(branchStmt), description(description){ }

const std::string getEventDescription() const;
const std::string getFuncName() const;
const std::string getEventLoc() const;

/// ClassOf
static inline bool classof(const GenericEvent* event)
{
return event->getEventType() == GenericEvent::Branch;
}
};

class CallSiteEvent: public GenericEvent{
protected:
const CallICFGNode *callSite;

public:
inline CallSiteEvent(const CallICFGNode *callSite): GenericEvent(GenericEvent::CallSite), callSite(callSite){ }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove inline for constructor

const std::string getEventDescription() const;
const std::string getFuncName() const;
const std::string getEventLoc() const;

/// ClassOf
static inline bool classof(const GenericEvent* event)
{
return event->getEventType() == GenericEvent::CallSite;
}
};

class GenericBug{
public:
typedef std::vector<GenericEvent *> EventStack;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const GenericEvent*


public:
enum BugType{FULLBUFOVERFLOW, PARTIALBUFOVERFLOW, NEVERFREE, PARTIALLEAK, DOUBLEFREE, FILENEVERCLOSE, FILEPARTIALCLOSE};

protected:
BugType bugType;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

classof method for each subclass.

const SVFInstruction * bugInst;
EventStack bugEventStack;

public:
inline GenericBug(BugType bugType, const SVFInstruction * bugInst, EventStack bugEventStack): bugType(bugType), bugInst(bugInst), bugEventStack(bugEventStack){ };
inline GenericBug(BugType bugType, const SVFInstruction * bugInst): bugType(bugType), bugInst(bugInst){ };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GenericBug(BugType bugType, eventstack)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove const SVFInstruction * bugInst,


virtual ~GenericBug() = default;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the destructor? How did you release the memory of the events in EventStack?


inline BugType getBugType() const { return bugType; }
const std::string getLoc() const;
const std::string getFuncName() const;

inline const EventStack& getEventStack() const { return bugEventStack; }

virtual cJSON *getBugDescription() = 0;
virtual void printBugToTerminal() = 0;
};

class BufferOverflowBug: public GenericBug{
protected:
long long allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use SVF’s type and DON’T use std long long


public:
inline BufferOverflowBug(GenericBug::BugType bugType, const SVFInstruction * bugInst, EventStack eventStack,
long long allocLowerBound, long long allocUpperBound,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above and followings

long long accessLowerBound, long long accessUpperBound):
GenericBug(bugType, bugInst, eventStack), allocLowerBound(allocLowerBound),
allocUpperBound(allocUpperBound), accessLowerBound(accessLowerBound),
accessUpperBound(accessUpperBound){ }

cJSON *getBugDescription();
void printBugToTerminal();

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::PARTIALBUFOVERFLOW || bug->getBugType() == GenericBug::FULLBUFOVERFLOW;
}
};

class FullBufferOverflowBug: public BufferOverflowBug{
public:
inline FullBufferOverflowBug(const SVFInstruction * bugInst, EventStack eventStack,
long long allocLowerBound, long long allocUpperBound,
long long accessLowerBound, long long accessUpperBound):
BufferOverflowBug(GenericBug::FULLBUFOVERFLOW, bugInst, eventStack, allocLowerBound,
allocUpperBound, accessLowerBound, accessUpperBound){ }

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::FULLBUFOVERFLOW;
}
};

class PartialBufferOverflowBug: public BufferOverflowBug{
protected:
long long allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound;

public:
inline PartialBufferOverflowBug(const SVFInstruction * bugInst, EventStack eventStack,
long long allocLowerBound, long long allocUpperBound,
long long accessLowerBound, long long accessUpperBound):
BufferOverflowBug(GenericBug::PARTIALBUFOVERFLOW, bugInst, eventStack, allocLowerBound,
allocUpperBound, accessLowerBound, accessUpperBound){ }

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::PARTIALBUFOVERFLOW;
}
};

class NeverFreeBug : public GenericBug{
public:
NeverFreeBug(const SVFInstruction *bugInst):
GenericBug(GenericBug::NEVERFREE, bugInst){ };

cJSON *getBugDescription();
void printBugToTerminal();

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::NEVERFREE;
}
};

class PartialLeakBug : public GenericBug{
protected:
Set<std::string> conditionalFreePath;
public:
PartialLeakBug(const SVFInstruction *bugInst, Set<std::string> conditionalFreePath):
GenericBug(GenericBug::PARTIALLEAK, bugInst), conditionalFreePath(conditionalFreePath){ }

cJSON *getBugDescription();
void printBugToTerminal();

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::PARTIALLEAK;
}
};

class DoubleFreeBug : public GenericBug{
protected:
Set<std::string> doubleFreePath;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this or put into the event stack?

Copy link
Contributor Author

@JoelYYoung JoelYYoung Apr 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you refer to doing so for DoubleFreeBug only, I think it's feasible, but may loss consistency with other bug classes like FilePartialCloseBug, ParitalLeakBug, etc.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the strings in this vector? Can we get or extract the from the event stack?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the reason for not doing so for other bug classes is that eventStack should be used to store events happening on the execution path from entry to the bug site, but not side effects like partial free paths and partial close paths.


public:
DoubleFreeBug(const SVFInstruction *bugInst, Set<std::string> doubleFreePath):
GenericBug(GenericBug::PARTIALLEAK, bugInst), doubleFreePath(doubleFreePath){ }

cJSON *getBugDescription();
void printBugToTerminal();

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::DOUBLEFREE;
}
};

class FileNeverCloseBug : public GenericBug{
public:
FileNeverCloseBug(const SVFInstruction *bugInst):
GenericBug(GenericBug::NEVERFREE, bugInst){ };

cJSON *getBugDescription();
void printBugToTerminal();

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::FILENEVERCLOSE;
}
};

class FilePartialCloseBug : public GenericBug{
protected:
Set<std::string> conditionalFileClosePath;

public:
FilePartialCloseBug(const SVFInstruction *bugInst, Set<std::string> conditionalFileClosePath):
GenericBug(GenericBug::PARTIALLEAK, bugInst), conditionalFileClosePath(conditionalFileClosePath){ }

cJSON *getBugDescription();
void printBugToTerminal();

/// ClassOf
static inline bool classof(const GenericBug *bug)
{
return bug->getBugType() == GenericBug::FILEPARTIALCLOSE;
}
};

class SVFBugReport
{
public:
SVFBugReport() = default;
~SVFBugReport();
typedef std::vector<GenericBug *> BugVector;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make it a set.


protected:
BugVector bugVector; // maintain bugs

public:
/*
* function: pass bug type (i.e., GenericBug::BOA) and bug object as parameter,
* it will add the bug into bugQueue.
* usage: addBug<GenericBug::BOA>(BufferOverflowBug(bugInst, 0, 10, 1, 11))
*/
template <typename T>
void addBug(T bug)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void addBug(eventstack, flag){

switch (xx)
case1:
xxxx

default:
assert(false && "no such kind of bug");

}

{
T *newBug = new T(bug);
bugVector.push_back(newBug);

// when add a bug, also print it to terminal
newBug->printBugToTerminal();
}

//dump all bugs to string, in Json format
std::string toString();
};
}

#endif
Loading