diff options
| author | David Carlier <devnexen@gmail.com> | 2018-07-19 21:50:03 +0000 | 
|---|---|---|
| committer | David Carlier <devnexen@gmail.com> | 2018-07-19 21:50:03 +0000 | 
| commit | 8e75de21002f104e4c328b5f43cc031fcb48f45f (patch) | |
| tree | 0f3d87fc13c546e850949df2f18e43c6e573c0b6 /clang/lib/StaticAnalyzer | |
| parent | 83497d9eadd04a0ee57e4858a8f3b7b3cb99a22b (diff) | |
| download | bcm5719-llvm-8e75de21002f104e4c328b5f43cc031fcb48f45f.tar.gz bcm5719-llvm-8e75de21002f104e4c328b5f43cc031fcb48f45f.zip  | |
[CStringSyntaxChecker] Check strlcpy sizeof syntax
The last argument is expected to be the destination buffer size (or less).
    Detects if it points to destination buffer size directly or via a variable.
    Detects if it is an integral, try to detect if the destination buffer can receive the source length.
Updating bsd-string.c unit tests as it make it fails now.
Reviewers: george.karpenpov, NoQ
Reviewed By: george.karpenkov
Differential Revision: https://reviews.llvm.org/D48884
llvm-svn: 337499
Diffstat (limited to 'clang/lib/StaticAnalyzer')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp | 62 | 
1 files changed, 62 insertions, 0 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index 4b5e97b6929..633e9724b61 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -80,6 +80,17 @@ class WalkAST: public StmtVisitor<WalkAST> {    /// of bytes to copy.    bool containsBadStrncatPattern(const CallExpr *CE); +  /// Identify erroneous patterns in the last argument to strlcpy - the number +  /// of bytes to copy. +  /// The bad pattern checked is when the size is known +  /// to be larger than the destination can handle. +  ///   char dst[2]; +  ///   size_t cpy = 4; +  ///   strlcpy(dst, "abcd", sizeof("abcd") - 1); +  ///   strlcpy(dst, "abcd", 4); +  ///   strlcpy(dst, "abcd", cpy); +  bool containsBadStrlcpyPattern(const CallExpr *CE); +  public:    WalkAST(const CheckerBase *Checker, BugReporter &BR, AnalysisDeclContext *AC)        : Checker(Checker), BR(BR), AC(AC) {} @@ -130,6 +141,38 @@ bool WalkAST::containsBadStrncatPattern(const CallExpr *CE) {    return false;  } +bool WalkAST::containsBadStrlcpyPattern(const CallExpr *CE) { +  if (CE->getNumArgs() != 3) +    return false; +  const Expr *DstArg = CE->getArg(0); +  const Expr *LenArg = CE->getArg(2); + +  const auto *DstArgDecl = dyn_cast<DeclRefExpr>(DstArg->IgnoreParenCasts()); +  const auto *LenArgDecl = dyn_cast<DeclRefExpr>(LenArg->IgnoreParenLValueCasts()); +  // - size_t dstlen = sizeof(dst) +  if (LenArgDecl) { +    const auto *LenArgVal = dyn_cast<VarDecl>(LenArgDecl->getDecl()); +    if (LenArgVal->getInit()) +	    LenArg = LenArgVal->getInit(); +  } + +  // - integral value +  // We try to figure out if the last argument is possibly longer +  // than the destination can possibly handle if its size can be defined +  if (const auto *IL = dyn_cast<IntegerLiteral>(LenArg->IgnoreParenCasts())) { +    uint64_t ILRawVal = IL->getValue().getZExtValue(); +    if (const auto *Buffer = dyn_cast<ConstantArrayType>(DstArgDecl->getType())) { +      ASTContext &C = BR.getContext(); +      uint64_t Usize = C.getTypeSizeInChars(DstArg->getType()).getQuantity(); +      uint64_t BufferLen = BR.getContext().getTypeSize(Buffer) / Usize; +      if (BufferLen < ILRawVal) +        return true; +    } +  } + +  return false; +} +  void WalkAST::VisitCallExpr(CallExpr *CE) {    const FunctionDecl *FD = CE->getDirectCallee();    if (!FD) @@ -159,6 +202,25 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {                           "C String API", os.str(), Loc,                           LenArg->getSourceRange());      } +  } else if (CheckerContext::isCLibraryFunction(FD, "strlcpy")) { +    if (containsBadStrlcpyPattern(CE)) { +      const Expr *DstArg = CE->getArg(0); +      const Expr *LenArg = CE->getArg(2); +      PathDiagnosticLocation Loc = +        PathDiagnosticLocation::createBegin(LenArg, BR.getSourceManager(), AC); + +      StringRef DstName = getPrintableName(DstArg); + +      SmallString<256> S; +      llvm::raw_svector_ostream os(S); +      os << "The third argument is larger than the size of the input buffer. "; +      if (!DstName.empty()) +        os << "Replace with the value 'sizeof(" << DstName << ")` or lower"; + +      BR.EmitBasicReport(FD, Checker, "Anti-pattern in the argument", +                         "C String API", os.str(), Loc, +                         LenArg->getSourceRange()); +    }    }    // Recurse and check children.  | 

