svf-tools 1.0.1084 → 1.0.1086

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.1084",
3
+ "version": "1.0.1086",
4
4
  "description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -291,7 +291,8 @@ public:
291
291
  /// domain meet with other, important! other widen this.
292
292
  void meetWith(const AbstractState&other);
293
293
 
294
- void addToFreedAddrs(NodeID addr) {
294
+ void addToFreedAddrs(NodeID addr)
295
+ {
295
296
  _freedAddrs.insert(addr);
296
297
  }
297
298
 
@@ -322,7 +322,8 @@ private:
322
322
  SVFBugReport recoder; ///< Recorder for abstract execution bugs.
323
323
  Map<const ICFGNode*, std::string> nodeToBugInfo; ///< Maps ICFG nodes to bug information.
324
324
  };
325
- class NullptrDerefDetector : public AEDetector{
325
+ class NullptrDerefDetector : public AEDetector
326
+ {
326
327
  friend class AbstractInterpretation;
327
328
  public:
328
329
  NullptrDerefDetector()
@@ -355,17 +356,17 @@ public:
355
356
  * @param v The Abstract Value to check.
356
357
  * @return True if the value is uninitialized, false otherwise.
357
358
  */
358
- bool isUninit(AbstractValue v)
359
+ bool isUninit(AbstractValue v)
359
360
  {
360
361
  bool is = v.getAddrs().isBottom() && v.getInterval().isBottom();
361
362
  return is;
362
363
  }
363
364
 
364
- /**
365
- * @brief Adds a bug to the reporter based on an exception.
366
- * @param e The exception that was thrown.
367
- * @param node Pointer to the ICFG node where the bug was detected.
368
- */
365
+ /**
366
+ * @brief Adds a bug to the reporter based on an exception.
367
+ * @param e The exception that was thrown.
368
+ * @param node Pointer to the ICFG node where the bug was detected.
369
+ */
369
370
  void addBugToReporter(const AEException& e, const ICFGNode* node)
370
371
  {
371
372
  GenericBug::EventStack eventStack;
@@ -390,7 +391,7 @@ public:
390
391
  recoder.addAbsExecBug(GenericBug::FULLNULLPTRDEREFERENCE, eventStack, 0, 0, 0, 0);
391
392
  nodeToBugInfo[node] = e.what(); // Record the exception information for the node
392
393
  }
393
-
394
+
394
395
  /**
395
396
  * @brief Reports all detected nullptr dereference bugs.
396
397
  */
@@ -415,7 +416,7 @@ public:
415
416
  */
416
417
  void detectExtAPI(AbstractState& as, const CallICFGNode* call);
417
418
 
418
-
419
+
419
420
  /**
420
421
  * @brief Check if an Abstract Value is NULL (or uninitialized).
421
422
  *
@@ -427,7 +428,7 @@ public:
427
428
  }
428
429
 
429
430
  bool canSafelyDerefPtr(AbstractState& as, const SVFVar* ptr);
430
-
431
+
431
432
  private:
432
433
  Set<std::string> bugLoc; ///< Set of locations where bugs have been reported.
433
434
  SVFBugReport recoder; ///< Recorder for abstract execution bugs.
@@ -359,7 +359,8 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add
359
359
  {
360
360
  addToGepObjOffsetFromBase(gepObjVar, offset);
361
361
  }
362
- else {
362
+ else
363
+ {
363
364
  assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address");
364
365
  }
365
366
  }
@@ -387,7 +388,8 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add
387
388
  "GEP RHS object has no offset from base");
388
389
  }
389
390
  }
390
- else {
391
+ else
392
+ {
391
393
  assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address");
392
394
  }
393
395
  }
@@ -513,26 +515,34 @@ bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SV
513
515
  return true;
514
516
  }
515
517
 
516
- void NullptrDerefDetector::detect(AbstractState& as, const ICFGNode* node) {
517
- if (SVFUtil::isa<CallICFGNode>(node)){
518
+ void NullptrDerefDetector::detect(AbstractState& as, const ICFGNode* node)
519
+ {
520
+ if (SVFUtil::isa<CallICFGNode>(node))
521
+ {
518
522
  const CallICFGNode* callNode = SVFUtil::cast<CallICFGNode>(node);
519
523
  if (SVFUtil::isExtCall(callNode->getCalledFunction()))
520
524
  {
521
525
  detectExtAPI(as, callNode);
522
526
  }
523
527
  }
524
- else {
525
- for (const auto& stmt: node->getSVFStmts()) {
526
- if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt)) {
528
+ else
529
+ {
530
+ for (const auto& stmt: node->getSVFStmts())
531
+ {
532
+ if (const GepStmt* gep = SVFUtil::dyn_cast<GepStmt>(stmt))
533
+ {
527
534
  SVFVar* rhs = gep->getRHSVar();
528
- if (!canSafelyDerefPtr(as, rhs)) {
535
+ if (!canSafelyDerefPtr(as, rhs))
536
+ {
529
537
  AEException bug(stmt->toString());
530
538
  addBugToReporter(bug, stmt->getICFGNode());
531
539
  }
532
540
  }
533
- else if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt)) {
541
+ else if (const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt))
542
+ {
534
543
  SVFVar* lhs = load->getLHSVar();
535
- if ( !canSafelyDerefPtr(as, lhs)) {
544
+ if ( !canSafelyDerefPtr(as, lhs))
545
+ {
536
546
  AEException bug(stmt->toString());
537
547
  addBugToReporter(bug, stmt->getICFGNode());
538
548
  }
@@ -542,68 +552,75 @@ void NullptrDerefDetector::detect(AbstractState& as, const ICFGNode* node) {
542
552
  }
543
553
 
544
554
 
545
- void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode){
546
- std::string funcName = callNode->getCalledFunction()->getName();
547
- if (funcName == "UNSAFE_LOAD")
548
- {
549
- // void UNSAFE_LOAD(void* ptr);
550
- AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
551
- if (callNode->arg_size() < 1)
552
- return;
553
- AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode);
554
-
555
- const SVFVar* arg0Val = callNode->getArgument(0);
556
- // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)
557
- bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
558
- if (!isSafe) {
555
+ void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode)
556
+ {
557
+ std::string funcName = callNode->getCalledFunction()->getName();
558
+ if (funcName == "UNSAFE_LOAD")
559
+ {
560
+ // void UNSAFE_LOAD(void* ptr);
561
+ AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
562
+ if (callNode->arg_size() < 1)
563
+ return;
564
+ AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode);
565
+
566
+ const SVFVar* arg0Val = callNode->getArgument(0);
567
+ // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)
568
+ bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
569
+ if (!isSafe)
570
+ {
559
571
  std::cout << "detect null pointer deference success: " << callNode->toString() << std::endl;
560
572
  return;
561
- }
562
- else
563
- {
573
+ }
574
+ else
575
+ {
564
576
  std::string err_msg = "this UNSAFE_LOAD should be a null pointer dereference but not detected. Pos: ";
565
577
  err_msg += callNode->getSourceLoc();
566
578
  std::cerr << err_msg << std::endl;
567
579
  assert(false);
568
- }
569
- }
570
- else if (funcName == "SAFE_LOAD")
571
- {
572
- // void SAFE_LOAD(void* ptr);
573
- AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
574
- if (callNode->arg_size() < 1) return;
575
- AbstractState&as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode);
576
- const SVFVar* arg0Val = callNode->getArgument(0);
577
- // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols
578
- bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
579
- if (isSafe) {
580
- std::cout << "safe load pointer success: " << callNode->toString() << std::endl;
581
- return;
582
- }
583
- else
584
- {
585
- std::string err_msg = "this SAFE_LOAD should be a safe but a null pointer dereference detected. Pos: ";
586
- err_msg += callNode->getSourceLoc();
587
- std::cerr << err_msg << std::endl;
588
- assert(false);
589
- }
590
- }
580
+ }
581
+ }
582
+ else if (funcName == "SAFE_LOAD")
583
+ {
584
+ // void SAFE_LOAD(void* ptr);
585
+ AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
586
+ if (callNode->arg_size() < 1) return;
587
+ AbstractState&as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode);
588
+ const SVFVar* arg0Val = callNode->getArgument(0);
589
+ // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols
590
+ bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0;
591
+ if (isSafe)
592
+ {
593
+ std::cout << "safe load pointer success: " << callNode->toString() << std::endl;
594
+ return;
595
+ }
596
+ else
597
+ {
598
+ std::string err_msg = "this SAFE_LOAD should be a safe but a null pointer dereference detected. Pos: ";
599
+ err_msg += callNode->getSourceLoc();
600
+ std::cerr << err_msg << std::endl;
601
+ assert(false);
602
+ }
603
+ }
591
604
  }
592
605
 
593
- void NullptrDerefDetector::detectExtAPI(AbstractState& as, const CallICFGNode* call) {
606
+ void NullptrDerefDetector::detectExtAPI(AbstractState& as, const CallICFGNode* call)
607
+ {
594
608
  assert(call->getCalledFunction() && "FunObjVar* is nullptr");
595
609
  // get ext type
596
610
  // get argument index which are nullptr deref checkpoints for extapi
597
611
  std::vector<u32_t> tmp_args;
598
- for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction())){
612
+ for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(call->getCalledFunction()))
613
+ {
599
614
  if (annotation.find("MEMCPY") != std::string::npos)
600
615
  {
601
- if (call->arg_size() < 4) {
616
+ if (call->arg_size() < 4)
617
+ {
602
618
  // for memcpy(void* dest, const void* src, size_t n)
603
619
  tmp_args.push_back(0);
604
620
  tmp_args.push_back(1);
605
621
  }
606
- else {
622
+ else
623
+ {
607
624
  // for unsigned long iconv(void* cd, char **restrict inbuf, unsigned long *restrict inbytesleft, char **restrict outbuf, unsigned long *restrict outbytesleft)
608
625
  tmp_args.push_back(1);
609
626
  tmp_args.push_back(2);
@@ -631,11 +648,13 @@ void NullptrDerefDetector::detectExtAPI(AbstractState& as, const CallICFGNode* c
631
648
  }
632
649
  }
633
650
 
634
- for (const auto &arg: tmp_args) {
651
+ for (const auto &arg: tmp_args)
652
+ {
635
653
  if (call->arg_size() <= arg)
636
654
  continue;
637
655
  const SVFVar* argVal = call->getArgument(arg);
638
- if (argVal && !canSafelyDerefPtr(as, argVal)) {
656
+ if (argVal && !canSafelyDerefPtr(as, argVal))
657
+ {
639
658
  AEException bug(call->toString());
640
659
  addBugToReporter(bug, call);
641
660
  }
@@ -649,8 +668,10 @@ bool NullptrDerefDetector::canSafelyDerefPtr(AbstractState& as, const SVFVar* va
649
668
  AbstractValue AbsVal = as[value_id];
650
669
  if (isUninit(AbsVal)) return false;
651
670
  if (!AbsVal.isAddr()) return true;
652
- for (const auto &addr: AbsVal.getAddrs()) {
653
- if (AbstractState::isInvalidMem(addr)) {
671
+ for (const auto &addr: AbsVal.getAddrs())
672
+ {
673
+ if (AbstractState::isInvalidMem(addr))
674
+ {
654
675
  return false;
655
676
  }
656
677
  else if (AbstractState::isNullMem(addr))
@@ -340,32 +340,37 @@ void AbsExtAPI::initExtFunMap()
340
340
  };
341
341
  func_map["recv"] = sse_recv;
342
342
  func_map["__recv"] = sse_recv;
343
-
344
- auto sse_free = [&](const CallICFGNode *callNode)
345
- {
346
- if (callNode->arg_size() < 1) return;
347
- AbstractState& as = getAbsStateFromTrace(callNode);
348
- const u32_t freePtr = callNode->getArgument(0)->getId();
349
- for (auto addr: as[freePtr].getAddrs()) {
350
- if (AbstractState::isInvalidMem(addr)) {
351
- // double free here.
352
- } else
353
- {
354
- as.addToFreedAddrs(addr);
355
- }
356
- }
357
- };
358
- // Add all free-related functions to func_map
359
- std::vector<std::string> freeFunctions = {
360
- "VOS_MemFree", "cfree", "free", "free_all_mem", "freeaddrinfo",
361
- "gcry_mpi_release", "gcry_sexp_release", "globfree", "nhfree",
362
- "obstack_free", "safe_cfree", "safe_free", "safefree", "safexfree",
363
- "sm_free", "vim_free", "xfree", "SSL_CTX_free", "SSL_free", "XFree"
364
- };
365
-
366
- for (const auto& name : freeFunctions) {
367
- func_map[name] = sse_free;
368
- }
343
+
344
+ auto sse_free = [&](const CallICFGNode *callNode)
345
+ {
346
+ if (callNode->arg_size() < 1) return;
347
+ AbstractState& as = getAbsStateFromTrace(callNode);
348
+ const u32_t freePtr = callNode->getArgument(0)->getId();
349
+ for (auto addr: as[freePtr].getAddrs())
350
+ {
351
+ if (AbstractState::isInvalidMem(addr))
352
+ {
353
+ // double free here.
354
+ }
355
+ else
356
+ {
357
+ as.addToFreedAddrs(addr);
358
+ }
359
+ }
360
+ };
361
+ // Add all free-related functions to func_map
362
+ std::vector<std::string> freeFunctions =
363
+ {
364
+ "VOS_MemFree", "cfree", "free", "free_all_mem", "freeaddrinfo",
365
+ "gcry_mpi_release", "gcry_sexp_release", "globfree", "nhfree",
366
+ "obstack_free", "safe_cfree", "safe_free", "safefree", "safexfree",
367
+ "sm_free", "vim_free", "xfree", "SSL_CTX_free", "SSL_free", "XFree"
368
+ };
369
+
370
+ for (const auto& name : freeFunctions)
371
+ {
372
+ func_map[name] = sse_free;
373
+ }
369
374
  };
370
375
 
371
376
  AbstractState& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node)
@@ -275,7 +275,8 @@ bool AbstractInterpretation::isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t s
275
275
  NodeID res_id = cmpStmt->getResID();
276
276
  s32_t predicate = cmpStmt->getPredicate();
277
277
  // if op0 or op1 is nullptr, no need to change value, just copy the state
278
- if (op0 == IRGraph::NullPtr || op1 == IRGraph::NullPtr) {
278
+ if (op0 == IRGraph::NullPtr || op1 == IRGraph::NullPtr)
279
+ {
279
280
  as = new_es;
280
281
  return true;
281
282
  }
@@ -1325,7 +1326,8 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp)
1325
1326
  as[res] = resVal;
1326
1327
  }
1327
1328
  // if op0 or op1 is nullptr, compare abstractValue instead of touching addr or interval
1328
- else if (op0 == IRGraph::NullPtr || op1 == IRGraph::NullPtr) {
1329
+ else if (op0 == IRGraph::NullPtr || op1 == IRGraph::NullPtr)
1330
+ {
1329
1331
  u32_t res = cmp->getResID();
1330
1332
  IntervalValue resVal = (as[op0].equals(as[op1])) ? IntervalValue(1, 1) : IntervalValue(0, 0);
1331
1333
  as[res] = resVal;