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.
|
|
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": {
|
|
@@ -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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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
|
-
|
|
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
|
-
|
|
526
|
-
|
|
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
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
-
|
|
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
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
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;
|