Static Value-Flow Analysis
Loading...
Searching...
No Matches
Public Types | Public Member Functions | Static Public Member Functions | Protected Attributes | List of all members
SVF::AbsExtAPI Class Reference

Handles external API calls and manages abstract states. More...

#include <AbsExtAPI.h>

Public Types

enum  ExtAPIType {
  UNCLASSIFIED , MEMCPY , MEMSET , STRCPY ,
  STRCAT
}
 Enumeration of external API types. More...
 

Public Member Functions

 AbsExtAPI (Map< const ICFGNode *, AbstractState > &traces)
 Constructor for AbsExtAPI.
 
void initExtFunMap ()
 Initializes the external function map.
 
std::string strRead (AbstractState &as, const SVFVar *rhs)
 Reads a string from the abstract state.
 
void handleExtAPI (const CallICFGNode *call)
 Handles an external API call.
 
u32_t getElementSize (AbstractState &as, const SVFVar *var)
 Get the byte size of each element for a pointer/array variable.
 
IntervalValue getStrlen (AbstractState &as, const SVF::SVFVar *strValue)
 Calculate the length of a null-terminated string in abstract state.
 
void handleStrcpy (const CallICFGNode *call)
 
void handleStrcat (const CallICFGNode *call)
 
void handleStrncat (const CallICFGNode *call)
 
void handleMemcpy (AbstractState &as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx)
 Core memcpy: copy len bytes from src to dst starting at dst[start_idx].
 
void handleMemset (AbstractState &as, const SVFVar *dst, IntervalValue elem, IntervalValue len)
 
IntervalValue getRangeLimitFromType (const SVFType *type)
 Gets the range limit from a type.
 
AbstractStategetAbsStateFromTrace (const ICFGNode *node)
 Retrieves the abstract state from the trace for a given ICFG node.
 

Static Public Member Functions

static bool isValidLength (const IntervalValue &len)
 Check if an interval length is usable (not bottom, not unbounded).
 

Protected Attributes

SVFIRsvfir
 Pointer to the SVF intermediate representation.
 
ICFGicfg
 Pointer to the interprocedural control flow graph.
 
Map< const ICFGNode *, AbstractState > & abstractTrace
 Map of ICFG nodes to abstract states.
 
Map< std::string, std::function< void(const CallICFGNode *)> > func_map
 Map of function names to handlers.
 

Detailed Description

Handles external API calls and manages abstract states.

Definition at line 43 of file AbsExtAPI.h.

Member Enumeration Documentation

◆ ExtAPIType

Enumeration of external API types.

Enumerator
UNCLASSIFIED 
MEMCPY 
MEMSET 
STRCPY 
STRCAT 

Definition at line 50 of file AbsExtAPI.h.

Constructor & Destructor Documentation

◆ AbsExtAPI()

AbsExtAPI::AbsExtAPI ( Map< const ICFGNode *, AbstractState > &  traces)

Constructor for AbsExtAPI.

Parameters
abstractTraceReference to a map of ICFG nodes to abstract states.

Definition at line 35 of file AbsExtAPI.cpp.

36{
38 icfg = svfir->getICFG();
40}
void initExtFunMap()
Initializes the external function map.
Definition AbsExtAPI.cpp:42
Map< const ICFGNode *, AbstractState > & abstractTrace
Map of ICFG nodes to abstract states.
Definition AbsExtAPI.h:114
SVFIR * svfir
Pointer to the SVF intermediate representation.
Definition AbsExtAPI.h:112
ICFG * icfg
Pointer to the interprocedural control flow graph.
Definition AbsExtAPI.h:113
ICFG * getICFG() const
Definition SVFIR.h:217
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:116
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74

Member Function Documentation

◆ getAbsStateFromTrace()

AbstractState & AbsExtAPI::getAbsStateFromTrace ( const ICFGNode node)

Retrieves the abstract state from the trace for a given ICFG node.

Parameters
nodePointer to the ICFG node.
Returns
Reference to the abstract state.
Exceptions
Assertionif no trace exists for the node.

Definition at line 338 of file AbsExtAPI.cpp.

339{
340 if (abstractTrace.count(node) == 0)
341 {
342 assert(0 && "No preAbsTrace for this node");
343 abort();
344 }
345 else
346 {
347 return abstractTrace[node];
348 }
349}

◆ getElementSize()

u32_t AbsExtAPI::getElementSize ( AbstractState as,
const SVFVar var 
)

Get the byte size of each element for a pointer/array variable.

Get the byte size of each element for a pointer/array variable. Shared by handleMemcpy, handleMemset, and getStrlen to avoid duplication.

Definition at line 463 of file AbsExtAPI.cpp.

464{
465 if (var->getType()->isArrayTy())
466 {
467 return SVFUtil::dyn_cast<SVFArrayType>(var->getType())
468 ->getTypeOfElement()->getByteSize();
469 }
470 if (var->getType()->isPointerTy())
471 {
472 if (const SVFType* elemType = as.getPointeeElement(var->getId()))
473 {
474 if (elemType->isArrayTy())
475 return SVFUtil::dyn_cast<SVFArrayType>(elemType)
476 ->getTypeOfElement()->getByteSize();
477 return elemType->getByteSize();
478 }
479 return 1;
480 }
481 assert(false && "unsupported type for element size");
482 return 1;
483}

◆ getRangeLimitFromType()

IntervalValue AbsExtAPI::getRangeLimitFromType ( const SVFType type)

Gets the range limit from a type.

Parameters
typePointer to the SVF type.
Returns
The interval value representing the range limit.

This function, getRangeLimitFromType, calculates the lower and upper bounds of a numeric range for a given SVFType. It is used to determine the possible value range of integer types. If the type is an SVFIntegerType, it calculates the bounds based on the size and signedness of the type. The calculated bounds are returned as an IntervalValue representing the lower (lb) and upper (ub) limits of the range.

Parameters
typeThe SVFType for which to calculate the value range.
Returns
An IntervalValue representing the lower and upper bounds of the range.

Definition at line 696 of file AbsExtAPI.cpp.

697{
698 if (const SVFIntegerType* intType = SVFUtil::dyn_cast<SVFIntegerType>(type))
699 {
700 u32_t bits = type->getByteSize() * 8;
701 s64_t ub = 0;
702 s64_t lb = 0;
703 if (bits >= 32)
704 {
705 if (intType->isSigned())
706 {
707 ub = static_cast<s64_t>(std::numeric_limits<s32_t>::max());
708 lb = static_cast<s64_t>(std::numeric_limits<s32_t>::min());
709 }
710 else
711 {
712 ub = static_cast<s64_t>(std::numeric_limits<u32_t>::max());
713 lb = static_cast<s64_t>(std::numeric_limits<u32_t>::min());
714 }
715 }
716 else if (bits == 16)
717 {
718 if (intType->isSigned())
719 {
720 ub = static_cast<s64_t>(std::numeric_limits<s16_t>::max());
721 lb = static_cast<s64_t>(std::numeric_limits<s16_t>::min());
722 }
723 else
724 {
725 ub = static_cast<s64_t>(std::numeric_limits<u16_t>::max());
726 lb = static_cast<s64_t>(std::numeric_limits<u16_t>::min());
727 }
728 }
729 else if (bits == 8)
730 {
731 if (intType->isSigned())
732 {
733 ub = static_cast<s64_t>(std::numeric_limits<int8_t>::max());
734 lb = static_cast<s64_t>(std::numeric_limits<int8_t>::min());
735 }
736 else
737 {
738 ub = static_cast<s64_t>(std::numeric_limits<uint8_t>::max());
739 lb = static_cast<s64_t>(std::numeric_limits<uint8_t>::min());
740 }
741 }
742 return IntervalValue(lb, ub);
743 }
744 else if (SVFUtil::isa<SVFOtherType>(type))
745 {
746 // handle other type like float double, set s32_t as the range
747 s64_t ub = static_cast<s64_t>(std::numeric_limits<s32_t>::max());
748 s64_t lb = static_cast<s64_t>(std::numeric_limits<s32_t>::min());
749 return IntervalValue(lb, ub);
750 }
751 else
752 {
753 return IntervalValue::top();
754 // other types, return top interval
755 }
756}
unsigned u32_t
Definition CommandLine.h:18
newitem type
Definition cJSON.cpp:2739
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
signed long long s64_t
Definition GeneralType.h:50

◆ getStrlen()

IntervalValue AbsExtAPI::getStrlen ( AbstractState as,
const SVF::SVFVar strValue 
)

Calculate the length of a null-terminated string in abstract state.

Calculate the length of a null-terminated string in abstract state. Scans memory from the base of strValue looking for a '\0' byte. Returns an IntervalValue: exact length if '\0' found, otherwise [0, MaxFieldLimit].

Definition at line 496 of file AbsExtAPI.cpp.

497{
498 NodeID value_id = strValue->getId();
499
500 // Step 1: determine the buffer size (in bytes) backing this pointer
501 u32_t dst_size = 0;
502 for (const auto& addr : as[value_id].getAddrs())
503 {
504 NodeID objId = as.getIDFromAddr(addr);
506 {
508 }
509 else
510 {
511 const ICFGNode* icfgNode = svfir->getBaseObject(objId)->getICFGNode();
512 for (const SVFStmt* stmt2: icfgNode->getSVFStmts())
513 {
514 if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
515 {
516 dst_size = as.getAllocaInstByteSize(addrStmt);
517 }
518 }
519 }
520 }
521
522 // Step 2: scan for '\0' terminator
523 u32_t len = 0;
524 if (as.inVarToAddrsTable(value_id))
525 {
526 for (u32_t index = 0; index < dst_size; index++)
527 {
529 as.getGepObjAddrs(value_id, IntervalValue(index));
531 for (const auto &addr: expr0.getAddrs())
532 {
533 val.join_with(as.load(addr));
534 }
535 if (val.getInterval().is_numeral() &&
536 (char) val.getInterval().getIntNumeral() == '\0')
537 {
538 break;
539 }
540 ++len;
541 }
542 }
543
544 // Step 3: scale by element size and return
546 if (len == 0)
548 return IntervalValue(len * elemSize);
549}
int index
Definition cJSON.h:170
u32_t getElementSize(AbstractState &as, const SVFVar *var)
Get the byte size of each element for a pointer/array variable.
void join_with(const AbstractValue &other)
const ICFGNode * getICFGNode() const
Get the ICFGNode related to the creation of this object.
bool isConstantByteSize() const
Check if byte size is a const value.
u32_t getByteSizeOfObj() const
Get the byte size of this object.
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:35
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:478
u32_t NodeID
Definition GeneralType.h:56

◆ handleExtAPI()

void AbsExtAPI::handleExtAPI ( const CallICFGNode call)

Handles an external API call.

Parameters
callPointer to the call ICFG node.

Definition at line 381 of file AbsExtAPI.cpp.

382{
384 const FunObjVar *fun = call->getCalledFunction();
385 assert(fun && "FunObjVar* is nullptr");
387 // get type of mem api
388 for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(fun))
389 {
390 if (annotation.find("MEMCPY") != std::string::npos)
391 extType = MEMCPY;
392 if (annotation.find("MEMSET") != std::string::npos)
393 extType = MEMSET;
394 if (annotation.find("STRCPY") != std::string::npos)
395 extType = STRCPY;
396 if (annotation.find("STRCAT") != std::string::npos)
397 extType = STRCAT;
398 }
399 if (extType == UNCLASSIFIED)
400 {
401 if (func_map.find(fun->getName()) != func_map.end())
402 {
403 func_map[fun->getName()](call);
404 }
405 else
406 {
407 if (const SVFVar* ret = call->getRetICFGNode()->getActualRet())
408 {
409 u32_t lhsId = ret->getId();
410 if (as.inVarToAddrsTable(lhsId))
411 {
412
413 }
414 else
415 {
417 }
418 }
419 return;
420 }
421 }
422 // 1. memcpy functions like memcpy_chk, strncpy, annotate("MEMCPY"), annotate("BUF_CHECK:Arg0, Arg2"), annotate("BUF_CHECK:Arg1, Arg2")
423 else if (extType == MEMCPY)
424 {
425 IntervalValue len = as[call->getArgument(2)->getId()].getInterval();
426 (void)svfir->getSVFVar(call->getArgument(0)->getId());
427 handleMemcpy(as, call->getArgument(0), call->getArgument(1), len, 0);
428 }
429 else if (extType == MEMSET)
430 {
431 // memset dst is arg0, elem is arg1, size is arg2
432 IntervalValue len = as[call->getArgument(2)->getId()].getInterval();
433 IntervalValue elem = as[call->getArgument(1)->getId()].getInterval();
434 handleMemset(as, call->getArgument(0), elem, len);
435 }
436 else if (extType == STRCPY)
437 {
438 handleStrcpy(call);
439 }
440 else if (extType == STRCAT)
441 {
442 // Both strcat and strncat are annotated as STRCAT.
443 // Distinguish by name: strncat/wcsncat contain "ncat".
444 const std::string& name = fun->getName();
445 if (name.find("ncat") != std::string::npos)
446 handleStrncat(call);
447 else
448 handleStrcat(call);
449 }
450 else
451 {
452
453 }
454 return;
455}
const char *const name
Definition cJSON.h:264
void handleMemset(AbstractState &as, const SVFVar *dst, IntervalValue elem, IntervalValue len)
void handleStrncat(const CallICFGNode *call)
AbstractState & getAbsStateFromTrace(const ICFGNode *node)
Retrieves the abstract state from the trace for a given ICFG node.
void handleMemcpy(AbstractState &as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx)
Core memcpy: copy len bytes from src to dst starting at dst[start_idx].
ExtAPIType
Enumeration of external API types.
Definition AbsExtAPI.h:50
void handleStrcat(const CallICFGNode *call)
void handleStrcpy(const CallICFGNode *call)
Map< std::string, std::function< void(const CallICFGNode *)> > func_map
Map of function names to handlers.
Definition AbsExtAPI.h:115
const ValVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition ICFGNode.h:482
const FunObjVar * getCalledFunction() const
Definition ICFGNode.h:500
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:439
const SVFVar * getActualRet() const
Return actual return parameter.
Definition ICFGNode.h:624
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:131
NodeID getId() const
Get ID.
Definition SVFValue.h:160
virtual const std::string & getName() const
Definition SVFValue.h:186

◆ handleMemcpy()

void AbsExtAPI::handleMemcpy ( AbstractState as,
const SVF::SVFVar dst,
const SVF::SVFVar src,
IntervalValue  len,
u32_t  start_idx 
)

Core memcpy: copy len bytes from src to dst starting at dst[start_idx].

Definition at line 595 of file AbsExtAPI.cpp.

598{
599 if (!isValidLength(len)) return;
600
601 u32_t dstId = dst->getId();
602 u32_t srcId = src->getId();
604 u32_t size = std::min((u32_t)Options::MaxFieldLimit(),
605 (u32_t)len.lb().getIntNumeral());
606 u32_t range_val = size / elemSize;
607
608 if (!as.inVarToAddrsTable(srcId) || !as.inVarToAddrsTable(dstId))
609 return;
610
611 for (u32_t index = 0; index < range_val; index++)
612 {
614 as.getGepObjAddrs(srcId, IntervalValue(index));
616 as.getGepObjAddrs(dstId, IntervalValue(index + start_idx));
617 for (const auto &dstAddr: expr_dst.getAddrs())
618 {
619 for (const auto &srcAddr: expr_src.getAddrs())
620 {
621 u32_t objId = as.getIDFromAddr(srcAddr);
622 if (as.inAddrToValTable(objId) || as.inAddrToAddrsTable(objId))
623 {
624 as.store(dstAddr, as.load(srcAddr));
625 }
626 }
627 }
628 }
629}
static bool isValidLength(const IntervalValue &len)
Check if an interval length is usable (not bottom, not unbounded).

◆ handleMemset()

void AbsExtAPI::handleMemset ( AbstractState as,
const SVFVar dst,
IntervalValue  elem,
IntervalValue  len 
)

Core memset: fill dst with elem for len bytes. Note: elemSize here uses the pointee type's full size (not array element size) to match how LLVM memset/wmemset intrinsics measure len. For a pointer to wchar_t[100], elemSize = sizeof(wchar_t[100]), so range_val reflects the number of top-level GEP fields, not individual array elements.

Definition at line 636 of file AbsExtAPI.cpp.

638{
639 if (!isValidLength(len)) return;
640
641 u32_t dstId = dst->getId();
642 u32_t elemSize = 1;
643 if (dst->getType()->isArrayTy())
644 {
645 elemSize = SVFUtil::dyn_cast<SVFArrayType>(dst->getType())
646 ->getTypeOfElement()->getByteSize();
647 }
648 else if (dst->getType()->isPointerTy())
649 {
650 if (const SVFType* elemType = as.getPointeeElement(dstId))
651 elemSize = elemType->getByteSize();
652 else
653 elemSize = 1;
654 }
655 else
656 {
657 assert(false && "unsupported type for element size");
658 }
659 u32_t size = std::min((u32_t)Options::MaxFieldLimit(),
660 (u32_t)len.lb().getIntNumeral());
661 u32_t range_val = size / elemSize;
662
663 for (u32_t index = 0; index < range_val; index++)
664 {
665 if (!as.inVarToAddrsTable(dstId))
666 break;
667 AbstractValue lhs_gep = as.getGepObjAddrs(dstId, IntervalValue(index));
668 for (const auto &addr: lhs_gep.getAddrs())
669 {
670 u32_t objId = as.getIDFromAddr(addr);
671 if (as.inAddrToValTable(objId))
672 {
673 AbstractValue tmp = as.load(addr);
675 as.store(addr, tmp);
676 }
677 else
678 {
679 as.store(addr, elem);
680 }
681 }
682 }
683}
bool isArrayTy() const
Definition SVFType.h:299
bool isPointerTy() const
Definition SVFType.h:294
virtual const SVFType * getType() const
Definition SVFValue.h:171

◆ handleStrcat()

void AbsExtAPI::handleStrcat ( const CallICFGNode call)

strcat(dst, src): append all of src after the end of dst. Covers: strcat, __strcat_chk, wcscat, __wcscat_chk

Definition at line 570 of file AbsExtAPI.cpp.

571{
573 const SVFVar* dst = call->getArgument(0);
574 const SVFVar* src = call->getArgument(1);
577 if (!isValidLength(dstLen)) return;
578 handleMemcpy(as, dst, src, srcLen, dstLen.lb().getIntNumeral());
579}
IntervalValue getStrlen(AbstractState &as, const SVF::SVFVar *strValue)
Calculate the length of a null-terminated string in abstract state.

◆ handleStrcpy()

void AbsExtAPI::handleStrcpy ( const CallICFGNode call)

strcpy(dst, src): copy all of src (including '\0') into dst. Covers: strcpy, __strcpy_chk, stpcpy, wcscpy, __wcscpy_chk

Definition at line 557 of file AbsExtAPI.cpp.

558{
560 const SVFVar* dst = call->getArgument(0);
561 const SVFVar* src = call->getArgument(1);
563 // no need to -1, since srcLen includes up to (but not past) '\0'
564 if (!isValidLength(srcLen)) return;
565 handleMemcpy(as, dst, src, srcLen, 0);
566}

◆ handleStrncat()

void AbsExtAPI::handleStrncat ( const CallICFGNode call)

strncat(dst, src, n): append at most n bytes of src after the end of dst. Covers: strncat, __strncat_chk, wcsncat, __wcsncat_chk

Definition at line 583 of file AbsExtAPI.cpp.

584{
586 const SVFVar* dst = call->getArgument(0);
587 const SVFVar* src = call->getArgument(1);
588 IntervalValue n = as[call->getArgument(2)->getId()].getInterval();
590 if (!isValidLength(dstLen)) return;
591 handleMemcpy(as, dst, src, n, dstLen.lb().getIntNumeral());
592}
cJSON * n
Definition cJSON.cpp:2558

◆ initExtFunMap()

void AbsExtAPI::initExtFunMap ( )

Initializes the external function map.

Definition at line 42 of file AbsExtAPI.cpp.

43{
44#define SSE_FUNC_PROCESS(LLVM_NAME ,FUNC_NAME) \
45 auto sse_##FUNC_NAME = [this](const CallICFGNode *callNode) { \
46 /* run real ext function */ \
47 AbstractState& as = getAbsStateFromTrace(callNode); \
48 u32_t rhs_id = callNode->getArgument(0)->getId(); \
49 if (!as.inVarToValTable(rhs_id)) return; \
50 u32_t rhs = as[rhs_id].getInterval().lb().getIntNumeral(); \
51 s32_t res = FUNC_NAME(rhs); \
52 u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId(); \
53 as[lhsId] = IntervalValue(res); \
54 return; \
55 }; \
56 func_map[#FUNC_NAME] = sse_##FUNC_NAME;
57
69 SSE_FUNC_PROCESS(llvm.sin.f64, sin);
70 SSE_FUNC_PROCESS(llvm.cos.f64, cos);
71 SSE_FUNC_PROCESS(llvm.tan.f64, tan);
72 SSE_FUNC_PROCESS(llvm.log.f64, log);
76
77 auto sse_svf_assert = [this](const CallICFGNode* callNode)
78 {
80 u32_t arg0 = callNode->getArgument(0)->getId();
82 if (as[arg0].getInterval().equals(IntervalValue(1, 1)))
83 {
84 SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n");
85 }
86 else
87 {
88 SVFUtil::errs() << SVFUtil::errMsg("Assertion failure, this svf_assert cannot be verified!!\n") << callNode->toString() << "\n";
89 assert(false);
90 }
91 return;
92 };
93 func_map["svf_assert"] = sse_svf_assert;
94
95 auto svf_assert_eq = [this](const CallICFGNode* callNode)
96 {
97 u32_t arg0 = callNode->getArgument(0)->getId();
98 u32_t arg1 = callNode->getArgument(1)->getId();
100 if (as[arg0].getInterval().equals(as[arg1].getInterval()))
101 {
102 SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n");
103 }
104 else
105 {
106 SVFUtil::errs() <<"svf_assert_eq Fail. " << callNode->toString() << "\n";
107 assert(false);
108 }
109 return;
110 };
111 func_map["svf_assert_eq"] = svf_assert_eq;
112
113 auto svf_print = [&](const CallICFGNode* callNode)
114 {
115 if (callNode->arg_size() < 2) return;
117 u32_t num_id = callNode->getArgument(0)->getId();
118 std::string text = strRead(as, callNode->getArgument(1));
119 assert(as.inVarToValTable(num_id) && "print() should pass integer");
120 IntervalValue itv = as[num_id].getInterval();
121 std::cout << "Text: " << text <<", Value: " << callNode->getArgument(0)->toString()
122 << ", PrintVal: " << itv.toString() << ", Loc:" << callNode->getSourceLoc() << std::endl;
123 return;
124 };
125 func_map["svf_print"] = svf_print;
126
127 auto svf_set_value = [&](const CallICFGNode* callNode)
128 {
129 if (callNode->arg_size() < 2) return;
131 AbstractValue& num = as[callNode->getArgument(0)->getId()];
132 AbstractValue& lb = as[callNode->getArgument(1)->getId()];
133 AbstractValue& ub = as[callNode->getArgument(2)->getId()];
135 num.getInterval().set_to_top();
136 num.getInterval().meet_with(IntervalValue(lb.getInterval().lb(), ub.getInterval().ub()));
137 const ICFGNode* node = SVFUtil::cast<ValVar>(callNode->getArgument(0))->getICFGNode();
138 for (const SVFStmt* stmt: node->getSVFStmts())
139 {
140 if (SVFUtil::isa<LoadStmt>(stmt))
141 {
142 const LoadStmt* load = SVFUtil::cast<LoadStmt>(stmt);
143 NodeID rhsId = load->getRHSVarID();
144 as.storeValue(rhsId, num);
145 }
146 }
147 return;
148 };
149 func_map["set_value"] = svf_set_value;
150
151 auto sse_scanf = [&](const CallICFGNode* callNode)
152 {
154 //scanf("%d", &data);
155 if (callNode->arg_size() < 2) return;
156
157 u32_t dst_id = callNode->getArgument(1)->getId();
158 if (!as.inVarToAddrsTable(dst_id))
159 {
160 return;
161 }
162 else
163 {
165 for (auto vaddr: Addrs.getAddrs())
166 {
167 u32_t objId = as.getIDFromAddr(vaddr);
169 as.store(vaddr, range);
170 }
171 }
172 };
173 auto sse_fscanf = [&](const CallICFGNode* callNode)
174 {
175 //fscanf(stdin, "%d", &data);
176 if (callNode->arg_size() < 3) return;
178 u32_t dst_id = callNode->getArgument(2)->getId();
179 if (!as.inVarToAddrsTable(dst_id))
180 {
181 }
182 else
183 {
185 for (auto vaddr: Addrs.getAddrs())
186 {
187 u32_t objId = as.getIDFromAddr(vaddr);
189 as.store(vaddr, range);
190 }
191 }
192 };
193
194 func_map["__isoc99_fscanf"] = sse_fscanf;
195 func_map["__isoc99_scanf"] = sse_scanf;
196 func_map["__isoc99_vscanf"] = sse_scanf;
197 func_map["fscanf"] = sse_fscanf;
198 func_map["scanf"] = sse_scanf;
199 func_map["sscanf"] = sse_scanf;
200 func_map["__isoc99_sscanf"] = sse_scanf;
201 func_map["vscanf"] = sse_scanf;
202
203 auto sse_fread = [&](const CallICFGNode *callNode)
204 {
205 if (callNode->arg_size() < 3) return;
207 u32_t block_count_id = callNode->getArgument(2)->getId();
208 u32_t block_size_id = callNode->getArgument(1)->getId();
210 IntervalValue block_size = as[block_size_id].getInterval();
212 };
213 func_map["fread"] = sse_fread;
214
215 auto sse_sprintf = [&](const CallICFGNode *callNode)
216 {
217 // printf is difficult to predict since it has no byte size arguments
218 };
219
220 auto sse_snprintf = [&](const CallICFGNode *callNode)
221 {
222 if (callNode->arg_size() < 2) return;
224 u32_t size_id = callNode->getArgument(1)->getId();
225 u32_t dst_id = callNode->getArgument(0)->getId();
226 // get elem size of arg2
227 u32_t elemSize = 1;
228 if (callNode->getArgument(2)->getType()->isArrayTy())
229 {
230 elemSize = SVFUtil::dyn_cast<SVFArrayType>(
231 callNode->getArgument(2)->getType())->getTypeOfElement()->getByteSize();
232 }
233 else if (callNode->getArgument(2)->getType()->isPointerTy())
234 {
235 elemSize = as.getPointeeElement(callNode->getArgument(2)->getId())->getByteSize();
236 }
237 else
238 {
239 return;
240 // assert(false && "we cannot support this type");
241 }
242 IntervalValue size = as[size_id].getInterval() * IntervalValue(elemSize) - IntervalValue(1);
243 if (!as.inVarToAddrsTable(dst_id))
244 {
245 }
246 };
247 func_map["__snprintf_chk"] = sse_snprintf;
248 func_map["__vsprintf_chk"] = sse_sprintf;
249 func_map["__sprintf_chk"] = sse_sprintf;
250 func_map["snprintf"] = sse_snprintf;
251 func_map["sprintf"] = sse_sprintf;
252 func_map["vsprintf"] = sse_sprintf;
253 func_map["vsnprintf"] = sse_snprintf;
254 func_map["__vsnprintf_chk"] = sse_snprintf;
255 func_map["swprintf"] = sse_snprintf;
256 func_map["_snwprintf"] = sse_snprintf;
257
258
259 auto sse_itoa = [&](const CallICFGNode* callNode)
260 {
261 // itoa(num, ch, 10);
262 // num: int, ch: char*, 10 is decimal
263 if (callNode->arg_size() < 3) return;
265 u32_t num_id = callNode->getArgument(0)->getId();
266
267 u32_t num = (u32_t) as[num_id].getInterval().getNumeral();
268 std::string snum = std::to_string(num);
269 };
270 func_map["itoa"] = sse_itoa;
271
272
273 auto sse_strlen = [&](const CallICFGNode *callNode)
274 {
275 if (callNode->arg_size() < 1) return;
277 u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId();
278 // strlen/wcslen return the number of characters (not bytes).
279 // getStrlen returns byte-scaled length (len * elemSize) for use
280 // by memcpy/strcpy. Here we need the raw character count, so
281 // divide back by elemSize.
282 IntervalValue byteLen = getStrlen(as, callNode->getArgument(0));
283 u32_t elemSize = getElementSize(as, callNode->getArgument(0));
284 if (byteLen.is_numeral() && elemSize > 1)
285 as[lhsId] = IntervalValue(byteLen.getIntNumeral() / (s64_t)elemSize);
286 else
287 as[lhsId] = byteLen;
288 };
289 func_map["strlen"] = sse_strlen;
290 func_map["wcslen"] = sse_strlen;
291
292 auto sse_recv = [&](const CallICFGNode *callNode)
293 {
294 // recv(sockfd, buf, len, flags);
295 if (callNode->arg_size() < 4) return;
297 u32_t len_id = callNode->getArgument(2)->getId();
298 IntervalValue len = as[len_id].getInterval() - IntervalValue(1);
299 u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId();
300 as[lhsId] = len;
301 };
302 func_map["recv"] = sse_recv;
303 func_map["__recv"] = sse_recv;
304
305 auto sse_free = [&](const CallICFGNode *callNode)
306 {
307 if (callNode->arg_size() < 1) return;
309 const u32_t freePtr = callNode->getArgument(0)->getId();
310 for (auto addr: as[freePtr].getAddrs())
311 {
313 {
314 // Detected a double free — the address has already been freed.
315 // No action is taken at this point.
316 }
317 else
318 {
319 as.addToFreedAddrs(addr);
320 }
321 }
322 };
323 // Add all free-related functions to func_map
324 std::vector<std::string> freeFunctions =
325 {
326 "VOS_MemFree", "cfree", "free", "free_all_mem", "freeaddrinfo",
327 "gcry_mpi_release", "gcry_sexp_release", "globfree", "nhfree",
328 "obstack_free", "safe_cfree", "safe_free", "safefree", "safexfree",
329 "sm_free", "vim_free", "xfree", "SSL_CTX_free", "SSL_free", "XFree"
330 };
331
332 for (const auto& name : freeFunctions)
333 {
335 }
336};
#define SSE_FUNC_PROCESS(LLVM_NAME,FUNC_NAME)
std::string strRead(AbstractState &as, const SVFVar *rhs)
Reads a string from the abstract state.
IntervalValue getRangeLimitFromType(const SVFType *type)
Gets the range limit from a type.
static AbstractInterpretation & getAEInstance()
Set< const CallICFGNode * > checkpoints
static bool isBlackHoleObjAddr(u32_t addr)
IntervalValue & getInterval()
NodeID getRHSVarID() const
const BoundedInt & ub() const
Return the upper bound.
bool is_numeral() const
Return true if the IntervalValue is a number [num, num].
const std::string toString() const
const BoundedInt & lb() const
Return the lower bound.
int iscntrl(int c)
Definition extapi.c:932
int isdigit(int c)
Definition extapi.c:937
int isgraph(int c)
Definition extapi.c:942
int isspace(char c)
Definition extapi.c:962
int isprint(int c)
Definition extapi.c:952
int ispunct(int argument)
Definition extapi.c:957
int isblank(int character)
Definition extapi.c:927
int isalnum(int character)
Definition extapi.c:917
int isupper(int c)
Definition extapi.c:967
int isxdigit(int c)
Definition extapi.c:972
int isalpha(int character)
Definition extapi.c:922
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 & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
unsigned u32_t
Definition GeneralType.h:47

◆ isValidLength()

bool AbsExtAPI::isValidLength ( const IntervalValue len)
static

Check if an interval length is usable (not bottom, not unbounded).

Check if an interval length is usable for memory operations. Returns false for bottom (no information) or unbounded lower bound (cannot determine a concrete start for iteration).

Definition at line 488 of file AbsExtAPI.cpp.

489{
490 return !len.isBottom() && !len.lb().is_minus_infinity();
491}

◆ strRead()

std::string AbsExtAPI::strRead ( AbstractState as,
const SVFVar rhs 
)

Reads a string from the abstract state.

Parameters
asReference to the abstract state.
rhsPointer to the SVF variable representing the string.
Returns
The string value.

Definition at line 351 of file AbsExtAPI.cpp.

352{
353 // sse read string nodeID->string
354 std::string str0;
355
357 {
358 // dead loop for string and break if there's a \0. If no \0, it will throw err.
359 if (!as.inVarToAddrsTable(rhs->getId())) continue;
361 as.getGepObjAddrs(rhs->getId(), IntervalValue(index));
362
364 for (const auto &addr: expr0.getAddrs())
365 {
366 val.join_with(as.load(addr));
367 }
368 if (!val.getInterval().is_numeral())
369 {
370 break;
371 }
372 if ((char) val.getInterval().getIntNumeral() == '\0')
373 {
374 break;
375 }
376 str0.push_back((char) val.getInterval().getIntNumeral());
377 }
378 return str0;
379}

Member Data Documentation

◆ abstractTrace

Map<const ICFGNode*, AbstractState>& SVF::AbsExtAPI::abstractTrace
protected

Map of ICFG nodes to abstract states.

Definition at line 114 of file AbsExtAPI.h.

◆ func_map

Map<std::string, std::function<void(const CallICFGNode*)> > SVF::AbsExtAPI::func_map
protected

Map of function names to handlers.

Definition at line 115 of file AbsExtAPI.h.

◆ icfg

ICFG* SVF::AbsExtAPI::icfg
protected

Pointer to the interprocedural control flow graph.

Definition at line 113 of file AbsExtAPI.h.

◆ svfir

SVFIR* SVF::AbsExtAPI::svfir
protected

Pointer to the SVF intermediate representation.

Definition at line 112 of file AbsExtAPI.h.


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