|
58 | 58 | #include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
59 | 59 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
|
60 | 60 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
| 61 | +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" |
61 | 62 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
|
62 | 63 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
|
63 | 64 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
|
@@ -389,6 +390,13 @@ class MallocChecker
|
389 | 390 | // TODO: Remove mutable by moving the initializtaion to the registry function.
|
390 | 391 | mutable Optional<uint64_t> KernelZeroFlagVal;
|
391 | 392 |
|
| 393 | + using KernelZeroSizePtrValueTy = Optional<int>; |
| 394 | + /// Store the value of macro called `ZERO_SIZE_PTR`. |
| 395 | + /// The value is initialized at first use, before first use the outer |
| 396 | + /// Optional is empty, afterwards it contains another Optional that indicates |
| 397 | + /// if the macro value could be determined, and if yes the value itself. |
| 398 | + mutable Optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue; |
| 399 | + |
392 | 400 | /// Process C++ operator new()'s allocation, which is the part of C++
|
393 | 401 | /// new-expression that goes before the constructor.
|
394 | 402 | void processNewAllocation(const CXXNewExpr *NE, CheckerContext &C,
|
@@ -658,6 +666,10 @@ class MallocChecker
|
658 | 666 | CheckerContext &C);
|
659 | 667 |
|
660 | 668 | void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const;
|
| 669 | + |
| 670 | + /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`. |
| 671 | + bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, |
| 672 | + SVal ArgVal) const; |
661 | 673 | };
|
662 | 674 |
|
663 | 675 | //===----------------------------------------------------------------------===//
|
@@ -1677,7 +1689,13 @@ ProgramStateRef MallocChecker::FreeMemAux(
|
1677 | 1689 | // Nonlocs can't be freed, of course.
|
1678 | 1690 | // Non-region locations (labels and fixed addresses) also shouldn't be freed.
|
1679 | 1691 | if (!R) {
|
1680 |
| - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); |
| 1692 | + // Exception: |
| 1693 | + // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source |
| 1694 | + // code. In that case, the ZERO_SIZE_PTR defines a special value used for a |
| 1695 | + // zero-sized memory block which is allowed to be freed, despite not being a |
| 1696 | + // null pointer. |
| 1697 | + if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal)) |
| 1698 | + ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); |
1681 | 1699 | return nullptr;
|
1682 | 1700 | }
|
1683 | 1701 |
|
@@ -3023,6 +3041,18 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(
|
3023 | 3041 | return State;
|
3024 | 3042 | }
|
3025 | 3043 |
|
| 3044 | +bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, |
| 3045 | + SVal ArgVal) const { |
| 3046 | + if (!KernelZeroSizePtrValue) |
| 3047 | + KernelZeroSizePtrValue = |
| 3048 | + tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor()); |
| 3049 | + |
| 3050 | + const llvm::APSInt *ArgValKnown = |
| 3051 | + C.getSValBuilder().getKnownValue(State, ArgVal); |
| 3052 | + return ArgValKnown && *KernelZeroSizePtrValue && |
| 3053 | + ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue; |
| 3054 | +} |
| 3055 | + |
3026 | 3056 | static SymbolRef findFailedReallocSymbol(ProgramStateRef currState,
|
3027 | 3057 | ProgramStateRef prevState) {
|
3028 | 3058 | ReallocPairsTy currMap = currState->get<ReallocPairs>();
|
|
0 commit comments