Static Value-Flow Analysis
Loading...
Searching...
No Matches
AEDetector.cpp
Go to the documentation of this file.
1//===- AEDetector.cpp -- Vulnerability Detectors---------------------------------//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22
23
24//
25// Created on: May 1, 2025
26// Author: Xiao Cheng, Jiawei Wang, Mingxiu Wang
27//
28
30#include <AE/Svfexe/AbsExtAPI.h>
33#include <algorithm>
34
35using namespace SVF;
47{
49 if (!SVFUtil::isa<CallICFGNode>(node))
50 {
51 // Handle non-call nodes by analyzing GEP instructions
52 for (const SVFStmt* stmt : node->getSVFStmts())
53 {
54 if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
55 {
56 SVFIR* svfir = PAG::getPAG();
57
58 // Update the GEP object offset from its base
59 const AbstractValue& lhsVal = ae.getAbsValue(gep->getLHSVar(), node);
60 const AbstractValue& rhsVal = ae.getAbsValue(gep->getRHSVar(), node);
61 updateGepObjOffsetFromBase(node, lhsVal.getAddrs(), rhsVal.getAddrs(),
62 ae.getGepByteOffset(gep));
63
64 const AddressValue& objAddrs = rhsVal.getAddrs();
65 for (const auto& addr : objAddrs)
66 {
67 NodeID objId = ae.getAbsState(node).getIDFromAddr(addr);
68 u32_t size = 0;
69 // like `int arr[10]` which has constant size before runtime
71 {
72 size = svfir->getBaseObject(objId)->getByteSizeOfObj();
73 }
74 else
75 {
76 // like `int len = ***; int arr[len]`, whose size can only be known in runtime
78 for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
79 {
80 if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
81 {
82 size = ae.getAllocaInstByteSize(addrStmt);
83 }
84 }
85 }
86
87 // Calculate access offset and check for potential overflow
89 if (accessOffset.ub().getIntNumeral() >= size)
90 {
91 AEException bug(stmt->toString());
92 addBugToReporter(bug, stmt->getICFGNode());
93 }
94 }
95 }
96 }
97 }
98 else
99 {
100 // Handle call nodes by checking for external API calls
101 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
102 if (SVFUtil::isExtCall(callNode->getCalledFunction()))
103 {
105 }
106 }
107}
108
109
118{
119 // get function name
120 std::string funcName = callNode->getCalledFunction()->getName();
122 if (funcName == "SAFE_BUFACCESS")
123 {
124 ae.getUtils()->checkpoints.erase(callNode);
125 if (callNode->arg_size() < 2)
126 return;
127 IntervalValue val = ae.getAbsValue(callNode->getArgument(1), callNode).getInterval();
128 if (val.isBottom())
129 {
130 val = IntervalValue(0);
131 assert(false && "SAFE_BUFACCESS size is bottom");
132 }
133 const ValVar* arg0Val = callNode->getArgument(0);
135 if (isSafe)
136 {
137 SVFUtil::outs() << SVFUtil::sucMsg("success: expected safe buffer access at SAFE_BUFACCESS")
138 << " — " << callNode->toString() << "\n";
139 return;
140 }
141 else
142 {
143 SVFUtil::outs() << SVFUtil::errMsg("failure: unexpected buffer overflow at SAFE_BUFACCESS")
144 << " — Position: " << callNode->getSourceLoc() << "\n";
145 assert(false);
146 }
147 }
148 else if (funcName == "UNSAFE_BUFACCESS")
149 {
150 ae.getUtils()->checkpoints.erase(callNode);
151 if (callNode->arg_size() < 2) return;
152 IntervalValue val = ae.getAbsValue(callNode->getArgument(1), callNode).getInterval();
153 if (val.isBottom())
154 {
155 assert(false && "UNSAFE_BUFACCESS size is bottom");
156 }
157 const ValVar* arg0Val = callNode->getArgument(0);
159 if (!isSafe)
160 {
161 SVFUtil::outs() << SVFUtil::sucMsg("success: expected buffer overflow at UNSAFE_BUFACCESS")
162 << " — " << callNode->toString() << "\n";
163 return;
164 }
165 else
166 {
167 SVFUtil::outs() << SVFUtil::errMsg("failure: buffer overflow expected at UNSAFE_BUFACCESS, but none detected")
168 << " — Position: " << callNode->getSourceLoc() << "\n";
169 assert(false);
170 }
171 }
172}
173
181{
182 extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
183 extAPIBufOverflowCheckRules["llvm_memcpy_p0_p0_i64"] = {{0, 2}, {1, 2}};
184 extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
185 extAPIBufOverflowCheckRules["llvm_memcpy"] = {{0, 2}, {1, 2}};
186 extAPIBufOverflowCheckRules["llvm_memmove"] = {{0, 2}, {1, 2}};
187 extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
188 extAPIBufOverflowCheckRules["llvm_memmove_p0_p0_i64"] = {{0, 2}, {1, 2}};
189 extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
190 extAPIBufOverflowCheckRules["__memcpy_chk"] = {{0, 2}, {1, 2}};
191 extAPIBufOverflowCheckRules["memmove"] = {{0, 2}, {1, 2}};
192 extAPIBufOverflowCheckRules["bcopy"] = {{0, 2}, {1, 2}};
193 extAPIBufOverflowCheckRules["memccpy"] = {{0, 3}, {1, 3}};
194 extAPIBufOverflowCheckRules["__memmove_chk"] = {{0, 2}, {1, 2}};
195 extAPIBufOverflowCheckRules["llvm_memset"] = {{0, 2}};
196 extAPIBufOverflowCheckRules["llvm_memset_p0i8_i32"] = {{0, 2}};
197 extAPIBufOverflowCheckRules["llvm_memset_p0i8_i64"] = {{0, 2}};
198 extAPIBufOverflowCheckRules["llvm_memset_p0_i64"] = {{0, 2}};
199 extAPIBufOverflowCheckRules["__memset_chk"] = {{0, 2}};
200 extAPIBufOverflowCheckRules["wmemset"] = {{0, 2}};
201 extAPIBufOverflowCheckRules["strncpy"] = {{0, 2}, {1, 2}};
202 extAPIBufOverflowCheckRules["iconv"] = {{1, 2}, {3, 4}};
203}
204
214{
215 assert(call->getCalledFunction() && "FunObjVar* is nullptr");
217
219
220 // Determine the type of external memory API
221 for (const std::string &annotation : ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
222 {
223 if (annotation.find("MEMCPY") != std::string::npos)
225 if (annotation.find("MEMSET") != std::string::npos)
227 if (annotation.find("STRCPY") != std::string::npos)
229 if (annotation.find("STRCAT") != std::string::npos)
231 }
232
233 // Apply buffer overflow checks based on the determined API type
235 {
236 if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
237 {
238 SVFUtil::errs() << "Warning: " << call->getCalledFunction()->getName() << " is not in the rules, please implement it\n";
239 return;
240 }
241 std::vector<std::pair<u32_t, u32_t>> args =
243 for (auto arg : args)
244 {
245 IntervalValue offset = ae.getAbsValue(call->getArgument(arg.second), call).getInterval() - IntervalValue(1);
246 const ValVar* argVar = call->getArgument(arg.first);
248 {
249 AEException bug(call->toString());
250 addBugToReporter(bug, call);
251 }
252 }
253 }
254 else if (extType == AbsExtAPI::MEMSET)
255 {
256 if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
257 {
258 SVFUtil::errs() << "Warning: " << call->getCalledFunction()->getName() << " is not in the rules, please implement it\n";
259 return;
260 }
261 std::vector<std::pair<u32_t, u32_t>> args =
263 for (auto arg : args)
264 {
265 IntervalValue offset = ae.getAbsValue(call->getArgument(arg.second), call).getInterval() - IntervalValue(1);
266 const ValVar* argVar = call->getArgument(arg.first);
268 {
269 AEException bug(call->toString());
270 addBugToReporter(bug, call);
271 }
272 }
273 }
274 else if (extType == AbsExtAPI::STRCPY)
275 {
276 if (!detectStrcpy(call))
277 {
278 AEException bug(call->toString());
279 addBugToReporter(bug, call);
280 }
281 }
282 else if (extType == AbsExtAPI::STRCAT)
283 {
284 if (!detectStrcat(call))
285 {
286 AEException bug(call->toString());
287 addBugToReporter(bug, call);
288 }
289 }
290 else
291 {
292 // Handle other cases
293 }
294}
295
307{
308 SVFIR* svfir = PAG::getPAG();
310 auto obj = svfir->getSVFVar(objId);
311
312 if (SVFUtil::isa<BaseObjVar>(obj))
313 {
314 return ae.getGepByteOffset(gep);
315 }
316 else if (SVFUtil::isa<GepObjVar>(obj))
317 {
318 return getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(obj)) + ae.getGepByteOffset(gep);
319 }
320 else
321 {
322 assert(SVFUtil::isa<DummyObjVar>(obj) && "Unknown object type");
323 return IntervalValue::top();
324 }
325}
326
338{
339 SVFIR* svfir = PAG::getPAG();
341 const AbstractState& as = ae.getAbsState(node);
342
343 for (const auto& objAddr : objAddrs)
344 {
346 auto obj = svfir->getSVFVar(objId);
347
348 if (SVFUtil::isa<BaseObjVar>(obj))
349 {
350 // if the object is a BaseObjVar, add the offset directly
351 // like llvm bc `arr = alloc i8 12; p = gep arr, 4`
352 // we write key value pair {gep, 4}
353 for (const auto& gepAddr : gepAddrs)
354 {
355 NodeID gepObj = as.getIDFromAddr(gepAddr);
356 if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast<GepObjVar>(svfir->getSVFVar(gepObj)))
357 {
359 }
360 else
361 {
363 "GEP object is neither a GepObjVar nor an address without a backing object");
364 }
365 }
366 }
367 else if (SVFUtil::isa<GepObjVar>(obj))
368 {
369 // if the object is a GepObjVar, add the offset from the base object
370 // like llvm bc `arr = alloc i8 12; p = gep arr, 4; q = gep p, 6`
371 // we retreive {p, 4} and write {q, 4+6}
372 const GepObjVar* objVar = SVFUtil::cast<GepObjVar>(obj);
373 for (const auto& gepAddr : gepAddrs)
374 {
375 NodeID gepObj = as.getIDFromAddr(gepAddr);
376 if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast<GepObjVar>(svfir->getSVFVar(gepObj)))
377 {
379 {
385 }
386 else
387 {
388 assert(false &&
389 "GEP RHS object has no offset from base");
390 }
391 }
392 else
393 {
395 "GEP object is neither a GepObjVar nor an address without a backing object");
396 }
397 }
398 }
399 }
400}
401
413{
414 const ValVar* arg0Val = call->getArgument(0);
415 const ValVar* arg1Val = call->getArgument(1);
417 IntervalValue strLen = ae.getUtils()->getStrlen(arg1Val, call);
418 return canSafelyAccessMemory(arg0Val, strLen, call);
419}
420
422{
424 const std::vector<std::string> strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"};
425 const std::vector<std::string> strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"};
426
427 if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end())
428 {
429 const ValVar* arg0Val = call->getArgument(0);
430 const ValVar* arg1Val = call->getArgument(1);
431 IntervalValue strLen0 = ae.getUtils()->getStrlen(arg0Val, call);
432 IntervalValue strLen1 = ae.getUtils()->getStrlen(arg1Val, call);
435 }
436 else if (std::find(strncatGroup.begin(), strncatGroup.end(), call->getCalledFunction()->getName()) != strncatGroup.end())
437 {
438 const ValVar* arg0Val = call->getArgument(0);
439 const ValVar* arg2Val = call->getArgument(2);
440 IntervalValue arg2Num = ae.getAbsValue(arg2Val, call).getInterval();
441 IntervalValue strLen0 = ae.getUtils()->getStrlen(arg0Val, call);
444 }
445 else
446 {
447 assert(false && "Unknown strcat function, please add it to strcatGroup or strncatGroup");
448 abort();
449 }
450}
451
464{
465 SVFIR* svfir = PAG::getPAG();
467
468 AbstractValue ptrVal = ae.getAbsValue(value, node);
469 if (!ptrVal.isAddr())
470 {
472 ae.updateAbsValue(value, ptrVal, node);
473 }
474
475 const AddressValue& addresses = ptrVal.getAddrs();
476 if (std::any_of(addresses.begin(), addresses.end(),
478 return false;
479
480 for (const auto& addr : addresses)
481 {
482 NodeID objId = ae.getAbsState(node).getIDFromAddr(addr);
483 u32_t size = 0;
484 // if the object is a constant size object, get the size directly
486 {
487 size = svfir->getBaseObject(objId)->getByteSizeOfObj();
488 }
489 else
490 {
491 // if the object is not a constant size object, get the size from the addrStmt
492 const ICFGNode* addrNode = svfir->getBaseObject(objId)->getICFGNode();
493 for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
494 {
495 if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
496 {
497 size = ae.getAllocaInstByteSize(addrStmt);
498 }
499 }
500 }
501
503 // if the object is a GepObjVar, get the offset from the base object
504 if (SVFUtil::isa<GepObjVar>(svfir->getSVFVar(objId)))
505 {
506 offset = getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(svfir->getSVFVar(objId))) + len;
507 }
508 else if (SVFUtil::isa<BaseObjVar>(svfir->getSVFVar(objId)))
509 {
510 // if the object is a BaseObjVar, get the offset directly
511 offset = len;
512 }
513
514 // if the offset is greater than the size, return false
515 if (offset.ub().getIntNumeral() >= size)
516 {
517 return false;
518 }
519 }
520 return true;
521}
522
524{
525 if (SVFUtil::isa<CallICFGNode>(node))
526 {
527 // external API like memset(*dst, elem, sz)
528 // we check if it's external api and check the corrisponding index
529 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
530 if (SVFUtil::isExtCall(callNode->getCalledFunction()))
531 {
533 }
534 }
535 else
536 {
537 for (const auto& stmt: node->getSVFStmts())
538 {
539 if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
540 {
541 // like llvm bitcode `p = gep p, idx`
542 // we check rhs p's all address are valid mem
543 const ValVar* rhs = gep->getRHSVar();
544 if (!canSafelyDerefPtr(rhs, node))
545 {
546 AEException bug(stmt->toString());
547 addBugToReporter(bug, stmt->getICFGNode());
548 }
549 }
550 else if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
551 {
552 // like llvm bitcode `p = load q`
553 // we check lhs p's all address are valid mem
554 const ValVar* lhs = load->getLHSVar();
555 if (!canSafelyDerefPtr(lhs, node))
556 {
557 AEException bug(stmt->toString());
558 addBugToReporter(bug, stmt->getICFGNode());
559 }
560 }
561 }
562 }
563}
564
565
567{
568 std::string funcName = callNode->getCalledFunction()->getName();
570 if (funcName == "UNSAFE_LOAD")
571 {
572 // void UNSAFE_LOAD(void* ptr);
573 ae.getUtils()->checkpoints.erase(callNode);
574 if (callNode->arg_size() < 1)
575 return;
576
577 const ValVar* arg0Val = callNode->getArgument(0);
578 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)
580 SVFUtil::outs() << "[UNSAFE_LOAD] node=" << callNode->getId()
581 << " arg0=" << arg0Val->getId() << " isSafe=" << isSafe
582 << "\n";
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);
599 ae.getUtils()->checkpoints.erase(callNode);
600 if (callNode->arg_size() < 1) return;
601 const ValVar* arg0Val = callNode->getArgument(0);
602 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols
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}
618
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 ValVar* argVal = call->getArgument(arg);
669 if (argVal && !canSafelyDerefPtr(argVal, call))
670 {
671 AEException bug(call->toString());
672 addBugToReporter(bug, call);
673 }
674 }
675}
676
677
679{
681 const AbstractValue& AbsVal = ae.getAbsValue(value, node);
682 if (isUninit(AbsVal)) return false;
683 if (!AbsVal.isAddr()) return true;
684 for (const auto &addr: AbsVal.getAddrs())
685 {
686 // Unknown, null, and freed addresses cannot be safely dereferenced.
688 ae.getAbsState(node).isFreedMem(addr))
689 return false;
690 }
691 return true;
692}
#define BlackHoleObjAddr
buffer offset
Definition cJSON.cpp:1113
Exception class for handling errors in Abstract Execution.
Definition AEDetector.h:112
ExtAPIType
Enumeration of external API types.
Definition AbsExtAPI.h:55
static AbstractInterpretation & getAEInstance()
u32_t getIDFromAddr(u32_t addr) const
Return the internal index if addr is an address otherwise return the value of idx.
static bool isNullOrBlackHoleAddr(u32_t addr)
Whether addr has no concrete backing memory object.
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.
void addToGepObjOffsetFromBase(const GepObjVar *obj, const IntervalValue &offset)
Adds an offset to a GEP object.
Definition AEDetector.h:197
void detect(const ICFGNode *) override
Detect buffer overflow issues within a node.
Map< std::string, std::vector< std::pair< u32_t, u32_t > > > extAPIBufOverflowCheckRules
Rules for checking buffer overflows in external APIs.
Definition AEDetector.h:326
IntervalValue getAccessOffset(NodeID objId, const GepStmt *gep)
Retrieves the access offset for a given object and GEP statement.
void updateGepObjOffsetFromBase(const ICFGNode *node, AddressValue gepAddrs, AddressValue objAddrs, IntervalValue offset)
Updates the offset of a GEP object from its base.
void detectExtAPI(const CallICFGNode *call)
Handles external API calls related to buffer overflow detection.
bool canSafelyAccessMemory(const ValVar *value, const IntervalValue &len, const ICFGNode *node)
Checks if memory can be safely accessed.
IntervalValue getGepObjOffsetFromBase(const GepObjVar *obj) const
Retrieves the offset of a GEP object from its base.
Definition AEDetector.h:217
bool detectStrcpy(const CallICFGNode *call)
Detects buffer overflow in 'strcpy' function calls.
void handleStubFunctions(const CallICFGNode *) override
Handles external API calls related to buffer overflow detection.
bool hasGepObjOffsetFromBase(const GepObjVar *obj) const
Checks if a GEP object has an associated offset.
Definition AEDetector.h:207
void initExtAPIBufOverflowCheckRules()
Initializes external API buffer overflow check rules.
bool detectStrcat(const CallICFGNode *call)
Detects buffer overflow in 'strcat' function calls.
void addBugToReporter(const AEException &e, const ICFGNode *node)
Adds a bug to the reporter based on an exception.
Definition AEDetector.h:242
const std::string toString() const override
Definition ICFG.cpp:129
const ValVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition ICFGNode.h:483
const FunObjVar * getCalledFunction() const
Definition ICFGNode.h:501
u32_t arg_size() const
Definition ICFGNode.h:488
static ExtAPI * getExtAPI()
Definition ExtAPI.cpp:43
const std::vector< std::string > & getExtFuncAnnotations(const FunObjVar *fun)
Definition ExtAPI.cpp:232
const SVFStmtList & getSVFStmts() const
Definition ICFGNode.h:116
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
bool canSafelyDerefPtr(const ValVar *ptr, const ICFGNode *node)
bool isUninit(AbstractValue v)
Checks if an Abstract Value is uninitialized.
Definition AEDetector.h:365
void handleStubFunctions(const CallICFGNode *call) override
Handles external API calls related to nullptr dereferences.
void detect(const ICFGNode *node) override
Detects nullptr dereferences issues within a node.
void addBugToReporter(const AEException &e, const ICFGNode *node)
Adds a bug to the reporter based on an exception.
Definition AEDetector.h:377
void detectExtAPI(const CallICFGNode *call)
Handle external API calls related to nullptr dereferences.
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:498
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:135
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:120
NodeID getId() const
Get ID.
Definition SVFValue.h:158
virtual const std::string & getName() const
Definition SVFValue.h:184
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:75
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
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:526
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:58
for isBitcode
Definition BasicTypes.h:70
u32_t NodeID
Definition GeneralType.h:76
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:67