Static Value-Flow Analysis
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Private Attributes | Friends | List of all members
SVF::NullptrDerefDetector Class Reference

#include <AEDetector.h>

Inheritance diagram for SVF::NullptrDerefDetector:
SVF::AEDetector

Public Member Functions

 NullptrDerefDetector ()
 
 ~NullptrDerefDetector ()=default
 
void detect (AbstractState &as, const ICFGNode *node)
 Detects nullptr dereferences issues within a node.
 
void handleStubFunctions (const CallICFGNode *call)
 Handles external API calls related to nullptr dereferences.
 
bool isUninit (AbstractValue v)
 Checks if an Abstract Value is uninitialized.
 
void addBugToReporter (const AEException &e, const ICFGNode *node)
 Adds a bug to the reporter based on an exception.
 
void reportBug ()
 Reports all detected nullptr dereference bugs.
 
void detectExtAPI (AbstractState &as, const CallICFGNode *call)
 Handle external API calls related to nullptr dereferences.
 
bool isNull (AbstractValue v)
 Check if an Abstract Value is NULL (or uninitialized).
 
bool canSafelyDerefPtr (AbstractState &as, const SVFVar *ptr)
 
- Public Member Functions inherited from SVF::AEDetector
 AEDetector ()
 Constructor initializes the detector kind to UNKNOWN.
 
virtual ~AEDetector ()=default
 Virtual destructor for safe polymorphic use.
 
DetectorKind getKind () const
 Get the kind of the detector.
 

Static Public Member Functions

static bool classof (const AEDetector *detector)
 
- Static Public Member Functions inherited from SVF::AEDetector
static bool classof (const AEDetector *detector)
 Check if the detector is of the UNKNOWN kind.
 

Private Attributes

Set< std::string > bugLoc
 Set of locations where bugs have been reported.
 
SVFBugReport recoder
 Recorder for abstract execution bugs.
 
Map< const ICFGNode *, std::string > nodeToBugInfo
 Maps ICFG nodes to bug information.
 

Friends

class AbstractInterpretation
 

Additional Inherited Members

- Public Types inherited from SVF::AEDetector
enum  DetectorKind { BUF_OVERFLOW , NULL_DEREF , UNKNOWN }
 Enumerates the types of detectors available. More...
 
- Protected Attributes inherited from SVF::AEDetector
DetectorKind kind
 The kind of the detector.
 

Detailed Description

Definition at line 330 of file AEDetector.h.

Constructor & Destructor Documentation

◆ NullptrDerefDetector()

SVF::NullptrDerefDetector::NullptrDerefDetector ( )
inline

Definition at line 334 of file AEDetector.h.

335 {
337 }
@ NULL_DEREF
Detector for nullptr dereference issues.
Definition AEDetector.h:49
DetectorKind kind
The kind of the detector.
Definition AEDetector.h:101

◆ ~NullptrDerefDetector()

SVF::NullptrDerefDetector::~NullptrDerefDetector ( )
default

Member Function Documentation

◆ addBugToReporter()

void SVF::NullptrDerefDetector::addBugToReporter ( const AEException e,
const ICFGNode node 
)
inline

Adds a bug to the reporter based on an exception.

Parameters
eThe exception that was thrown.
nodePointer to the ICFG node where the bug was detected.

Definition at line 376 of file AEDetector.h.

377 {
380 eventStack.push_back(sourceInstEvent); // Add the source instruction event to the event stack
381
382 if (eventStack.empty())
383 {
384 return; // If the event stack is empty, return early
385 }
386 std::string loc = eventStack.back().getEventLoc(); // Get the location of the last event in the stack
387
388 // Check if the bug at this location has already been reported
389 if (bugLoc.find(loc) != bugLoc.end())
390 {
391 return; // If the bug location is already reported, return early
392 }
393 else
394 {
395 bugLoc.insert(loc); // Otherwise, mark this location as reported
396 }
398 nodeToBugInfo[node] = e.what(); // Record the exception information for the node
399 }
std::vector< SVFBugEvent > EventStack
Set< std::string > bugLoc
Set of locations where bugs have been reported.
Definition AEDetector.h:439
SVFBugReport recoder
Recorder for abstract execution bugs.
Definition AEDetector.h:440
Map< const ICFGNode *, std::string > nodeToBugInfo
Maps ICFG nodes to bug information.
Definition AEDetector.h:441
void addAbsExecBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack, s64_t allocLowerBound, s64_t allocUpperBound, s64_t accessLowerBound, s64_t accessUpperBound)
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74

◆ canSafelyDerefPtr()

bool NullptrDerefDetector::canSafelyDerefPtr ( AbstractState as,
const SVFVar ptr 
)

Definition at line 679 of file AEDetector.cpp.

680{
681 NodeID value_id = value->getId();
683 // uninit value cannot be dereferenced, return unsafe
684 if (isUninit(AbsVal)) return false;
685 // Interval Value (non-addr) is not the checkpoint of nullptr dereference, return safe
686 if (!AbsVal.isAddr()) return true;
687 for (const auto &addr: AbsVal.getAddrs())
688 {
689 // if the addr itself is invalid mem, report unsafe
691 return false;
692 // if nullptr is detected, return unsafe
694 return false;
695 // if addr is labeled freed mem, report unsafe
696 else if (as.isFreedMem(addr))
697 return false;
698 }
699
700
701 return true;
702}
static bool isNullMem(u32_t addr)
static bool isInvalidMem(u32_t addr)
bool isUninit(AbstractValue v)
Checks if an Abstract Value is uninitialized.
Definition AEDetector.h:364
u32_t NodeID
Definition GeneralType.h:56

◆ classof()

static bool SVF::NullptrDerefDetector::classof ( const AEDetector detector)
inlinestatic

Definition at line 341 of file AEDetector.h.

342 {
343 return detector->getKind() == AEDetector::NULL_DEREF;
344 }

◆ detect()

void NullptrDerefDetector::detect ( AbstractState as,
const ICFGNode node 
)
virtual

Detects nullptr dereferences issues within a node.

Parameters
asReference to the abstract state.
nodePointer to the ICFG node.

Implements SVF::AEDetector.

Definition at line 526 of file AEDetector.cpp.

527{
528 if (SVFUtil::isa<CallICFGNode>(node))
529 {
530 // external API like memset(*dst, elem, sz)
531 // we check if it's external api and check the corrisponding index
532 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
533 if (SVFUtil::isExtCall(callNode->getCalledFunction()))
534 {
536 }
537 }
538 else
539 {
540 for (const auto& stmt: node->getSVFStmts())
541 {
542 if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
543 {
544 // like llvm bitcode `p = gep p, idx`
545 // we check rhs p's all address are valid mem
546 SVFVar* rhs = gep->getRHSVar();
547 if (!canSafelyDerefPtr(as, rhs))
548 {
549 AEException bug(stmt->toString());
550 addBugToReporter(bug, stmt->getICFGNode());
551 }
552 }
553 else if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
554 {
555 // like llvm bitcode `p = load q`
556 // we check lhs p's all address are valid mem
557 SVFVar* lhs = load->getLHSVar();
558 if ( !canSafelyDerefPtr(as, lhs))
559 {
560 AEException bug(stmt->toString());
561 addBugToReporter(bug, stmt->getICFGNode());
562 }
563 }
564 }
565 }
566}
Exception class for handling errors in Abstract Execution.
Definition AEDetector.h:109
bool canSafelyDerefPtr(AbstractState &as, const SVFVar *ptr)
void addBugToReporter(const AEException &e, const ICFGNode *node)
Adds a bug to the reporter based on an exception.
Definition AEDetector.h:376
void detectExtAPI(AbstractState &as, const CallICFGNode *call)
Handle external API calls related to nullptr dereferences.
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:437

◆ detectExtAPI()

void NullptrDerefDetector::detectExtAPI ( AbstractState as,
const CallICFGNode call 
)

Handle external API calls related to nullptr dereferences.

Parameters
asReference to the abstract state.
callPointer to the call ICFG node.

Definition at line 620 of file AEDetector.cpp.

621{
622 assert(call->getCalledFunction() && "FunObjVar* is nullptr");
623 // get ext type
624 // get argument index which are nullptr deref checkpoints for extapi
625 std::vector<u32_t> tmp_args;
626 for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
627 {
628 if (annotation.find("MEMCPY") != std::string::npos)
629 {
630 if (call->arg_size() < 4)
631 {
632 // for memcpy(void* dest, const void* src, size_t n)
633 tmp_args.push_back(0);
634 tmp_args.push_back(1);
635 }
636 else
637 {
638 // for unsigned long iconv(void* cd, char **restrict inbuf, unsigned long *restrict inbytesleft, char **restrict outbuf, unsigned long *restrict outbytesleft)
639 tmp_args.push_back(1);
640 tmp_args.push_back(2);
641 tmp_args.push_back(3);
642 tmp_args.push_back(4);
643 }
644 }
645 else if (annotation.find("MEMSET") != std::string::npos)
646 {
647 // for memset(void* dest, elem, sz)
648 tmp_args.push_back(0);
649 }
650 else if (annotation.find("STRCPY") != std::string::npos)
651 {
652 // for strcpy(void* dest, void* src)
653 tmp_args.push_back(0);
654 tmp_args.push_back(1);
655 }
656 else if (annotation.find("STRCAT") != std::string::npos)
657 {
658 // for strcat(void* dest, const void* src)
659 // for strncat(void* dest, const void* src, size_t n)
660 tmp_args.push_back(0);
661 tmp_args.push_back(1);
662 }
663 }
664
665 for (const auto &arg: tmp_args)
666 {
667 if (call->arg_size() <= arg)
668 continue;
669 const SVFVar* argVal = call->getArgument(arg);
671 {
672 AEException bug(call->toString());
673 addBugToReporter(bug, call);
674 }
675 }
676}
const std::string toString() const override
Definition ICFG.cpp:139
const ValVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition ICFGNode.h:494
const FunObjVar * getCalledFunction() const
Definition ICFGNode.h:512
u32_t arg_size() const
Definition ICFGNode.h:499

◆ handleStubFunctions()

void NullptrDerefDetector::handleStubFunctions ( const CallICFGNode call)
virtual

Handles external API calls related to nullptr dereferences.

Parameters
callPointer to the call ICFG node.

Implements SVF::AEDetector.

Definition at line 569 of file AEDetector.cpp.

570{
571 std::string funcName = callNode->getCalledFunction()->getName();
572 if (funcName == "UNSAFE_LOAD")
573 {
574 // void UNSAFE_LOAD(void* ptr);
576 if (callNode->arg_size() < 1)
577 return;
579
580 const SVFVar* arg0Val = callNode->getArgument(0);
581 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)
582 bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
583 if (!isSafe)
584 {
585 SVFUtil::outs() << SVFUtil::sucMsg("success: expected null dereference at UNSAFE_LOAD")
586 << " — " << callNode->toString() << "\n";
587 return;
588 }
589 else
590 {
591 SVFUtil::outs() << SVFUtil::errMsg("failure: null dereference expected at UNSAFE_LOAD, but none detected")
592 << " — Position: " << callNode->getSourceLoc() << "\n";
593 assert(false);
594 }
595 }
596 else if (funcName == "SAFE_LOAD")
597 {
598 // void SAFE_LOAD(void* ptr);
600 if (callNode->arg_size() < 1) return;
602 const SVFVar* arg0Val = callNode->getArgument(0);
603 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols
604 bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
605 if (isSafe)
606 {
607 SVFUtil::outs() << SVFUtil::sucMsg("success: expected safe dereference at SAFE_LOAD")
608 << " — " << callNode->toString() << "\n";
609 return;
610 }
611 else
612 {
613 SVFUtil::outs() << SVFUtil::errMsg("failure: unexpected null dereference at SAFE_LOAD")
614 << " — Position: " << callNode->getSourceLoc() << "\n";
615 assert(false);
616 }
617 }
618}
static AbstractInterpretation & getAEInstance()
AbstractState & getAbsStateFromTrace(const ICFGNode *node)
Retrieves the abstract state from the trace for a given ICFG node.
Set< const CallICFGNode * > checkpoints
NodeID getId() const
Get ID.
Definition SVFValue.h:160
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:55
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:78
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52

◆ isNull()

bool SVF::NullptrDerefDetector::isNull ( AbstractValue  v)
inline

Check if an Abstract Value is NULL (or uninitialized).

Parameters
vAn Abstract Value of loaded from an address in an Abstract State.

Definition at line 431 of file AEDetector.h.

432 {
433 return !v.isAddr() && !v.isInterval();
434 }

◆ isUninit()

bool SVF::NullptrDerefDetector::isUninit ( AbstractValue  v)
inline

Checks if an Abstract Value is uninitialized.

Parameters
vThe Abstract Value to check.
Returns
True if the value is uninitialized, false otherwise.

Definition at line 364 of file AEDetector.h.

365 {
366 // uninitialized value has neither interval value nor address value
367 bool is = v.getAddrs().isBottom() && v.getInterval().isBottom();
368 return is;
369 }

◆ reportBug()

void SVF::NullptrDerefDetector::reportBug ( )
inlinevirtual

Reports all detected nullptr dereference bugs.

Implements SVF::AEDetector.

Definition at line 404 of file AEDetector.h.

405 {
406 if (!nodeToBugInfo.empty())
407 {
408 std::cerr << "###################### Nullptr Dereference (" + std::to_string(nodeToBugInfo.size())
409 + " found)######################\n";
410 std::cerr << "---------------------------------------------\n";
411 for (const auto& it : nodeToBugInfo)
412 {
413 std::cerr << it.second << "\n---------------------------------------------\n";
414 }
415 }
416 }

Friends And Related Symbol Documentation

◆ AbstractInterpretation

Definition at line 332 of file AEDetector.h.

Member Data Documentation

◆ bugLoc

Set<std::string> SVF::NullptrDerefDetector::bugLoc
private

Set of locations where bugs have been reported.

Definition at line 439 of file AEDetector.h.

◆ nodeToBugInfo

Map<const ICFGNode*, std::string> SVF::NullptrDerefDetector::nodeToBugInfo
private

Maps ICFG nodes to bug information.

Definition at line 441 of file AEDetector.h.

◆ recoder

SVFBugReport SVF::NullptrDerefDetector::recoder
private

Recorder for abstract execution bugs.

Definition at line 440 of file AEDetector.h.


The documentation for this class was generated from the following files: