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
4 changes: 3 additions & 1 deletion svf/include/SABER/ProgSlice.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "Util/WorkList.h"
#include "Graphs/SVFG.h"
#include "Util/DPItem.h"
#include "Util/SVFBugReport.h"

namespace SVF
{
Expand Down Expand Up @@ -201,7 +202,8 @@ class ProgSlice
}
/// Evaluate final condition
std::string evalFinalCond() const;
Set<std::string> evalFinalCondSet() const;
/// Add final condition to eventStack
void evalFinalCond2Event(GenericBug::EventStack &eventStack) const;
//@}

protected:
Expand Down
123 changes: 82 additions & 41 deletions svf/include/Util/SVFBugReport.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ class GenericEvent{
class BranchEvent: public GenericEvent{
/// branch statement and branch condition true or false
protected:
const BranchStmt *branchStmt;
bool branchCondition;
const SVFStmt *branchStmt;
bool branchSuccessFlg;

public:
BranchEvent(const BranchStmt *branchStmt, bool branchCondition):
GenericEvent(GenericEvent::Branch), branchStmt(branchStmt), branchCondition(branchCondition){ }
BranchEvent(const SVFStmt *branchStmt, bool branchSuccessFlg):
GenericEvent(GenericEvent::Branch), branchStmt(branchStmt), branchSuccessFlg(branchSuccessFlg){ }

const std::string getEventDescription() const;
const std::string getFuncName() const;
Expand Down Expand Up @@ -120,7 +120,7 @@ class SourceInstructionEvent: public GenericEvent{

class GenericBug{
public:
typedef std::vector<GenericEvent *> EventStack;
typedef std::vector<const GenericEvent *> EventStack;

public:
enum BugType{FULLBUFOVERFLOW, PARTIALBUFOVERFLOW, NEVERFREE, PARTIALLEAK, DOUBLEFREE, FILENEVERCLOSE, FILEPARTIALCLOSE};
Expand All @@ -137,7 +137,7 @@ class GenericBug{
assert(bugEventStack.size() != 0 && "bugEventStack should NOT be empty!");
}
virtual ~GenericBug();

//GenericBug(const GenericBug &) = delete;
/// returns bug type
inline BugType getBugType() const { return bugType; }
/// returns bug location as json format string
Expand All @@ -147,8 +147,8 @@ class GenericBug{

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

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

class BufferOverflowBug: public GenericBug{
Expand All @@ -163,8 +163,8 @@ class BufferOverflowBug: public GenericBug{
allocUpperBound(allocUpperBound), accessLowerBound(accessLowerBound),
accessUpperBound(accessUpperBound){ }

cJSON *getBugDescription();
void printBugToTerminal();
cJSON *getBugDescription() const;
void printBugToTerminal() const;

/// ClassOf
static inline bool classof(const GenericBug *bug)
Expand Down Expand Up @@ -208,8 +208,8 @@ class NeverFreeBug : public GenericBug{
NeverFreeBug(const EventStack &bugEventStack):
GenericBug(GenericBug::NEVERFREE, bugEventStack){ };

cJSON *getBugDescription();
void printBugToTerminal();
cJSON *getBugDescription() const;
void printBugToTerminal() const;

/// ClassOf
static inline bool classof(const GenericBug *bug)
Expand All @@ -219,15 +219,12 @@ class NeverFreeBug : public GenericBug{
};

class PartialLeakBug : public GenericBug{
protected:
Set<std::string> conditionalFreePath;

public:
PartialLeakBug(const EventStack &bugEventStack, Set<std::string> conditionalFreePath):
GenericBug(GenericBug::PARTIALLEAK, bugEventStack), conditionalFreePath(conditionalFreePath){ }
PartialLeakBug(const EventStack &bugEventStack):
GenericBug(GenericBug::PARTIALLEAK, bugEventStack){ }

cJSON *getBugDescription();
void printBugToTerminal();
cJSON *getBugDescription() const;
void printBugToTerminal() const;

/// ClassOf
static inline bool classof(const GenericBug *bug)
Expand All @@ -237,15 +234,12 @@ class PartialLeakBug : public GenericBug{
};

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

public:
DoubleFreeBug(const EventStack &bugEventStack, Set<std::string> doubleFreePath):
GenericBug(GenericBug::PARTIALLEAK, bugEventStack), doubleFreePath(doubleFreePath){ }
DoubleFreeBug(const EventStack &bugEventStack):
GenericBug(GenericBug::PARTIALLEAK, bugEventStack){ }

cJSON *getBugDescription();
void printBugToTerminal();
cJSON *getBugDescription() const;
void printBugToTerminal() const;

/// ClassOf
static inline bool classof(const GenericBug *bug)
Expand All @@ -259,8 +253,8 @@ class FileNeverCloseBug : public GenericBug{
FileNeverCloseBug(const EventStack &bugEventStack):
GenericBug(GenericBug::NEVERFREE, bugEventStack){ };

cJSON *getBugDescription();
void printBugToTerminal();
cJSON *getBugDescription() const;
void printBugToTerminal() const;

/// ClassOf
static inline bool classof(const GenericBug *bug)
Expand All @@ -270,15 +264,12 @@ class FileNeverCloseBug : public GenericBug{
};

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

public:
FilePartialCloseBug(const EventStack &bugEventStack, Set<std::string> conditionalFileClosePath):
GenericBug(GenericBug::PARTIALLEAK, bugEventStack), conditionalFileClosePath(conditionalFileClosePath){ }
FilePartialCloseBug(const EventStack &bugEventStack):
GenericBug(GenericBug::PARTIALLEAK, bugEventStack){ }

cJSON *getBugDescription();
void printBugToTerminal();
cJSON *getBugDescription() const;
void printBugToTerminal() const;

/// ClassOf
static inline bool classof(const GenericBug *bug)
Expand All @@ -292,7 +283,7 @@ class SVFBugReport
public:
SVFBugReport() = default;
~SVFBugReport();
typedef SVF::Set<GenericBug *> BugSet;
typedef SVF::Set<const GenericBug *> BugSet;

protected:
BugSet bugSet; // maintain bugs
Expand All @@ -303,21 +294,71 @@ class SVFBugReport
* it will add the bug into bugQueue.
* usage: addBug<GenericBug::BOA>(BufferOverflowBug(bugInst, 0, 10, 1, 11))
*/
template <typename T>
void addBug(T bug)
void addSaberBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack)
{
T *newBug = new T(bug);
bugSet.insert(newBug);
GenericBug *newBug;
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove this.

Copy link
Collaborator

Choose a reason for hiding this comment

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

GenericBug *newBug = nullptr;

switch(bugType){
case GenericBug::NEVERFREE:{
newBug = new NeverFreeBug(eventStack);
bugSet.insert(newBug);
Copy link
Collaborator

Choose a reason for hiding this comment

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

        bugSet.insert(new NeverFreeBug(eventStack));

Copy link
Contributor Author

Choose a reason for hiding this comment

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

newBug is use at line 333 newBug->printBugToTerminal()

break;
}
case GenericBug::PARTIALLEAK:{
newBug = new PartialLeakBug(eventStack);
bugSet.insert(newBug);
break;
}
case GenericBug::DOUBLEFREE:{
newBug = new DoubleFreeBug(eventStack);
bugSet.insert(newBug);
break;
}
case GenericBug::FILENEVERCLOSE:{
newBug = new FileNeverCloseBug(eventStack);
bugSet.insert(newBug);
break;
}
case GenericBug::FILEPARTIALCLOSE:{
newBug = new FilePartialCloseBug(eventStack);
bugSet.insert(newBug);
break;
}
default:{
assert(false && "saber does NOT have this bug type!");
break;
}
}

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

void addAbsExecBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack,
s64_t allocLowerBound, s64_t allocUpperBound, s64_t accessLowerBound, s64_t accessUpperBound){
GenericBug *newBug;
Copy link
Collaborator

Choose a reason for hiding this comment

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

GenericBug *newBug = nullptr;

switch(bugType){
case GenericBug::FULLBUFOVERFLOW: {
newBug = new FullBufferOverflowBug(eventStack, allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound);
bugSet.insert(newBug);
break;
}
case GenericBug::PARTIALBUFOVERFLOW:{
newBug = new PartialBufferOverflowBug(eventStack, allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound);
bugSet.insert(newBug);
break;
}
default:{
assert(false && "Abstract Execution does NOT hava his bug type!");
break;
}
}
}

/*
* function: pass file path, open the file and dump bug report as JSON format
* usage: dumpToFile("/path/to/file")
*/
void dumpToFile(const std::string& filePath);
void dumpToJsonFile(const std::string& filePath);
};
}

Expand Down
7 changes: 4 additions & 3 deletions svf/lib/SABER/DoubleFreeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ void DoubleFreeChecker::reportBug(ProgSlice* slice)
if(slice->isSatisfiableForPairs() == false)
{
SourceInstructionEvent *sourceInstEvent = new SourceInstructionEvent(getSrcCSID(slice->getSource())->getCallSite());
GenericBug::EventStack eventStack = {sourceInstEvent};
report.addBug<DoubleFreeBug>(
DoubleFreeBug(eventStack, slice->evalFinalCondSet()));
GenericBug::EventStack eventStack;
slice->evalFinalCond2Event(eventStack);
eventStack.push_back(sourceInstEvent);
report.addSaberBug(GenericBug::DOUBLEFREE, eventStack);
}
if(Options::ValidateTests())
testsValidation(slice);
Expand Down
10 changes: 5 additions & 5 deletions svf/lib/SABER/FileChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ void FileChecker::reportBug(ProgSlice* slice)
// full leakage
SourceInstructionEvent *sourceInstEvent = new SourceInstructionEvent(getSrcCSID(slice->getSource())->getCallSite());
GenericBug::EventStack eventStack = {sourceInstEvent};
report.addBug<FileNeverCloseBug>(
FileNeverCloseBug(eventStack));
report.addSaberBug(GenericBug::FILENEVERCLOSE, eventStack);
}
else if (isAllPathReachable() == false && isSomePathReachable() == true)
{
SourceInstructionEvent *sourceInstEvent = new SourceInstructionEvent(getSrcCSID(slice->getSource())->getCallSite());
GenericBug::EventStack eventStack = {sourceInstEvent};
report.addBug<FilePartialCloseBug>(
FilePartialCloseBug(eventStack, slice->evalFinalCondSet()));
GenericBug::EventStack eventStack;
slice->evalFinalCond2Event(eventStack);
eventStack.push_back(sourceInstEvent);
report.addSaberBug(GenericBug::FILEPARTIALCLOSE, eventStack);
}
}
10 changes: 5 additions & 5 deletions svf/lib/SABER/LeakChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,16 +154,16 @@ void LeakChecker::reportBug(ProgSlice* slice)
// full leakage
SourceInstructionEvent *sourceInstEvent = new SourceInstructionEvent(getSrcCSID(slice->getSource())->getCallSite());
GenericBug::EventStack eventStack = {sourceInstEvent};
report.addBug<NeverFreeBug>(
NeverFreeBug(eventStack));
report.addSaberBug(GenericBug::NEVERFREE, eventStack);
}
else if (isAllPathReachable() == false && isSomePathReachable() == true)
{
// partial leakage
SourceInstructionEvent *sourceInstEvent = new SourceInstructionEvent(getSrcCSID(slice->getSource())->getCallSite());
GenericBug::EventStack eventStack = {sourceInstEvent};
report.addBug<PartialLeakBug>(
PartialLeakBug(eventStack, slice->evalFinalCondSet()));
GenericBug::EventStack eventStack;
slice->evalFinalCond2Event(eventStack);
eventStack.push_back(sourceInstEvent);
report.addSaberBug(GenericBug::PARTIALLEAK, eventStack);
}

if(Options::ValidateTests())
Expand Down
22 changes: 17 additions & 5 deletions svf/lib/SABER/ProgSlice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,20 @@ const CallICFGNode* ProgSlice::getRetSite(const SVFGEdge* edge) const
return getSVFG()->getCallSite(SVFUtil::cast<RetIndSVFGEdge>(edge)->getCallSiteId());
}

Set<std::string> ProgSlice::evalFinalCondSet() const
void ProgSlice::evalFinalCond2Event(GenericBug::EventStack &eventStack) const
{
NodeBS elems = pathAllocator->exactCondElem(finalCond);
Set<std::string> locations;
for(NodeBS::iterator it = elems.begin(), eit = elems.end(); it!=eit; ++it)
{
const SVFInstruction* tinst = pathAllocator->getCondInst(*it);
auto stmt = PAG::getPAG()->getValueEdges(tinst);
assert(stmt.size() == 1 && "returned SVFStmtSet should be of size 1!");
if(pathAllocator->isNegCond(*it))
locations.insert(tinst->getSourceLoc()+"|False");
eventStack.push_back(new BranchEvent(*(stmt.begin()), false));
Copy link
Collaborator

Choose a reason for hiding this comment

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

new BranchEvent(tinst, false)

else
locations.insert(tinst->getSourceLoc()+"|True");
eventStack.push_back(new BranchEvent(*(stmt.begin()), true));
}
return locations;
}

/*!
Expand All @@ -174,7 +175,18 @@ std::string ProgSlice::evalFinalCond() const
{
std::string str;
std::stringstream rawstr(str);
Set<std::string> locations = evalFinalCondSet();
Set<std::string> locations;
NodeBS elems = pathAllocator->exactCondElem(finalCond);

for(NodeBS::iterator it = elems.begin(), eit = elems.end(); it!=eit; ++it)
{
const SVFInstruction* tinst = pathAllocator->getCondInst(*it);
if(pathAllocator->isNegCond(*it))
locations.insert(tinst->getSourceLoc()+"|False");
else
locations.insert(tinst->getSourceLoc()+"|True");
}

/// print leak path after eliminating duplicated element
for(Set<std::string>::iterator iter = locations.begin(), eiter = locations.end();
iter!=eiter; ++iter)
Expand Down
1 change: 0 additions & 1 deletion svf/lib/SABER/SrcSnkDDA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ void SrcSnkDDA::analyze(SVFModule* module)

reportBug(getCurSlice());
}

finalize();

}
Expand Down
Loading