Static Value-Flow Analysis
Loading...
Searching...
No Matches
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

void initExtFunMap ()
 Initializes the external function map.
std::string strRead (const ValVar *rhs, const ICFGNode *node)
 Reads a string from the abstract state.
void handleExtAPI (const CallICFGNode *call)
 Handles an external API call.
u32_t getElementSize (const ValVar *var)
 Get the byte size of each element for a pointer/array variable.
IntervalValue getStrlen (const ValVar *strValue, const ICFGNode *node)
 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 (const ValVar *dst, const ValVar *src, const IntervalValue &len, u32_t start_idx, const ICFGNode *node)
 Core memcpy: copy len bytes from src to dst starting at dst[start_idx].
void handleMemset (const ValVar *dst, const IntervalValue &elem, const IntervalValue &len, const ICFGNode *node)
IntervalValue getRangeLimitFromType (const SVFType *type)
 Gets the range limit from a type.
AbstractState & getAbsState (const ICFGNode *node)
 Retrieves the abstract state from the trace for a given ICFG node.
void collectCheckPoint ()
void checkPointAllSet ()

Static Public Member Functions

static bool isValidLength (const IntervalValue &len)
 Check if an interval length is usable (not bottom, not unbounded).
static u32_t getBoundedMinimumByteCount (const IntervalValue &len)
 Return the lower bound of len, capped by the field limit.

Public Attributes

Set< const CallICFGNode * > checkpoints

Protected Attributes

AbstractInterpretation * ae
 Owning AbstractInterpretation; provides state access.
SVFIR * svfir
 Pointer to the SVF intermediate representation.
ICFG * icfg
 Pointer to the interprocedural control flow graph.
Map< std::string, std::function< void(const CallICFGNode *)> > func_map
 Map of function names to handlers.

Private Member Functions

 AbsExtAPI (AbstractInterpretation *ae)
 Constructor for AbsExtAPI.

Friends

class AbstractInterpretation

Detailed Description

Handles external API calls and manages abstract states.

Definition at line 48 of file AbsExtAPI.h.

Member Enumeration Documentation

◆ ExtAPIType

Enumeration of external API types.

Enumerator
UNCLASSIFIED 
MEMCPY 
MEMSET 
STRCPY 
STRCAT 

Definition at line 55 of file AbsExtAPI.h.

Constructor & Destructor Documentation

◆ AbsExtAPI()

AbsExtAPI::AbsExtAPI ( AbstractInterpretation * ae)
private

Constructor for AbsExtAPI.

Parameters
aeReference to the AbstractInterpretation instance.

Definition at line 35 of file AbsExtAPI.cpp.

35 : ae(ae)
36{
38 icfg = svfir->getICFG();
40}
AbstractInterpretation * ae
Owning AbstractInterpretation; provides state access.
Definition AbsExtAPI.h:132
void initExtFunMap()
Initializes the external function map.
Definition AbsExtAPI.cpp:42
SVFIR * svfir
Pointer to the SVF intermediate representation.
Definition AbsExtAPI.h:133
ICFG * icfg
Pointer to the interprocedural control flow graph.
Definition AbsExtAPI.h:134
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:121

Member Function Documentation

◆ checkPointAllSet()

void AbsExtAPI::checkPointAllSet ( )

Definition at line 298 of file AbsExtAPI.cpp.

299{
300 if (!checkpoints.empty())
301 {
302 SVFUtil::errs() << SVFUtil::errMsg("At least one svf_assert has not been checked!!") << "\n";
303 for (const CallICFGNode* call: checkpoints)
304 SVFUtil::errs() << call->toString() + "\n";
305 assert(false);
306 }
307}
Set< const CallICFGNode * > checkpoints
Definition AbsExtAPI.h:129
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:98
std::ostream & errs()
Overwrite llvm::errs().
Definition SVFUtil.h:64

◆ collectCheckPoint()

void AbsExtAPI::collectCheckPoint ( )

Definition at line 258 of file AbsExtAPI.cpp.

259{
260 // traverse every ICFGNode
261 Set<std::string> ae_checkpoint_names = {"svf_assert"};
262 Set<std::string> buf_checkpoint_names = {"UNSAFE_BUFACCESS", "SAFE_BUFACCESS"};
263 Set<std::string> nullptr_checkpoint_names = {"UNSAFE_LOAD", "SAFE_LOAD"};
264
265 for (auto it = svfir->getICFG()->begin(); it != svfir->getICFG()->end(); ++it)
266 {
267 const ICFGNode* node = it->second;
268 if (const CallICFGNode *call = SVFUtil::dyn_cast<CallICFGNode>(node))
269 {
270 if (const FunObjVar *fun = call->getCalledFunction())
271 {
272 if (ae_checkpoint_names.find(fun->getName()) !=
273 ae_checkpoint_names.end())
274 {
275 checkpoints.insert(call);
276 }
278 {
279 if (buf_checkpoint_names.find(fun->getName()) !=
280 buf_checkpoint_names.end())
281 {
282 checkpoints.insert(call);
283 }
284 }
286 {
287 if (nullptr_checkpoint_names.find(fun->getName()) !=
288 nullptr_checkpoint_names.end())
289 {
290 checkpoints.insert(call);
291 }
292 }
293 }
294 }
295 }
296}
static const Option< bool > NullDerefCheck
nullptr dereference checker, Default: false
Definition Options.h:250
static const Option< bool > BufferOverflowCheck
buffer overflow checker, Default: false
Definition Options.h:248
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
Definition Casting.h:405
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition GeneralType.h:51

◆ getAbsState()

AbstractState & AbsExtAPI::getAbsState ( 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 253 of file AbsExtAPI.cpp.

254{
255 return ae->getAbsState(node);
256}

◆ getBoundedMinimumByteCount()

u32_t AbsExtAPI::getBoundedMinimumByteCount ( const IntervalValue & len)
static

Return the lower bound of len, capped by the field limit.

Definition at line 429 of file AbsExtAPI.cpp.

430{
431 u32_t byteCount = 0;
432 if (isValidLength(len) && len.lb().getIntNumeral() > 0)
433 {
434 byteCount = std::min(Options::MaxFieldLimit(),
435 (u32_t)len.lb().getIntNumeral());
436 }
437 return byteCount;
438}
static bool isValidLength(const IntervalValue &len)
Check if an interval length is usable (not bottom, not unbounded).
s64_t getIntNumeral() const
const BoundedInt & lb() const
Return the lower bound.
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition Options.h:34
unsigned u32_t
Definition GeneralType.h:67

◆ getElementSize()

u32_t AbsExtAPI::getElementSize ( const ValVar * 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 408 of file AbsExtAPI.cpp.

409{
410 if (var->getType()->isArrayTy())
411 {
413 ->getTypeOfElement()->getByteSize();
414 }
415 if (var->getType()->isPointerTy())
416 return 1;
417 assert(false && "unsupported type for element size");
418 return 1;
419}
bool isArrayTy() const
Definition SVFType.h:297
bool isPointerTy() const
Definition SVFType.h:292
virtual const SVFType * getType() const
Definition SVFValue.h:169

◆ 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 628 of file AbsExtAPI.cpp.

629{
630 if (const SVFIntegerType* intType = SVFUtil::dyn_cast<SVFIntegerType>(type))
631 {
632 u32_t bits = type->getByteSize() * 8;
633 s64_t ub = 0;
634 s64_t lb = 0;
635 if (bits >= 32)
636 {
637 if (intType->isSigned())
638 {
639 ub = static_cast<s64_t>(std::numeric_limits<s32_t>::max());
640 lb = static_cast<s64_t>(std::numeric_limits<s32_t>::min());
641 }
642 else
643 {
644 ub = static_cast<s64_t>(std::numeric_limits<u32_t>::max());
645 lb = static_cast<s64_t>(std::numeric_limits<u32_t>::min());
646 }
647 }
648 else if (bits == 16)
649 {
650 if (intType->isSigned())
651 {
652 ub = static_cast<s64_t>(std::numeric_limits<s16_t>::max());
653 lb = static_cast<s64_t>(std::numeric_limits<s16_t>::min());
654 }
655 else
656 {
657 ub = static_cast<s64_t>(std::numeric_limits<u16_t>::max());
658 lb = static_cast<s64_t>(std::numeric_limits<u16_t>::min());
659 }
660 }
661 else if (bits == 8)
662 {
663 if (intType->isSigned())
664 {
665 ub = static_cast<s64_t>(std::numeric_limits<int8_t>::max());
666 lb = static_cast<s64_t>(std::numeric_limits<int8_t>::min());
667 }
668 else
669 {
670 ub = static_cast<s64_t>(std::numeric_limits<uint8_t>::max());
671 lb = static_cast<s64_t>(std::numeric_limits<uint8_t>::min());
672 }
673 }
674 return IntervalValue(lb, ub);
675 }
677 {
678 // handle other type like float double, set s32_t as the range
679 s64_t ub = static_cast<s64_t>(std::numeric_limits<s32_t>::max());
680 s64_t lb = static_cast<s64_t>(std::numeric_limits<s32_t>::min());
681 return IntervalValue(lb, ub);
682 }
683 else
684 {
685 return IntervalValue::top();
686 // other types, return top interval
687 }
688}
newitem type
Definition cJSON.cpp:2739
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
LLVM_NODISCARD bool isa(const Y &Val)
Definition Casting.h:241
signed long long s64_t
Definition GeneralType.h:70

◆ getStrlen()

IntervalValue AbsExtAPI::getStrlen ( const ValVar * strValue,
const ICFGNode * node )

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 443 of file AbsExtAPI.cpp.

444{
445 AbstractState& as = getAbsState(node);
446 // Step 1: determine the buffer size (in bytes) backing this pointer
447 u32_t dst_size = 0;
448 const AbstractValue& ptrVal = ae->getAbsValue(strValue, node);
449 for (const auto& addr : ptrVal.getAddrs())
450 {
451 NodeID objId = as.getIDFromAddr(addr);
452 // A freed address also resolves to the blackhole object.
453 if (svfir->isNullOrBlkObj(objId))
454 continue;
455 if (svfir->getBaseObject(objId)->isConstantByteSize())
456 {
457 dst_size = svfir->getBaseObject(objId)->getByteSizeOfObj();
458 }
459 else
460 {
461 const ICFGNode* icfgNode = svfir->getBaseObject(objId)->getICFGNode();
462 if (!icfgNode)
463 continue;
464 for (const SVFStmt* stmt2: icfgNode->getSVFStmts())
465 {
466 if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
467 {
468 dst_size = ae->getAllocaInstByteSize(addrStmt).upperBound;
469 }
470 }
471 }
472 }
473
474 // Step 2: scan for '\0' terminator
475 u32_t len = 0;
476 for (u32_t index = 0; index < dst_size; index++)
477 {
478 AbstractValue expr0 =
479 ae->getGepObjAddrs(strValue, IntervalValue(index));
480 AbstractValue val;
481 for (const auto &addr: expr0.getAddrs())
482 {
483 val.join_with(as.load(addr));
484 }
485 if (val.getInterval().is_numeral() &&
486 (char) val.getInterval().getIntNumeral() == '\0')
487 {
488 break;
489 }
490 ++len;
491 }
492
493 // Step 3: scale by element size and return
494 u32_t elemSize = getElementSize(strValue);
495 if (len == 0)
496 return IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit());
497 return IntervalValue(len * elemSize);
498}
int index
Definition cJSON.h:170
AbstractState & getAbsState(const ICFGNode *node)
Retrieves the abstract state from the trace for a given ICFG node.
u32_t getElementSize(const ValVar *var)
Get the byte size of each element for a pointer/array variable.
u32_t getIDFromAddr(u32_t addr) const
Return the internal index if addr is an address otherwise return the value of idx.
virtual AbstractValue & load(u32_t addr)
void join_with(const AbstractValue &other)
IntervalValue & getInterval()
AddressValue & getAddrs()
const SVFStmtList & getSVFStmts() const
Definition ICFGNode.h:116
s64_t getIntNumeral() const
bool is_numeral() const
Return true if the IntervalValue is a number [num, num].
u32_t NodeID
Definition GeneralType.h:76

◆ handleExtAPI()

void AbsExtAPI::handleExtAPI ( const CallICFGNode * call)

Handles an external API call.

Parameters
callPointer to the call ICFG node.

Definition at line 337 of file AbsExtAPI.cpp.

338{
339 const FunObjVar *fun = call->getCalledFunction();
340 assert(fun && "FunObjVar* is nullptr");
341 ExtAPIType extType = UNCLASSIFIED;
342 // get type of mem api
343 for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(fun))
344 {
345 if (annotation.find("MEMCPY") != std::string::npos)
346 extType = MEMCPY;
347 if (annotation.find("MEMSET") != std::string::npos)
348 extType = MEMSET;
349 if (annotation.find("STRCPY") != std::string::npos)
350 extType = STRCPY;
351 if (annotation.find("STRCAT") != std::string::npos)
352 extType = STRCAT;
353 }
354 if (extType == UNCLASSIFIED)
355 {
356 if (func_map.find(fun->getName()) != func_map.end())
357 {
358 func_map[fun->getName()](call);
359 }
360 else
361 {
362 const SVFVar* ret = call->getRetICFGNode()->getActualRet();
363 if (ret && !ret->getType()->isPointerTy())
364 {
365 ae->updateAbsValue(ret, IntervalValue(), call);
366 }
367 }
368 }
369 // 1. memcpy functions like memcpy_chk, strncpy, annotate("MEMCPY"), annotate("BUF_CHECK:Arg0, Arg2"), annotate("BUF_CHECK:Arg1, Arg2")
370 else if (extType == MEMCPY)
371 {
372 IntervalValue len = ae->getAbsValue(call->getArgument(2), call).getInterval();
373 handleMemcpy(call->getArgument(0), call->getArgument(1), len, 0, call);
374 }
375 else if (extType == MEMSET)
376 {
377 IntervalValue len = ae->getAbsValue(call->getArgument(2), call).getInterval();
378 IntervalValue elem = ae->getAbsValue(call->getArgument(1), call).getInterval();
379 handleMemset(call->getArgument(0), elem, len, call);
380 }
381 else if (extType == STRCPY)
382 {
383 handleStrcpy(call);
384 }
385 else if (extType == STRCAT)
386 {
387 // Both strcat and strncat are annotated as STRCAT.
388 // Distinguish by name: strncat/wcsncat contain "ncat".
389 const std::string& name = fun->getName();
390 if (name.find("ncat") != std::string::npos)
391 handleStrncat(call);
392 else
393 handleStrcat(call);
394 }
395 else
396 {
397
398 }
399 return;
400}
const char *const name
Definition cJSON.h:264
void handleMemcpy(const ValVar *dst, const ValVar *src, const IntervalValue &len, u32_t start_idx, const ICFGNode *node)
Core memcpy: copy len bytes from src to dst starting at dst[start_idx].
void handleStrncat(const CallICFGNode *call)
void handleMemset(const ValVar *dst, const IntervalValue &elem, const IntervalValue &len, const ICFGNode *node)
ExtAPIType
Enumeration of external API types.
Definition AbsExtAPI.h:55
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:135
const ValVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition ICFGNode.h:483
const FunObjVar * getCalledFunction() const
Definition ICFGNode.h:501
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:440
static ExtAPI * getExtAPI()
Definition ExtAPI.cpp:43
const SVFVar * getActualRet() const
Return actual return parameter.
Definition ICFGNode.h:625
virtual const std::string & getName() const
Definition SVFValue.h:184

◆ handleMemcpy()

void AbsExtAPI::handleMemcpy ( const ValVar * dst,
const ValVar * src,
const IntervalValue & len,
u32_t start_idx,
const ICFGNode * node )

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

Definition at line 540 of file AbsExtAPI.cpp.

543{
544 AbstractState& as = getAbsState(node);
545
546 u32_t elemSize = getElementSize(dst);
548 u32_t range_val = size / elemSize;
549
550 for (u32_t index = 0; index < range_val; index++)
551 {
552 AbstractValue expr_src =
553 ae->getGepObjAddrs(src, IntervalValue(index));
554 AbstractValue expr_dst =
555 ae->getGepObjAddrs(dst, IntervalValue(index + start_idx));
556 for (const auto &dstAddr: expr_dst.getAddrs())
557 {
558 for (const auto &srcAddr: expr_src.getAddrs())
559 {
560 u32_t objId = as.getIDFromAddr(srcAddr);
561 if (as.inAddrToValTable(objId) || as.inAddrToAddrsTable(objId))
562 {
563 as.store(dstAddr, as.load(srcAddr));
564 }
565 }
566 }
567 }
568}
static u32_t getBoundedMinimumByteCount(const IntervalValue &len)
Return the lower bound of len, capped by the field limit.
void store(u32_t addr, const AbstractValue &val)
virtual bool inAddrToValTable(u32_t id) const
whether the memory address stores abstract value
bool inAddrToAddrsTable(u32_t id) const
whether the memory address stores memory addresses

◆ handleMemset()

void AbsExtAPI::handleMemset ( const ValVar * dst,
const IntervalValue & elem,
const IntervalValue & len,
const ICFGNode * node )

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 575 of file AbsExtAPI.cpp.

577{
578 AbstractState& as = getAbsState(node);
579
580 u32_t elemSize = 1;
581 if (dst->getType()->isArrayTy())
582 {
584 ->getTypeOfElement()->getByteSize();
585 }
586 else if (dst->getType()->isPointerTy())
587 {
588 elemSize = 1;
589 }
590 else
591 {
592 assert(false && "unsupported type for element size");
593 }
595 u32_t range_val = size / elemSize;
596
597 for (u32_t index = 0; index < range_val; index++)
598 {
599 AbstractValue lhs_gep = ae->getGepObjAddrs(dst, IntervalValue(index));
600 for (const auto &addr: lhs_gep.getAddrs())
601 {
602 u32_t objId = as.getIDFromAddr(addr);
603 if (as.inAddrToValTable(objId))
604 {
605 AbstractValue tmp = as.load(addr);
606 tmp.join_with(elem);
607 as.store(addr, tmp);
608 }
609 else
610 {
611 as.store(addr, elem);
612 }
613 }
614 }
615}

◆ 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 517 of file AbsExtAPI.cpp.

518{
519 const ValVar* dst = call->getArgument(0);
520 const ValVar* src = call->getArgument(1);
521 IntervalValue dstLen = getStrlen(dst, call);
522 IntervalValue srcLen = getStrlen(src, call);
523 assert(isValidLength(dstLen) && "getStrlen must return a bounded length");
524 handleMemcpy(dst, src, srcLen, dstLen.lb().getIntNumeral(), call);
525}
IntervalValue getStrlen(const ValVar *strValue, const ICFGNode *node)
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 506 of file AbsExtAPI.cpp.

507{
508 const ValVar* dst = call->getArgument(0);
509 const ValVar* src = call->getArgument(1);
510 IntervalValue srcLen = getStrlen(src, call);
511 assert(isValidLength(srcLen) && "getStrlen must return a bounded length");
512 handleMemcpy(dst, src, srcLen, 0, call);
513}

◆ 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 529 of file AbsExtAPI.cpp.

530{
531 const ValVar* dst = call->getArgument(0);
532 const ValVar* src = call->getArgument(1);
533 IntervalValue n = ae->getAbsValue(call->getArgument(2), call).getInterval();
534 IntervalValue dstLen = getStrlen(dst, call);
535 assert(isValidLength(dstLen) && "getStrlen must return a bounded length");
536 handleMemcpy(dst, src, n, dstLen.lb().getIntNumeral(), call);
537}
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 assert(callNode->arg_size() >= 1 && "external function expects one argument"); \
48 const SVFVar* argVar = callNode->getArgument(0); \
49 const AbstractValue& argVal = ae->getAbsValue(argVar, callNode); \
50 IntervalValue result = IntervalValue::top(); \
51 if (argVal.isInterval() && argVal.getInterval().is_numeral()) { \
52 u32_t rhs = argVal.getInterval().lb().getIntNumeral(); \
53 result = IntervalValue(FUNC_NAME(rhs)); \
54 } \
55 const SVFVar* retVar = callNode->getRetICFGNode()->getActualRet(); \
56 ae->updateAbsValue(retVar, result, callNode); \
57 }; \
58 func_map[#FUNC_NAME] = sse_##FUNC_NAME;
59
71 SSE_FUNC_PROCESS(llvm.sin.f64, sin);
72 SSE_FUNC_PROCESS(llvm.cos.f64, cos);
73 SSE_FUNC_PROCESS(llvm.tan.f64, tan);
74 SSE_FUNC_PROCESS(llvm.log.f64, log);
75 SSE_FUNC_PROCESS(sinh, sinh);
76 SSE_FUNC_PROCESS(cosh, cosh);
77 SSE_FUNC_PROCESS(tanh, tanh);
78
79 auto sse_svf_assert = [this](const CallICFGNode* callNode)
80 {
81 checkpoints.erase(callNode);
82 const AbstractValue& arg0Val = ae->getAbsValue(callNode->getArgument(0), callNode);
83 if (arg0Val.getInterval().equals(IntervalValue(1, 1)))
84 {
85 SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n");
86 }
87 else
88 {
89 SVFUtil::errs() << SVFUtil::errMsg("Assertion failure, this svf_assert cannot be verified!!\n") << callNode->toString() << "\n";
90 assert(false);
91 }
92 return;
93 };
94 func_map["svf_assert"] = sse_svf_assert;
95
96 auto svf_assert_eq = [this](const CallICFGNode* callNode)
97 {
98 const AbstractValue& arg0Val = ae->getAbsValue(callNode->getArgument(0), callNode);
99 const AbstractValue& arg1Val = ae->getAbsValue(callNode->getArgument(1), callNode);
100 if (arg0Val.getInterval().equals(arg1Val.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 assert(callNode->arg_size() >= 2 && "svf_print expects two arguments");
116 std::string text = strRead(callNode->getArgument(1), callNode);
117 IntervalValue itv = ae->getAbsValue(callNode->getArgument(0), callNode).getInterval();
118 std::cout << "Text: " << text <<", Value: " << callNode->getArgument(0)->toString()
119 << ", PrintVal: " << itv.toString() << ", Loc:" << callNode->getSourceLoc() << std::endl;
120 return;
121 };
122 func_map["svf_print"] = svf_print;
123
124 auto svf_set_value = [&](const CallICFGNode* callNode)
125 {
126 assert(callNode->arg_size() >= 3 && "set_value expects three arguments");
127 AbstractState&as = getAbsState(callNode);
128 const AbstractValue& lbVal = ae->getAbsValue(callNode->getArgument(1), callNode);
129 const AbstractValue& ubVal = ae->getAbsValue(callNode->getArgument(2), callNode);
130 assert(lbVal.getInterval().is_numeral() && ubVal.getInterval().is_numeral());
131 AbstractValue num;
132 num.getInterval().set_to_top();
133 num.getInterval().meet_with(IntervalValue(lbVal.getInterval().lb(), ubVal.getInterval().ub()));
134 ae->updateAbsValue(callNode->getArgument(0), num, callNode);
135 const ICFGNode* node = SVFUtil::cast<ValVar>(callNode->getArgument(0))->getICFGNode();
136 for (const SVFStmt* stmt: node->getSVFStmts())
137 {
138 if (SVFUtil::isa<LoadStmt>(stmt))
139 {
140 const LoadStmt* load = SVFUtil::cast<LoadStmt>(stmt);
141 const AbstractValue& ptrVal = ae->getAbsValue(load->getRHSVar(), callNode);
142 for (auto addr : ptrVal.getAddrs())
143 as.store(addr, num);
144 }
145 }
146 return;
147 };
148 func_map["set_value"] = svf_set_value;
149
150 auto sse_fread = [&](const CallICFGNode *callNode)
151 {
152 assert(callNode->arg_size() >= 3 && "fread expects at least three arguments");
153 IntervalValue block_count = ae->getAbsValue(callNode->getArgument(2), callNode).getInterval();
154 IntervalValue block_size = ae->getAbsValue(callNode->getArgument(1), callNode).getInterval();
155 IntervalValue block_byte = block_count * block_size;
156 (void)block_byte;
157 };
158 func_map["fread"] = sse_fread;
159
160 auto sse_sprintf = [&](const CallICFGNode *callNode)
161 {
162 // printf is difficult to predict since it has no byte size arguments
163 };
164
165 auto sse_snprintf = [&](const CallICFGNode *callNode)
166 {
167 assert(callNode->arg_size() >= 2 &&
168 "formatted-output function expects at least two arguments");
169 u32_t elemSize = 1;
170 if (callNode->arg_size() > 2 &&
171 callNode->getArgument(2)->getType()->isArrayTy())
172 {
174 callNode->getArgument(2)->getType())
175 ->getTypeOfElement()->getByteSize();
176 }
177 IntervalValue size = ae->getAbsValue(callNode->getArgument(1), callNode).getInterval()
178 * IntervalValue(elemSize) - IntervalValue(1);
179 (void)size;
180 };
181 func_map["__snprintf_chk"] = sse_snprintf;
182 func_map["__vsprintf_chk"] = sse_sprintf;
183 func_map["__sprintf_chk"] = sse_sprintf;
184 func_map["snprintf"] = sse_snprintf;
185 func_map["sprintf"] = sse_sprintf;
186 func_map["vsprintf"] = sse_sprintf;
187 func_map["vsnprintf"] = sse_snprintf;
188 func_map["__vsnprintf_chk"] = sse_snprintf;
189 func_map["swprintf"] = sse_snprintf;
190 func_map["_snwprintf"] = sse_snprintf;
191
192
193 auto sse_itoa = [&](const CallICFGNode* callNode)
194 {
195 assert(callNode->arg_size() >= 3 && "itoa expects three arguments");
196 u32_t num = (u32_t) ae->getAbsValue(callNode->getArgument(0), callNode).getInterval().getNumeral();
197 std::string snum = std::to_string(num);
198 (void)snum;
199 };
200 func_map["itoa"] = sse_itoa;
201
202
203 auto sse_strlen = [&](const CallICFGNode *callNode)
204 {
205 assert(callNode->arg_size() >= 1 && "strlen expects one argument");
206 const SVFVar* retVar = callNode->getRetICFGNode()->getActualRet();
207 IntervalValue byteLen = getStrlen(callNode->getArgument(0), callNode);
208 u32_t elemSize = getElementSize(callNode->getArgument(0));
209 if (byteLen.is_numeral() && elemSize > 1)
210 ae->updateAbsValue(retVar, IntervalValue(byteLen.getIntNumeral() / (s64_t)elemSize), callNode);
211 else
212 ae->updateAbsValue(retVar, byteLen, callNode);
213 };
214 func_map["strlen"] = sse_strlen;
215 func_map["wcslen"] = sse_strlen;
216
217 auto sse_recv = [&](const CallICFGNode *callNode)
218 {
219 assert(callNode->arg_size() >= 4 && "recv expects four arguments");
220 IntervalValue len = ae->getAbsValue(callNode->getArgument(2), callNode).getInterval() - IntervalValue(1);
221 const SVFVar* retVar = callNode->getRetICFGNode()->getActualRet();
222 ae->updateAbsValue(retVar, len, callNode);
223 };
224 func_map["recv"] = sse_recv;
225 func_map["__recv"] = sse_recv;
226
227 auto sse_free = [&](const CallICFGNode *callNode)
228 {
229 assert(callNode->arg_size() >= 1 && "free expects one argument");
230 AbstractState& as = getAbsState(callNode);
231 const AbstractValue& ptrVal = ae->getAbsValue(callNode->getArgument(0), callNode);
232 for (auto addr: ptrVal.getAddrs())
233 {
235 as.addToFreedAddrs(addr);
236 }
237 };
238 // Add all free-related functions to func_map
239 std::vector<std::string> freeFunctions =
240 {
241 "VOS_MemFree", "cfree", "free", "free_all_mem", "freeaddrinfo",
242 "gcry_mpi_release", "gcry_sexp_release", "globfree", "nhfree",
243 "obstack_free", "safe_cfree", "safe_free", "safefree", "safexfree",
244 "sm_free", "vim_free", "xfree", "SSL_CTX_free", "SSL_free", "XFree"
245 };
246
247 for (const auto& name : freeFunctions)
248 {
249 func_map[name] = sse_free;
250 }
251};
#define SSE_FUNC_PROCESS(LLVM_NAME,FUNC_NAME)
std::string strRead(const ValVar *rhs, const ICFGNode *node)
Reads a string from the abstract state.
static bool isNullOrBlackHoleAddr(u32_t addr)
Whether addr has no concrete backing memory object.
void addToFreedAddrs(NodeID addr)
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
const BoundedInt & ub() const
Return the upper bound.
const std::string toString() const
void set_to_top()
Set current IntervalValue as top.
bool equals(const IntervalValue &other) const
Equality comparison.
const ValVar * getRHSVar() const
int iscntrl(int c)
Definition extapi.c:1026
int isdigit(int c)
Definition extapi.c:1031
int isgraph(int c)
Definition extapi.c:1036
int isspace(char c)
Definition extapi.c:1056
int isprint(int c)
Definition extapi.c:1046
int ispunct(int argument)
Definition extapi.c:1051
int isblank(int character)
Definition extapi.c:1021
int isalnum(int character)
Definition extapi.c:1011
int isupper(int c)
Definition extapi.c:1061
int isxdigit(int c)
Definition extapi.c:1066
int isalpha(int character)
Definition extapi.c:1016
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:75
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
Definition Casting.h:360

◆ 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 424 of file AbsExtAPI.cpp.

425{
426 return !len.isBottom() && !len.lb().is_minus_infinity();
427}
bool is_minus_infinity() const
bool isBottom() const

◆ strRead()

std::string AbsExtAPI::strRead ( const ValVar * rhs,
const ICFGNode * node )

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 309 of file AbsExtAPI.cpp.

310{
311 AbstractState& as = getAbsState(node);
312 std::string str0;
313
315 {
316 AbstractValue expr0 =
317 ae->getGepObjAddrs(rhs, IntervalValue(index));
318
319 AbstractValue val;
320 for (const auto &addr: expr0.getAddrs())
321 {
322 val.join_with(as.load(addr));
323 }
324 if (!val.getInterval().is_numeral())
325 {
326 break;
327 }
328 if ((char) val.getInterval().getIntNumeral() == '\0')
329 {
330 break;
331 }
332 str0.push_back((char) val.getInterval().getIntNumeral());
333 }
334 return str0;
335}

◆ AbstractInterpretation

friend class AbstractInterpretation
friend

Definition at line 61 of file AbsExtAPI.h.

Member Data Documentation

◆ ae

AbstractInterpretation* SVF::AbsExtAPI::ae
protected

Owning AbstractInterpretation; provides state access.

Definition at line 132 of file AbsExtAPI.h.

◆ checkpoints

Set<const CallICFGNode*> SVF::AbsExtAPI::checkpoints

Definition at line 129 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 135 of file AbsExtAPI.h.

◆ icfg

ICFG* SVF::AbsExtAPI::icfg
protected

Pointer to the interprocedural control flow graph.

Definition at line 134 of file AbsExtAPI.h.

◆ svfir

SVFIR* SVF::AbsExtAPI::svfir
protected

Pointer to the SVF intermediate representation.

Definition at line 133 of file AbsExtAPI.h.


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