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
34using namespace SVF;
46{
47 if (!SVFUtil::isa<CallICFGNode>(node))
48 {
49 // Handle non-call nodes by analyzing GEP instructions
50 for (const SVFStmt* stmt : node->getSVFStmts())
51 {
52 if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
53 {
54 SVFIR* svfir = PAG::getPAG();
55 NodeID lhs = gep->getLHSVarID();
56 NodeID rhs = gep->getRHSVarID();
57
58 // Update the GEP object offset from its base
59 updateGepObjOffsetFromBase(as, as[lhs].getAddrs(), as[rhs].getAddrs(), as.getByteOffset(gep));
60
62 AddressValue objAddrs = as[gep->getRHSVarID()].getAddrs();
63 for (const auto& addr : objAddrs)
64 {
65 NodeID objId = as.getIDFromAddr(addr);
66 u32_t size = 0;
67 // like `int arr[10]` which has constant size before runtime
69 {
70 size = svfir->getBaseObject(objId)->getByteSizeOfObj();
71 }
72 else
73 {
74 // like `int len = ***; int arr[len]`, whose size can only be known in runtime
76 for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
77 {
78 if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
79 {
80 size = as.getAllocaInstByteSize(addrStmt);
81 }
82 }
83 }
84
85 // Calculate access offset and check for potential overflow
87 if (accessOffset.ub().getIntNumeral() >= size)
88 {
89 AEException bug(stmt->toString());
90 addBugToReporter(bug, stmt->getICFGNode());
91 }
92 }
93 }
94 }
95 }
96 else
97 {
98 // Handle call nodes by checking for external API calls
99 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
100 if (SVFUtil::isExtCall(callNode->getCalledFunction()))
101 {
103 }
104 }
105}
106
107
116{
117 // get function name
118 std::string funcName = callNode->getCalledFunction()->getName();
119 if (funcName == "SAFE_BUFACCESS")
120 {
121 // void SAFE_BUFACCESS(void* data, int size);
123 if (callNode->arg_size() < 2)
124 return;
127 callNode);
128 u32_t size_id = callNode->getArgument(1)->getId();
129 IntervalValue val = as[size_id].getInterval();
130 if (val.isBottom())
131 {
132 val = IntervalValue(0);
133 assert(false && "SAFE_BUFACCESS size is bottom");
134 }
135 const SVFVar* arg0Val = callNode->getArgument(0);
137 if (isSafe)
138 {
139 SVFUtil::outs() << SVFUtil::sucMsg("success: expected safe buffer access at SAFE_BUFACCESS")
140 << " — " << callNode->toString() << "\n";
141 return;
142 }
143 else
144 {
145 SVFUtil::outs() << SVFUtil::errMsg("failure: unexpected buffer overflow at SAFE_BUFACCESS")
146 << " — Position: " << callNode->getSourceLoc() << "\n";
147 assert(false);
148 }
149 }
150 else if (funcName == "UNSAFE_BUFACCESS")
151 {
152 // void UNSAFE_BUFACCESS(void* data, int size);
154 if (callNode->arg_size() < 2) return;
156 u32_t size_id = callNode->getArgument(1)->getId();
157 IntervalValue val = as[size_id].getInterval();
158 if (val.isBottom())
159 {
160 assert(false && "UNSAFE_BUFACCESS size is bottom");
161 }
162 const SVFVar* arg0Val = callNode->getArgument(0);
164 if (!isSafe)
165 {
166 SVFUtil::outs() << SVFUtil::sucMsg("success: expected buffer overflow at UNSAFE_BUFACCESS")
167 << " — " << callNode->toString() << "\n";
168 return;
169 }
170 else
171 {
172 SVFUtil::outs() << SVFUtil::errMsg("failure: buffer overflow expected at UNSAFE_BUFACCESS, but none detected")
173 << " — Position: " << callNode->getSourceLoc() << "\n";
174 assert(false);
175 }
176 }
177}
178
186{
187 extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
188 extAPIBufOverflowCheckRules["llvm_memcpy_p0_p0_i64"] = {{0, 2}, {1, 2}};
189 extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
190 extAPIBufOverflowCheckRules["llvm_memcpy"] = {{0, 2}, {1, 2}};
191 extAPIBufOverflowCheckRules["llvm_memmove"] = {{0, 2}, {1, 2}};
192 extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
193 extAPIBufOverflowCheckRules["llvm_memmove_p0_p0_i64"] = {{0, 2}, {1, 2}};
194 extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
195 extAPIBufOverflowCheckRules["__memcpy_chk"] = {{0, 2}, {1, 2}};
196 extAPIBufOverflowCheckRules["memmove"] = {{0, 2}, {1, 2}};
197 extAPIBufOverflowCheckRules["bcopy"] = {{0, 2}, {1, 2}};
198 extAPIBufOverflowCheckRules["memccpy"] = {{0, 3}, {1, 3}};
199 extAPIBufOverflowCheckRules["__memmove_chk"] = {{0, 2}, {1, 2}};
200 extAPIBufOverflowCheckRules["llvm_memset"] = {{0, 2}};
201 extAPIBufOverflowCheckRules["llvm_memset_p0i8_i32"] = {{0, 2}};
202 extAPIBufOverflowCheckRules["llvm_memset_p0i8_i64"] = {{0, 2}};
203 extAPIBufOverflowCheckRules["llvm_memset_p0_i64"] = {{0, 2}};
204 extAPIBufOverflowCheckRules["__memset_chk"] = {{0, 2}};
205 extAPIBufOverflowCheckRules["wmemset"] = {{0, 2}};
206 extAPIBufOverflowCheckRules["strncpy"] = {{0, 2}, {1, 2}};
207 extAPIBufOverflowCheckRules["iconv"] = {{1, 2}, {3, 4}};
208}
209
220 const CallICFGNode* call)
221{
222 assert(call->getCalledFunction() && "FunObjVar* is nullptr");
223
225
226 // Determine the type of external memory API
227 for (const std::string &annotation : ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
228 {
229 if (annotation.find("MEMCPY") != std::string::npos)
231 if (annotation.find("MEMSET") != std::string::npos)
233 if (annotation.find("STRCPY") != std::string::npos)
235 if (annotation.find("STRCAT") != std::string::npos)
237 }
238
239 // Apply buffer overflow checks based on the determined API type
241 {
242 if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
243 {
244 SVFUtil::errs() << "Warning: " << call->getCalledFunction()->getName() << " is not in the rules, please implement it\n";
245 return;
246 }
247 std::vector<std::pair<u32_t, u32_t>> args =
249 for (auto arg : args)
250 {
251 IntervalValue offset = as[call->getArgument(arg.second)->getId()].getInterval() - IntervalValue(1);
252 const SVFVar* argVar = call->getArgument(arg.first);
254 {
255 AEException bug(call->toString());
256 addBugToReporter(bug, call);
257 }
258 }
259 }
260 else if (extType == AbsExtAPI::MEMSET)
261 {
262 if (extAPIBufOverflowCheckRules.count(call->getCalledFunction()->getName()) == 0)
263 {
264 SVFUtil::errs() << "Warning: " << call->getCalledFunction()->getName() << " is not in the rules, please implement it\n";
265 return;
266 }
267 std::vector<std::pair<u32_t, u32_t>> args =
269 for (auto arg : args)
270 {
271 IntervalValue offset = as[call->getArgument(arg.second)->getId()].getInterval() - IntervalValue(1);
272 const SVFVar* argVar = call->getArgument(arg.first);
274 {
275 AEException bug(call->toString());
276 addBugToReporter(bug, call);
277 }
278 }
279 }
280 else if (extType == AbsExtAPI::STRCPY)
281 {
282 if (!detectStrcpy(as, call))
283 {
284 AEException bug(call->toString());
285 addBugToReporter(bug, call);
286 }
287 }
288 else if (extType == AbsExtAPI::STRCAT)
289 {
290 if (!detectStrcat(as, call))
291 {
292 AEException bug(call->toString());
293 addBugToReporter(bug, call);
294 }
295 }
296 else
297 {
298 // Handle other cases
299 }
300}
301
314{
315 SVFIR* svfir = PAG::getPAG();
316 auto obj = svfir->getGNode(objId);
317
318 if (SVFUtil::isa<BaseObjVar>(obj))
319 {
320 // if the object is a BaseObjVar, return the byte offset directly
321 // like `int arr[10]; arr[5] = 1;` arr is the baseObjVar
322 return as.getByteOffset(gep);
323 }
324 else if (SVFUtil::isa<GepObjVar>(obj))
325 {
326 // if the object is a GepObjVar, return the offset from the base object
327 // like `int arr[10]; int* p=arr+5; p[3] = 1`, p is the GepObjVar from arr.
328 return getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(obj)) + as.getByteOffset(gep);
329 }
330 else
331 {
332 assert(SVFUtil::isa<DummyObjVar>(obj) && "Unknown object type");
333 return IntervalValue::top();
334 }
335}
336
348{
349 SVFIR* svfir = PAG::getPAG();
350
351 for (const auto& objAddr : objAddrs)
352 {
353 NodeID objId = as.getIDFromAddr(objAddr);
354 auto obj = svfir->getGNode(objId);
355
356 if (SVFUtil::isa<BaseObjVar>(obj))
357 {
358 // if the object is a BaseObjVar, add the offset directly
359 // like llvm bc `arr = alloc i8 12; p = gep arr, 4`
360 // we write key value pair {gep, 4}
361 for (const auto& gepAddr : gepAddrs)
362 {
363 NodeID gepObj = as.getIDFromAddr(gepAddr);
364 if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast<GepObjVar>(svfir->getGNode(gepObj)))
365 {
367 }
368 else
369 {
370 assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address");
371 }
372 }
373 }
374 else if (SVFUtil::isa<GepObjVar>(obj))
375 {
376 // if the object is a GepObjVar, add the offset from the base object
377 // like llvm bc `arr = alloc i8 12; p = gep arr, 4; q = gep p, 6`
378 // we retreive {p, 4} and write {q, 4+6}
379 const GepObjVar* objVar = SVFUtil::cast<GepObjVar>(obj);
380 for (const auto& gepAddr : gepAddrs)
381 {
382 NodeID gepObj = as.getIDFromAddr(gepAddr);
383 if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast<GepObjVar>(svfir->getGNode(gepObj)))
384 {
386 {
392 }
393 else
394 {
395 assert(false &&
396 "GEP RHS object has no offset from base");
397 }
398 }
399 else
400 {
401 assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address");
402 }
403 }
404 }
405 }
406}
407
425
437{
438 const std::vector<std::string> strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"};
439 const std::vector<std::string> strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"};
440
441 if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end())
442 {
443 const SVFVar* arg0Val = call->getArgument(0);
444 const SVFVar* arg1Val = call->getArgument(1);
449 }
450 else if (std::find(strncatGroup.begin(), strncatGroup.end(), call->getCalledFunction()->getName()) != strncatGroup.end())
451 {
452 const SVFVar* arg0Val = call->getArgument(0);
453 const SVFVar* arg2Val = call->getArgument(2);
454 IntervalValue arg2Num = as[arg2Val->getId()].getInterval();
458 }
459 else
460 {
461 assert(false && "Unknown strcat function, please add it to strcatGroup or strncatGroup");
462 abort();
463 }
464}
465
478{
479 SVFIR* svfir = PAG::getPAG();
480 NodeID value_id = value->getId();
481
482 assert(as[value_id].isAddr());
483 for (const auto& addr : as[value_id].getAddrs())
484 {
485 NodeID objId = as.getIDFromAddr(addr);
486 u32_t size = 0;
487 // if the object is a constant size object, get the size directly
489 {
490 size = svfir->getBaseObject(objId)->getByteSizeOfObj();
491 }
492 else
493 {
494 // if the object is not a constant size object, get the size from the addrStmt
495 const ICFGNode* addrNode = svfir->getBaseObject(objId)->getICFGNode();
496 for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
497 {
498 if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
499 {
500 size = as.getAllocaInstByteSize(addrStmt);
501 }
502 }
503 }
504
506 // if the object is a GepObjVar, get the offset from the base object
507 if (SVFUtil::isa<GepObjVar>(svfir->getGNode(objId)))
508 {
509 offset = getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(svfir->getGNode(objId))) + len;
510 }
511 else if (SVFUtil::isa<BaseObjVar>(svfir->getGNode(objId)))
512 {
513 // if the object is a BaseObjVar, get the offset directly
514 offset = len;
515 }
516
517 // if the offset is greater than the size, return false
518 if (offset.ub().getIntNumeral() >= size)
519 {
520 return false;
521 }
522 }
523 return true;
524}
525
527{
528 if (SVFUtil::isa<CallICFGNode>(node))
529 {
530 // external API like memset(*dst, elem, sz)
531 // we check if it's external api and check the corrisponding index
532 const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
533 if (SVFUtil::isExtCall(callNode->getCalledFunction()))
534 {
536 }
537 }
538 else
539 {
540 for (const auto& stmt: node->getSVFStmts())
541 {
542 if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
543 {
544 // like llvm bitcode `p = gep p, idx`
545 // we check rhs p's all address are valid mem
546 SVFVar* rhs = gep->getRHSVar();
547 if (!canSafelyDerefPtr(as, rhs))
548 {
549 AEException bug(stmt->toString());
550 addBugToReporter(bug, stmt->getICFGNode());
551 }
552 }
553 else if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
554 {
555 // like llvm bitcode `p = load q`
556 // we check lhs p's all address are valid mem
557 SVFVar* lhs = load->getLHSVar();
558 if ( !canSafelyDerefPtr(as, lhs))
559 {
560 AEException bug(stmt->toString());
561 addBugToReporter(bug, stmt->getICFGNode());
562 }
563 }
564 }
565 }
566}
567
568
570{
571 std::string funcName = callNode->getCalledFunction()->getName();
572 if (funcName == "UNSAFE_LOAD")
573 {
574 // void UNSAFE_LOAD(void* ptr);
576 if (callNode->arg_size() < 1)
577 return;
579
580 const SVFVar* arg0Val = callNode->getArgument(0);
581 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)
582 bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
583 if (!isSafe)
584 {
585 SVFUtil::outs() << SVFUtil::sucMsg("success: expected null dereference at UNSAFE_LOAD")
586 << " — " << callNode->toString() << "\n";
587 return;
588 }
589 else
590 {
591 SVFUtil::outs() << SVFUtil::errMsg("failure: null dereference expected at UNSAFE_LOAD, but none detected")
592 << " — Position: " << callNode->getSourceLoc() << "\n";
593 assert(false);
594 }
595 }
596 else if (funcName == "SAFE_LOAD")
597 {
598 // void SAFE_LOAD(void* ptr);
600 if (callNode->arg_size() < 1) return;
602 const SVFVar* arg0Val = callNode->getArgument(0);
603 // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols
604 bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
605 if (isSafe)
606 {
607 SVFUtil::outs() << SVFUtil::sucMsg("success: expected safe dereference at SAFE_LOAD")
608 << " — " << callNode->toString() << "\n";
609 return;
610 }
611 else
612 {
613 SVFUtil::outs() << SVFUtil::errMsg("failure: unexpected null dereference at SAFE_LOAD")
614 << " — Position: " << callNode->getSourceLoc() << "\n";
615 assert(false);
616 }
617 }
618}
619
621{
622 assert(call->getCalledFunction() && "FunObjVar* is nullptr");
623 // get ext type
624 // get argument index which are nullptr deref checkpoints for extapi
625 std::vector<u32_t> tmp_args;
626 for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
627 {
628 if (annotation.find("MEMCPY") != std::string::npos)
629 {
630 if (call->arg_size() < 4)
631 {
632 // for memcpy(void* dest, const void* src, size_t n)
633 tmp_args.push_back(0);
634 tmp_args.push_back(1);
635 }
636 else
637 {
638 // for unsigned long iconv(void* cd, char **restrict inbuf, unsigned long *restrict inbytesleft, char **restrict outbuf, unsigned long *restrict outbytesleft)
639 tmp_args.push_back(1);
640 tmp_args.push_back(2);
641 tmp_args.push_back(3);
642 tmp_args.push_back(4);
643 }
644 }
645 else if (annotation.find("MEMSET") != std::string::npos)
646 {
647 // for memset(void* dest, elem, sz)
648 tmp_args.push_back(0);
649 }
650 else if (annotation.find("STRCPY") != std::string::npos)
651 {
652 // for strcpy(void* dest, void* src)
653 tmp_args.push_back(0);
654 tmp_args.push_back(1);
655 }
656 else if (annotation.find("STRCAT") != std::string::npos)
657 {
658 // for strcat(void* dest, const void* src)
659 // for strncat(void* dest, const void* src, size_t n)
660 tmp_args.push_back(0);
661 tmp_args.push_back(1);
662 }
663 }
664
665 for (const auto &arg: tmp_args)
666 {
667 if (call->arg_size() <= arg)
668 continue;
669 const SVFVar* argVal = call->getArgument(arg);
671 {
672 AEException bug(call->toString());
673 addBugToReporter(bug, call);
674 }
675 }
676}
677
678
680{
681 NodeID value_id = value->getId();
683 // uninit value cannot be dereferenced, return unsafe
684 if (isUninit(AbsVal)) return false;
685 // Interval Value (non-addr) is not the checkpoint of nullptr dereference, return safe
686 if (!AbsVal.isAddr()) return true;
687 for (const auto &addr: AbsVal.getAddrs())
688 {
689 // if the addr itself is invalid mem, report unsafe
691 return false;
692 // if nullptr is detected, return unsafe
694 return false;
695 // if addr is labeled freed mem, report unsafe
696 else if (as.isFreedMem(addr))
697 return false;
698 }
699
700
701 return true;
702}
buffer offset
Definition cJSON.cpp:1113
Exception class for handling errors in Abstract Execution.
Definition AEDetector.h:109
IntervalValue getStrlen(AbstractState &as, const SVF::SVFVar *strValue)
Calculates the length of a string.
ExtAPIType
Enumeration of external API types.
Definition AbsExtAPI.h:50
static AbstractInterpretation & getAEInstance()
AbstractState & getAbsStateFromTrace(const ICFGNode *node)
Retrieves the abstract state from the trace for a given ICFG node.
Set< const CallICFGNode * > checkpoints
static bool isNullMem(u32_t addr)
static bool isInvalidMem(u32_t addr)
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.
IntervalValue getAccessOffset(AbstractState &as, NodeID objId, const GepStmt *gep)
Retrieves the access offset for a given object and GEP statement.
void addToGepObjOffsetFromBase(const GepObjVar *obj, const IntervalValue &offset)
Adds an offset to a GEP object.
Definition AEDetector.h:194
Map< std::string, std::vector< std::pair< u32_t, u32_t > > > extAPIBufOverflowCheckRules
Rules for checking buffer overflows in external APIs.
Definition AEDetector.h:325
void detect(AbstractState &as, const ICFGNode *)
Detect buffer overflow issues within a node.
bool detectStrcpy(AbstractState &as, const CallICFGNode *call)
Detects buffer overflow in 'strcpy' function calls.
bool detectStrcat(AbstractState &as, const CallICFGNode *call)
Detects buffer overflow in 'strcat' function calls.
IntervalValue getGepObjOffsetFromBase(const GepObjVar *obj) const
Retrieves the offset of a GEP object from its base.
Definition AEDetector.h:214
void handleStubFunctions(const CallICFGNode *)
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:204
bool canSafelyAccessMemory(AbstractState &as, const SVFVar *value, const IntervalValue &len)
Checks if memory can be safely accessed.
void initExtAPIBufOverflowCheckRules()
Initializes external API buffer overflow check rules.
void detectExtAPI(AbstractState &as, const CallICFGNode *call)
Handles external API calls related to buffer overflow detection.
void updateGepObjOffsetFromBase(AbstractState &as, AddressValue gepAddrs, AddressValue objAddrs, IntervalValue offset)
Updates the offset of a GEP object from its base.
void addBugToReporter(const AEException &e, const ICFGNode *node)
Adds a bug to the reporter based on an exception.
Definition AEDetector.h:239
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
static ExtAPI * getExtAPI()
Definition ExtAPI.cpp:44
const std::vector< std::string > & getExtFuncAnnotations(const FunObjVar *fun)
Definition ExtAPI.cpp:256
NodeType * getGNode(NodeID id) const
Get a node.
const SVFStmtList & getSVFStmts() const
Definition ICFGNode.h:117
static IntervalValue bottom()
Create the bottom IntervalValue [+inf, -inf].
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
bool canSafelyDerefPtr(AbstractState &as, const SVFVar *ptr)
bool isUninit(AbstractValue v)
Checks if an Abstract Value is uninitialized.
Definition AEDetector.h:364
void detect(AbstractState &as, const ICFGNode *node)
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:376
void handleStubFunctions(const CallICFGNode *call)
Handles external API calls related to nullptr dereferences.
void detectExtAPI(AbstractState &as, const CallICFGNode *call)
Handle external API calls related to nullptr dereferences.
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:419
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:116
NodeID getId() const
Get ID.
Definition SVFValue.h:160
virtual const std::string & getName() const
Definition SVFValue.h:186
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
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:437
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:68
u32_t NodeID
Definition GeneralType.h:56
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
unsigned u32_t
Definition GeneralType.h:47