balazske updated this revision to Diff 252804. balazske added a comment. Improved documentation and handling of `KernelZeroSizePtrValue`.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D76830/new/ https://reviews.llvm.org/D76830 Files: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp clang/test/Analysis/kmalloc-linux-1.c
Index: clang/test/Analysis/kmalloc-linux-1.c =================================================================== --- /dev/null +++ clang/test/Analysis/kmalloc-linux-1.c @@ -0,0 +1,27 @@ +// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=unix.Malloc -verify %s + +#define ZERO_SIZE_PTR ((void *)16) + +void *__kmalloc(int size, int flags); + +// Linux kmalloc looks like this. +// (simplified) +void *kmalloc(int size, int flags) { + if (size == 0) + return ZERO_SIZE_PTR; + return __kmalloc(size, flags); +} + +// FIXME: malloc checker expects kfree with 2 arguments, is this correct? +// (recent kernel source code contains a `kfree(const void *)`) +void kfree(void *, int); + +void test_kmalloc_zero_sized_block_fixed_value_address() { + void *ptr = kmalloc(0, 0); // kmalloc returns a constant address + kfree(ptr, 0); // no warning about freeing a constant value +} + +void test_kfree_constant_value() { + void *ptr = (void *)1; + kfree(ptr, 0); // expected-warning{{Argument to kfree() is a constant address (1)}} +} Index: clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp +++ clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp @@ -126,9 +126,6 @@ if (!T.isOneOf(tok::l_paren, tok::r_paren)) FilteredTokens.push_back(T); - if (FilteredTokens.size() > 2) - return llvm::None; - // Parse an integer at the end of the macro definition. const Token &T = FilteredTokens.back(); if (!T.isLiteral()) @@ -140,11 +137,10 @@ return llvm::None; // Parse an optional minus sign. - if (FilteredTokens.size() == 2) { - if (FilteredTokens.front().is(tok::minus)) + size_t Size = FilteredTokens.size(); + if (Size >= 2) { + if (FilteredTokens[Size - 2].is(tok::minus)) IntValue = -IntValue; - else - return llvm::None; } return IntValue.getSExtValue(); Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -58,6 +58,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" @@ -389,6 +390,13 @@ // TODO: Remove mutable by moving the initializtaion to the registry function. mutable Optional<uint64_t> KernelZeroFlagVal; + // This type stores obtained value of macro `ZERO_SIZE_PTR`, and if it could + // be obtained. + using KernelZeroSizePtrValueTy = Optional<int>; + /// Store the optional value of macro called `ZERO_SIZE_PTR`. + /// The value is initialized at first use. + mutable Optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue; + /// Process C++ operator new()'s allocation, which is the part of C++ /// new-expression that goes before the constructor. void processNewAllocation(const CXXNewExpr *NE, CheckerContext &C, @@ -658,6 +666,13 @@ CheckerContext &C); void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; + + void initKernelZeroSizePtrValue(Preprocessor &PP) const { + // If not initialized yet, + if (!KernelZeroSizePtrValue) + // try to get the value. + KernelZeroSizePtrValue = tryExpandAsInteger("ZERO_SIZE_PTR", PP); + } }; //===----------------------------------------------------------------------===// @@ -1672,6 +1687,18 @@ if (ArgVal.isUnknownOrUndef()) return nullptr; + // If there is a macro called ZERO_SIZE_PTR, it could be a kernel source code + // and this value indicates a special value used for a zero-sized memory + // block. It is a constant value that is allowed to be freed. + const llvm::APSInt *ArgValKnown = + C.getSValBuilder().getKnownValue(State, ArgVal); + if (ArgValKnown) { + initKernelZeroSizePtrValue(C.getPreprocessor()); + if (*KernelZeroSizePtrValue && + ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue) + return nullptr; + } + const MemRegion *R = ArgVal.getAsRegion(); // Nonlocs can't be freed, of course.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits