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 326 of file AEDetector.h.

Constructor & Destructor Documentation

◆ NullptrDerefDetector()

SVF::NullptrDerefDetector::NullptrDerefDetector ( )
inline

Definition at line 330 of file AEDetector.h.

331 {
333 }
@ NULL_DEREF
Detector for nullptr dereference issues.
Definition AEDetector.h:48
DetectorKind kind
The kind of the detector.
Definition AEDetector.h:100

◆ ~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 372 of file AEDetector.h.

373 {
376 eventStack.push_back(sourceInstEvent); // Add the source instruction event to the event stack
377
378 if (eventStack.empty())
379 {
380 return; // If the event stack is empty, return early
381 }
382 std::string loc = eventStack.back().getEventLoc(); // Get the location of the last event in the stack
383
384 // Check if the bug at this location has already been reported
385 if (bugLoc.find(loc) != bugLoc.end())
386 {
387 return; // If the bug location is already reported, return early
388 }
389 else
390 {
391 bugLoc.insert(loc); // Otherwise, mark this location as reported
392 }
394 nodeToBugInfo[node] = e.what(); // Record the exception information for the node
395 }
std::vector< SVFBugEvent > EventStack
Set< std::string > bugLoc
Set of locations where bugs have been reported.
Definition AEDetector.h:435
SVFBugReport recoder
Recorder for abstract execution bugs.
Definition AEDetector.h:436
Map< const ICFGNode *, std::string > nodeToBugInfo
Maps ICFG nodes to bug information.
Definition AEDetector.h:437
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 678 of file AEDetector.cpp.

679{
680 NodeID value_id = value->getId();
682 // uninit value cannot be dereferenced, return unsafe
683 if (isUninit(AbsVal)) return false;
684 // Interval Value (non-addr) is not the checkpoint of nullptr dereference, return safe
685 if (!AbsVal.isAddr()) return true;
686 for (const auto &addr: AbsVal.getAddrs())
687 {
688 // if the addr itself is invalid mem, report unsafe
690 return false;
691 // if nullptr is detected, return unsafe
693 return false;
694 // if addr is labeled freed mem, report unsafe
695 else if (as.isFreedMem(addr))
696 return false;
697 }
698
699
700 return true;
701}
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:360
u32_t NodeID
Definition GeneralType.h:56

◆ classof()

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

Definition at line 337 of file AEDetector.h.

338 {
339 return detector->getKind() == AEDetector::NULL_DEREF;
340 }

◆ 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 525 of file AEDetector.cpp.

526{
527 if (SVFUtil::isa<CallICFGNode>(node))
528 {
529 // external API like memset(*dst, elem, sz)
530 // we check if it's external api and check the corrisponding index
531 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
532 if (SVFUtil::isExtCall(callNode->getCalledFunction()))
533 {
535 }
536 }
537 else
538 {
539 for (const auto& stmt: node->getSVFStmts())
540 {
541 if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
542 {
543 // like llvm bitcode `p = gep p, idx`
544 // we check rhs p's all address are valid mem
545 SVFVar* rhs = gep->getRHSVar();
546 if (!canSafelyDerefPtr(as, rhs))
547 {
548 AEException bug(stmt->toString());
549 addBugToReporter(bug, stmt->getICFGNode());
550 }
551 }
552 else if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
553 {
554 // like llvm bitcode `p = load q`
555 // we check lhs p's all address are valid mem
556 SVFVar* lhs = load->getLHSVar();
557 if ( !canSafelyDerefPtr(as, lhs))
558 {
559 AEException bug(stmt->toString());
560 addBugToReporter(bug, stmt->getICFGNode());
561 }
562 }
563 }
564 }
565}
Exception class for handling errors in Abstract Execution.
Definition AEDetector.h:108
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:372
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 619 of file AEDetector.cpp.

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

569{
570 std::string funcName = callNode->getCalledFunction()->getName();
571 if (funcName == "UNSAFE_LOAD")
572 {
573 // void UNSAFE_LOAD(void* ptr);
575 if (callNode->arg_size() < 1)
576 return;
578
579 const SVFVar* arg0Val = callNode->getArgument(0);
580 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)
581 bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
582 if (!isSafe)
583 {
584 SVFUtil::outs() << SVFUtil::sucMsg("success: expected null dereference at UNSAFE_LOAD")
585 << " — " << callNode->toString() << "\n";
586 return;
587 }
588 else
589 {
590 SVFUtil::outs() << SVFUtil::errMsg("failure: null dereference expected at UNSAFE_LOAD, but none detected")
591 << " — Position: " << callNode->getSourceLoc() << "\n";
592 assert(false);
593 }
594 }
595 else if (funcName == "SAFE_LOAD")
596 {
597 // void SAFE_LOAD(void* ptr);
599 if (callNode->arg_size() < 1) return;
601 const SVFVar* arg0Val = callNode->getArgument(0);
602 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols
603 bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
604 if (isSafe)
605 {
606 SVFUtil::outs() << SVFUtil::sucMsg("success: expected safe dereference at SAFE_LOAD")
607 << " — " << callNode->toString() << "\n";
608 return;
609 }
610 else
611 {
612 SVFUtil::outs() << SVFUtil::errMsg("failure: unexpected null dereference at SAFE_LOAD")
613 << " — Position: " << callNode->getSourceLoc() << "\n";
614 assert(false);
615 }
616 }
617}
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:158
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 427 of file AEDetector.h.

428 {
429 return !v.isAddr() && !v.isInterval();
430 }

◆ 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 360 of file AEDetector.h.

361 {
362 // uninitialized value has neither interval value nor address value
363 bool is = v.getAddrs().isBottom() && v.getInterval().isBottom();
364 return is;
365 }

◆ reportBug()

void SVF::NullptrDerefDetector::reportBug ( )
inlinevirtual

Reports all detected nullptr dereference bugs.

Implements SVF::AEDetector.

Definition at line 400 of file AEDetector.h.

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

Friends And Related Symbol Documentation

◆ AbstractInterpretation

Definition at line 328 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 435 of file AEDetector.h.

◆ nodeToBugInfo

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

Maps ICFG nodes to bug information.

Definition at line 437 of file AEDetector.h.

◆ recoder

SVFBugReport SVF::NullptrDerefDetector::recoder
private

Recorder for abstract execution bugs.

Definition at line 436 of file AEDetector.h.


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