svf-tools 1.0.978 → 1.0.980

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -203,7 +203,7 @@ inline CallSite getSVFCallSite(const SVFInstruction* inst)
203
203
  /// Match arguments for callsite at caller and callee
204
204
  /// if the arg size does not match then we do not need to connect this parameter
205
205
  /// unless the callee is a variadic function (the first parameter of variadic function is its parameter number)
206
- bool matchArgs(const SVFInstruction* cs, const SVFFunction* callee);
206
+ bool matchArgs(const CallSite cs, const SVFFunction* callee);
207
207
 
208
208
  /// Return LLVM callsite given a value
209
209
  inline CallSite getSVFCallSite(const SVFValue* value)
@@ -466,11 +466,6 @@ inline int getHeapAllocHoldingArgPosition(const CallSite cs)
466
466
  {
467
467
  return getHeapAllocHoldingArgPosition(getCallee(cs));
468
468
  }
469
-
470
- inline int getHeapAllocHoldingArgPosition(const SVFInstruction *inst)
471
- {
472
- return getHeapAllocHoldingArgPosition(getCallee(inst));
473
- }
474
469
  //@}
475
470
 
476
471
  inline bool isReallocExtCall(const CallSite cs)
@@ -478,12 +473,6 @@ inline bool isReallocExtCall(const CallSite cs)
478
473
  bool isPtrTy = cs.getInstruction()->getType()->isPointerTy();
479
474
  return isPtrTy && isReallocExtFun(getCallee(cs));
480
475
  }
481
-
482
- inline bool isReallocExtCall(const SVFInstruction *inst)
483
- {
484
- bool isPtrTy = inst->getType()->isPointerTy();
485
- return isPtrTy && isReallocExtFun(getCallee(inst));
486
- }
487
476
  //@}
488
477
 
489
478
  /// Return true if this is a thread creation call
@@ -504,10 +493,6 @@ inline bool isThreadJoinCall(const CallSite cs)
504
493
  {
505
494
  return ThreadAPI::getThreadAPI()->isTDJoin(cs.getInstruction());
506
495
  }
507
- inline bool isThreadJoinCall(const SVFInstruction *inst)
508
- {
509
- return ThreadAPI::getThreadAPI()->isTDJoin(inst);
510
- }
511
496
  //@}
512
497
 
513
498
  /// Return true if this is a thread exit call
@@ -516,10 +501,6 @@ inline bool isThreadExitCall(const CallSite cs)
516
501
  {
517
502
  return ThreadAPI::getThreadAPI()->isTDExit(cs.getInstruction());
518
503
  }
519
- inline bool isThreadExitCall(const SVFInstruction *inst)
520
- {
521
- return ThreadAPI::getThreadAPI()->isTDExit(inst);
522
- }
523
504
  //@}
524
505
 
525
506
  /// Return true if this is a lock acquire call
@@ -528,10 +509,6 @@ inline bool isLockAquireCall(const CallSite cs)
528
509
  {
529
510
  return ThreadAPI::getThreadAPI()->isTDAcquire(cs.getInstruction());
530
511
  }
531
- inline bool isLockAquireCall(const SVFInstruction *inst)
532
- {
533
- return ThreadAPI::getThreadAPI()->isTDAcquire(inst);
534
- }
535
512
  //@}
536
513
 
537
514
  /// Return true if this is a lock acquire call
@@ -540,10 +517,6 @@ inline bool isLockReleaseCall(const CallSite cs)
540
517
  {
541
518
  return ThreadAPI::getThreadAPI()->isTDRelease(cs.getInstruction());
542
519
  }
543
- inline bool isLockReleaseCall(const SVFInstruction *inst)
544
- {
545
- return ThreadAPI::getThreadAPI()->isTDRelease(inst);
546
- }
547
520
  //@}
548
521
 
549
522
  /// Return true if this is a barrier wait call
@@ -552,10 +525,6 @@ inline bool isBarrierWaitCall(const CallSite cs)
552
525
  {
553
526
  return ThreadAPI::getThreadAPI()->isTDBarWait(cs.getInstruction());
554
527
  }
555
- inline bool isBarrierWaitCall(const SVFInstruction *inst)
556
- {
557
- return ThreadAPI::getThreadAPI()->isTDBarWait(inst);
558
- }
559
528
  //@}
560
529
 
561
530
  /// Return sole argument of the thread routine
@@ -564,10 +533,6 @@ inline const SVFValue* getActualParmAtForkSite(const CallSite cs)
564
533
  {
565
534
  return ThreadAPI::getThreadAPI()->getActualParmAtForkSite(cs.getInstruction());
566
535
  }
567
- inline const SVFValue* getActualParmAtForkSite(const SVFInstruction *inst)
568
- {
569
- return ThreadAPI::getThreadAPI()->getActualParmAtForkSite(inst);
570
- }
571
536
  //@}
572
537
 
573
538
 
@@ -576,10 +541,6 @@ inline bool isProgExitCall(const CallSite cs)
576
541
  return isProgExitFunction(getCallee(cs));
577
542
  }
578
543
 
579
- inline bool isProgExitCall(const SVFInstruction *inst)
580
- {
581
- return isProgExitFunction(getCallee(inst));
582
- }
583
544
 
584
545
  template<typename T>
585
546
  constexpr typename std::remove_reference<T>::type &&
@@ -468,4 +468,60 @@ void AbstractState::printAbstractState() const
468
468
  }
469
469
  }
470
470
  SVFUtil::outs() << "-----------------------------------------\n";
471
+ }
472
+
473
+ const SVFType* AbstractState::getPointeeElement(NodeID id)
474
+ {
475
+ SVFIR* svfir = PAG::getPAG();
476
+ if (inVarToAddrsTable(id))
477
+ {
478
+ const AbstractValue& addrs = (*this)[id];
479
+ for (auto addr: addrs.getAddrs())
480
+ {
481
+ NodeID addr_id = AbstractState::getInternalID(addr);
482
+ if (addr_id == 0) // nullptr has no memobj, skip
483
+ continue;
484
+ return SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(addr_id))->getMemObj()->getType();
485
+ }
486
+ }
487
+ else
488
+ {
489
+ // do nothing if no record in addrs table.
490
+ }
491
+ return nullptr;
492
+ }
493
+
494
+ u32_t AbstractState::getAllocaInstByteSize(const AddrStmt *addr)
495
+ {
496
+ SVFIR* svfir = PAG::getPAG();
497
+ if (const ObjVar* objvar = SVFUtil::dyn_cast<ObjVar>(addr->getRHSVar()))
498
+ {
499
+ objvar->getType();
500
+ if (objvar->getMemObj()->isConstantByteSize())
501
+ {
502
+ u32_t sz = objvar->getMemObj()->getByteSizeOfObj();
503
+ return sz;
504
+ }
505
+
506
+ else
507
+ {
508
+ const std::vector<SVFValue*>& sizes = addr->getArrSize();
509
+ // Default element size is set to 1.
510
+ u32_t elementSize = 1;
511
+ u64_t res = elementSize;
512
+ for (const SVFValue* value: sizes)
513
+ {
514
+ if (!inVarToValTable(svfir->getValueNode(value)))
515
+ {
516
+ (*this)[svfir->getValueNode(value)] = IntervalValue(Options::MaxFieldLimit());
517
+ }
518
+ IntervalValue itv =
519
+ (*this)[svfir->getValueNode(value)].getInterval();
520
+ res = res * itv.ub().getIntNumeral() > Options::MaxFieldLimit()? Options::MaxFieldLimit(): res * itv.ub().getIntNumeral();
521
+ }
522
+ return (u32_t)res;
523
+ }
524
+ }
525
+ assert (false && "Addr rhs value is not ObjVar");
526
+ abort();
471
527
  }
@@ -0,0 +1,435 @@
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 by Jiawei Wang on 2024/8/20.
26
+ //
27
+
28
+ #include <AE/Svfexe/AEDetector.h>
29
+ #include <AE/Svfexe/AbstractInterpretation.h>
30
+
31
+ using namespace SVF;
32
+
33
+ /**
34
+ * @brief Detects buffer overflow issues within a given ICFG node.
35
+ *
36
+ * This function handles both non-call nodes, where it analyzes GEP (GetElementPtr)
37
+ * instructions for potential buffer overflows, and call nodes, where it checks
38
+ * for external API calls that may cause overflows.
39
+ *
40
+ * @param as Reference to the abstract state.
41
+ * @param node Pointer to the ICFG node.
42
+ */
43
+ void BufOverflowDetector::detect(AbstractState& as, const ICFGNode* node)
44
+ {
45
+ if (!SVFUtil::isa<CallICFGNode>(node))
46
+ {
47
+ // Handle non-call nodes by analyzing GEP instructions
48
+ for (const SVFStmt* stmt : node->getSVFStmts())
49
+ {
50
+ if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
51
+ {
52
+ SVFIR* svfir = PAG::getPAG();
53
+ NodeID lhs = gep->getLHSVarID();
54
+ NodeID rhs = gep->getRHSVarID();
55
+
56
+ // Update the GEP object offset from its base
57
+ updateGepObjOffsetFromBase(as[lhs].getAddrs(), as[rhs].getAddrs(), as.getByteOffset(gep));
58
+
59
+ IntervalValue baseObjSize = IntervalValue::bottom();
60
+ AddressValue objAddrs = as[gep->getRHSVarID()].getAddrs();
61
+ for (const auto& addr : objAddrs)
62
+ {
63
+ NodeID objId = AbstractState::getInternalID(addr);
64
+ u32_t size = 0;
65
+
66
+ if (svfir->getBaseObj(objId)->isConstantByteSize())
67
+ {
68
+ size = svfir->getBaseObj(objId)->getByteSizeOfObj();
69
+ }
70
+ else
71
+ {
72
+ const ICFGNode* addrNode = svfir->getICFG()->getICFGNode(SVFUtil::cast<SVFInstruction>(svfir->getBaseObj(objId)->getValue()));
73
+ for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
74
+ {
75
+ if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
76
+ {
77
+ size = as.getAllocaInstByteSize(addrStmt);
78
+ }
79
+ }
80
+ }
81
+
82
+ // Calculate access offset and check for potential overflow
83
+ IntervalValue accessOffset = getAccessOffset(as, objId, gep);
84
+ if (accessOffset.ub().getIntNumeral() >= size)
85
+ {
86
+ AEException bug(stmt->toString());
87
+ addBugToReporter(bug, stmt->getICFGNode());
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ else
94
+ {
95
+ // Handle call nodes by checking for external API calls
96
+ const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
97
+ const SVFFunction *callfun = SVFUtil::getCallee(callNode->getCallSite());
98
+ if (SVFUtil::isExtCall(callfun))
99
+ {
100
+ detectExtAPI(as, callNode);
101
+ }
102
+ }
103
+ }
104
+
105
+ /**
106
+ * @brief Initializes external API buffer overflow check rules.
107
+ *
108
+ * This function sets up rules for various memory-related functions like memcpy,
109
+ * memset, etc., defining which arguments should be checked for buffer overflows.
110
+ */
111
+ void BufOverflowDetector::initExtAPIBufOverflowCheckRules()
112
+ {
113
+ extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
114
+ extAPIBufOverflowCheckRules["llvm_memcpy_p0_p0_i64"] = {{0, 2}, {1, 2}};
115
+ extAPIBufOverflowCheckRules["llvm_memcpy_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
116
+ extAPIBufOverflowCheckRules["llvm_memcpy"] = {{0, 2}, {1, 2}};
117
+ extAPIBufOverflowCheckRules["llvm_memmove"] = {{0, 2}, {1, 2}};
118
+ extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i64"] = {{0, 2}, {1, 2}};
119
+ extAPIBufOverflowCheckRules["llvm_memmove_p0_p0_i64"] = {{0, 2}, {1, 2}};
120
+ extAPIBufOverflowCheckRules["llvm_memmove_p0i8_p0i8_i32"] = {{0, 2}, {1, 2}};
121
+ extAPIBufOverflowCheckRules["__memcpy_chk"] = {{0, 2}, {1, 2}};
122
+ extAPIBufOverflowCheckRules["memmove"] = {{0, 2}, {1, 2}};
123
+ extAPIBufOverflowCheckRules["bcopy"] = {{0, 2}, {1, 2}};
124
+ extAPIBufOverflowCheckRules["memccpy"] = {{0, 3}, {1, 3}};
125
+ extAPIBufOverflowCheckRules["__memmove_chk"] = {{0, 2}, {1, 2}};
126
+ extAPIBufOverflowCheckRules["llvm_memset"] = {{0, 2}};
127
+ extAPIBufOverflowCheckRules["llvm_memset_p0i8_i32"] = {{0, 2}};
128
+ extAPIBufOverflowCheckRules["llvm_memset_p0i8_i64"] = {{0, 2}};
129
+ extAPIBufOverflowCheckRules["llvm_memset_p0_i64"] = {{0, 2}};
130
+ extAPIBufOverflowCheckRules["__memset_chk"] = {{0, 2}};
131
+ extAPIBufOverflowCheckRules["wmemset"] = {{0, 2}};
132
+ extAPIBufOverflowCheckRules["strncpy"] = {{0, 2}, {1, 2}};
133
+ extAPIBufOverflowCheckRules["iconv"] = {{1, 2}, {3, 4}};
134
+ }
135
+
136
+ /**
137
+ * @brief Handles external API calls related to buffer overflow detection.
138
+ *
139
+ * This function checks the type of external memory API (e.g., memcpy, memset, strcpy, strcat)
140
+ * and applies the corresponding buffer overflow checks based on predefined rules.
141
+ *
142
+ * @param as Reference to the abstract state.
143
+ * @param call Pointer to the call ICFG node.
144
+ */
145
+ void BufOverflowDetector::detectExtAPI(AbstractState& as,
146
+ const CallICFGNode* call)
147
+ {
148
+ SVFIR* svfir = PAG::getPAG();
149
+ const SVFFunction *fun = SVFUtil::getCallee(call->getCallSite());
150
+ assert(fun && "SVFFunction* is nullptr");
151
+ CallSite cs = SVFUtil::getSVFCallSite(call->getCallSite());
152
+
153
+ AbstractInterpretation::ExtAPIType extType = AbstractInterpretation::UNCLASSIFIED;
154
+
155
+ // Determine the type of external memory API
156
+ for (const std::string &annotation : fun->getAnnotations())
157
+ {
158
+ if (annotation.find("MEMCPY") != std::string::npos)
159
+ extType = AbstractInterpretation::MEMCPY;
160
+ if (annotation.find("MEMSET") != std::string::npos)
161
+ extType = AbstractInterpretation::MEMSET;
162
+ if (annotation.find("STRCPY") != std::string::npos)
163
+ extType = AbstractInterpretation::STRCPY;
164
+ if (annotation.find("STRCAT") != std::string::npos)
165
+ extType = AbstractInterpretation::STRCAT;
166
+ }
167
+
168
+ // Apply buffer overflow checks based on the determined API type
169
+ if (extType == AbstractInterpretation::MEMCPY)
170
+ {
171
+ if (extAPIBufOverflowCheckRules.count(fun->getName()) == 0)
172
+ {
173
+ SVFUtil::errs() << "Warning: " << fun->getName() << " is not in the rules, please implement it\n";
174
+ return;
175
+ }
176
+ std::vector<std::pair<u32_t, u32_t>> args =
177
+ extAPIBufOverflowCheckRules.at(fun->getName());
178
+ for (auto arg : args)
179
+ {
180
+ IntervalValue offset = as[svfir->getValueNode(cs.getArgument(arg.second))].getInterval() - IntervalValue(1);
181
+ if (!canSafelyAccessMemory(as, cs.getArgument(arg.first), offset))
182
+ {
183
+ AEException bug(call->getCallSite()->toString());
184
+ addBugToReporter(bug, call);
185
+ }
186
+ }
187
+ }
188
+ else if (extType == AbstractInterpretation::MEMSET)
189
+ {
190
+ if (extAPIBufOverflowCheckRules.count(fun->getName()) == 0)
191
+ {
192
+ SVFUtil::errs() << "Warning: " << fun->getName() << " is not in the rules, please implement it\n";
193
+ return;
194
+ }
195
+ std::vector<std::pair<u32_t, u32_t>> args =
196
+ extAPIBufOverflowCheckRules.at(fun->getName());
197
+ for (auto arg : args)
198
+ {
199
+ IntervalValue offset = as[svfir->getValueNode(cs.getArgument(arg.second))].getInterval() - IntervalValue(1);
200
+ if (!canSafelyAccessMemory(as, cs.getArgument(arg.first), offset))
201
+ {
202
+ AEException bug(call->getCallSite()->toString());
203
+ addBugToReporter(bug, call);
204
+ }
205
+ }
206
+ }
207
+ else if (extType == AbstractInterpretation::STRCPY)
208
+ {
209
+ if (!detectStrcpy(as, call))
210
+ {
211
+ AEException bug(call->getCallSite()->toString());
212
+ addBugToReporter(bug, call);
213
+ }
214
+ }
215
+ else if (extType == AbstractInterpretation::STRCAT)
216
+ {
217
+ if (!detectStrcat(as, call))
218
+ {
219
+ AEException bug(call->getCallSite()->toString());
220
+ addBugToReporter(bug, call);
221
+ }
222
+ }
223
+ else
224
+ {
225
+ // Handle other cases
226
+ }
227
+ }
228
+
229
+ /**
230
+ * @brief Retrieves the access offset for a given object and GEP statement.
231
+ *
232
+ * This function calculates the access offset for a base object or a sub-object of an
233
+ * aggregate object (using GEP). If the object is a dummy object, it returns a top interval value.
234
+ *
235
+ * @param as Reference to the abstract state.
236
+ * @param objId The ID of the object.
237
+ * @param gep Pointer to the GEP statement.
238
+ * @return The interval value of the access offset.
239
+ */
240
+ IntervalValue BufOverflowDetector::getAccessOffset(SVF::AbstractState& as, SVF::NodeID objId, const SVF::GepStmt* gep)
241
+ {
242
+ SVFIR* svfir = PAG::getPAG();
243
+ auto obj = svfir->getGNode(objId);
244
+
245
+ // if the object is a FIObjVar, return the byte offset directly
246
+ if (SVFUtil::isa<FIObjVar>(obj))
247
+ {
248
+ return as.getByteOffset(gep);
249
+ }
250
+ else if (SVFUtil::isa<GepObjVar>(obj))
251
+ {
252
+ // if the object is a GepObjVar, return the offset from the base object
253
+ return getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(obj)) + as.getByteOffset(gep);
254
+ }
255
+ else
256
+ {
257
+ assert(SVFUtil::isa<DummyObjVar>(obj) && "Unknown object type");
258
+ return IntervalValue::top();
259
+ }
260
+ }
261
+
262
+ /**
263
+ * @brief Updates the offset of a GEP object from its base.
264
+ *
265
+ * This function calculates and stores the offset of a GEP object from its base object
266
+ * using the addresses and offsets provided.
267
+ *
268
+ * @param gepAddrs The addresses of the GEP objects.
269
+ * @param objAddrs The addresses of the base objects.
270
+ * @param offset The interval value of the offset.
271
+ */
272
+ void BufOverflowDetector::updateGepObjOffsetFromBase(SVF::AddressValue gepAddrs, SVF::AddressValue objAddrs, SVF::IntervalValue offset)
273
+ {
274
+ SVFIR* svfir = PAG::getPAG();
275
+
276
+ for (const auto& objAddr : objAddrs)
277
+ {
278
+ NodeID objId = AbstractState::getInternalID(objAddr);
279
+ auto obj = svfir->getGNode(objId);
280
+ // if the object is a FIObjVar, add the offset directly
281
+ if (SVFUtil::isa<FIObjVar>(obj))
282
+ {
283
+ for (const auto& gepAddr : gepAddrs)
284
+ {
285
+ NodeID gepObj = AbstractState::getInternalID(gepAddr);
286
+ const GepObjVar* gepObjVar = SVFUtil::cast<GepObjVar>(svfir->getGNode(gepObj));
287
+ addToGepObjOffsetFromBase(gepObjVar, offset);
288
+ }
289
+ }
290
+ else if (SVFUtil::isa<GepObjVar>(obj))
291
+ {
292
+ // if the object is a GepObjVar, add the offset from the base object
293
+ const GepObjVar* objVar = SVFUtil::cast<GepObjVar>(obj);
294
+ for (const auto& gepAddr : gepAddrs)
295
+ {
296
+ NodeID gepObj = AbstractState::getInternalID(gepAddr);
297
+ const GepObjVar* gepObjVar = SVFUtil::cast<GepObjVar>(svfir->getGNode(gepObj));
298
+ if (hasGepObjOffsetFromBase(objVar))
299
+ {
300
+ IntervalValue objOffsetFromBase = getGepObjOffsetFromBase(objVar);
301
+ if (!hasGepObjOffsetFromBase(gepObjVar))
302
+ addToGepObjOffsetFromBase(gepObjVar, objOffsetFromBase + offset);
303
+ }
304
+ else
305
+ {
306
+ assert(false && "GEP RHS object has no offset from base");
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+
313
+ /**
314
+ * @brief Detects buffer overflow in 'strcpy' function calls.
315
+ *
316
+ * This function checks if the destination buffer can safely accommodate the
317
+ * source string being copied, accounting for the null terminator.
318
+ *
319
+ * @param as Reference to the abstract state.
320
+ * @param call Pointer to the call ICFG node.
321
+ * @return True if the memory access is safe, false otherwise.
322
+ */
323
+ bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *call)
324
+ {
325
+ CallSite cs = SVFUtil::getSVFCallSite(call->getCallSite());
326
+ const SVFValue* arg0Val = cs.getArgument(0);
327
+ const SVFValue* arg1Val = cs.getArgument(1);
328
+ IntervalValue strLen = AbstractInterpretation::getAEInstance().getStrlen(as, arg1Val);
329
+ return canSafelyAccessMemory(as, arg0Val, strLen);
330
+ }
331
+
332
+ /**
333
+ * @brief Detects buffer overflow in 'strcat' function calls.
334
+ *
335
+ * This function checks if the destination buffer can safely accommodate both the
336
+ * existing string and the concatenated string from the source.
337
+ *
338
+ * @param as Reference to the abstract state.
339
+ * @param call Pointer to the call ICFG node.
340
+ * @return True if the memory access is safe, false otherwise.
341
+ */
342
+ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *call)
343
+ {
344
+ SVFIR* svfir = PAG::getPAG();
345
+ const SVFFunction *fun = SVFUtil::getCallee(call->getCallSite());
346
+
347
+ const std::vector<std::string> strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"};
348
+ const std::vector<std::string> strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"};
349
+
350
+ if (std::find(strcatGroup.begin(), strcatGroup.end(), fun->getName()) != strcatGroup.end())
351
+ {
352
+ CallSite cs = SVFUtil::getSVFCallSite(call->getCallSite());
353
+ const SVFValue* arg0Val = cs.getArgument(0);
354
+ const SVFValue* arg1Val = cs.getArgument(1);
355
+ IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getStrlen(as, arg0Val);
356
+ IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getStrlen(as, arg1Val);
357
+ IntervalValue totalLen = strLen0 + strLen1;
358
+ return canSafelyAccessMemory(as, arg0Val, totalLen);
359
+ }
360
+ else if (std::find(strncatGroup.begin(), strncatGroup.end(), fun->getName()) != strncatGroup.end())
361
+ {
362
+ CallSite cs = SVFUtil::getSVFCallSite(call->getCallSite());
363
+ const SVFValue* arg0Val = cs.getArgument(0);
364
+ const SVFValue* arg2Val = cs.getArgument(2);
365
+ IntervalValue arg2Num = as[svfir->getValueNode(arg2Val)].getInterval();
366
+ IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getStrlen(as, arg0Val);
367
+ IntervalValue totalLen = strLen0 + arg2Num;
368
+ return canSafelyAccessMemory(as, arg0Val, totalLen);
369
+ }
370
+ else
371
+ {
372
+ assert(false && "Unknown strcat function, please add it to strcatGroup or strncatGroup");
373
+ abort();
374
+ }
375
+ }
376
+
377
+ /**
378
+ * @brief Checks if a memory access is safe given a specific buffer length.
379
+ *
380
+ * This function ensures that a given memory access, starting at a specific value,
381
+ * does not exceed the allocated size of the buffer.
382
+ *
383
+ * @param as Reference to the abstract state.
384
+ * @param value Pointer to the SVF value.
385
+ * @param len The interval value representing the length of the memory access.
386
+ * @return True if the memory access is safe, false otherwise.
387
+ */
388
+ bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SVFValue* value, const SVF::IntervalValue& len)
389
+ {
390
+ SVFIR* svfir = PAG::getPAG();
391
+ NodeID value_id = svfir->getValueNode(value);
392
+
393
+ assert(as[value_id].isAddr());
394
+ for (const auto& addr : as[value_id].getAddrs())
395
+ {
396
+ NodeID objId = AbstractState::getInternalID(addr);
397
+ u32_t size = 0;
398
+
399
+ // if the object is a constant size object, get the size directly
400
+ if (svfir->getBaseObj(objId)->isConstantByteSize())
401
+ {
402
+ size = svfir->getBaseObj(objId)->getByteSizeOfObj();
403
+ }
404
+ else
405
+ {
406
+ // if the object is not a constant size object, get the size from the addrStmt
407
+ const ICFGNode* addrNode = svfir->getICFG()->getICFGNode(SVFUtil::cast<SVFInstruction>(svfir->getBaseObj(objId)->getValue()));
408
+ for (const SVFStmt* stmt2 : addrNode->getSVFStmts())
409
+ {
410
+ if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
411
+ {
412
+ size = as.getAllocaInstByteSize(addrStmt);
413
+ }
414
+ }
415
+ }
416
+
417
+ IntervalValue offset(0);
418
+ // if the object is a GepObjVar, get the offset from the base object
419
+ if (SVFUtil::isa<GepObjVar>(svfir->getGNode(objId)))
420
+ {
421
+ offset = getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(svfir->getGNode(objId))) + len;
422
+ }
423
+ else
424
+ {
425
+ // if the object is a FIObjVar, get the offset directly
426
+ offset = len;
427
+ }
428
+ // if the offset is greater than the size, return false
429
+ if (offset.ub().getIntNumeral() >= size)
430
+ {
431
+ return false;
432
+ }
433
+ }
434
+ return true;
435
+ }