xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //== CheckerContext.cpp - Context info for path-sensitive checkers-----------=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file defines CheckerContext that provides contextual info for
100b57cec5SDimitry Andric //  path-sensitive checkers.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
150b57cec5SDimitry Andric #include "clang/Basic/Builtins.h"
160b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
1706c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace clang;
200b57cec5SDimitry Andric using namespace ento;
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric const FunctionDecl *CheckerContext::getCalleeDecl(const CallExpr *CE) const {
23fe6060f1SDimitry Andric   const FunctionDecl *D = CE->getDirectCallee();
24fe6060f1SDimitry Andric   if (D)
25fe6060f1SDimitry Andric     return D;
26fe6060f1SDimitry Andric 
270b57cec5SDimitry Andric   const Expr *Callee = CE->getCallee();
280b57cec5SDimitry Andric   SVal L = Pred->getSVal(Callee);
290b57cec5SDimitry Andric   return L.getAsFunctionDecl();
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const {
330b57cec5SDimitry Andric   if (!FunDecl)
340b57cec5SDimitry Andric     return StringRef();
350b57cec5SDimitry Andric   IdentifierInfo *funI = FunDecl->getIdentifier();
360b57cec5SDimitry Andric   if (!funI)
370b57cec5SDimitry Andric     return StringRef();
380b57cec5SDimitry Andric   return funI->getName();
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric StringRef CheckerContext::getDeclDescription(const Decl *D) {
42349cc55cSDimitry Andric   if (isa<ObjCMethodDecl, CXXMethodDecl>(D))
430b57cec5SDimitry Andric     return "method";
440b57cec5SDimitry Andric   if (isa<BlockDecl>(D))
450b57cec5SDimitry Andric     return "anonymous block";
460b57cec5SDimitry Andric   return "function";
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
500b57cec5SDimitry Andric                                         StringRef Name) {
510b57cec5SDimitry Andric   // To avoid false positives (Ex: finding user defined functions with
520b57cec5SDimitry Andric   // similar names), only perform fuzzy name matching when it's a builtin.
530b57cec5SDimitry Andric   // Using a string compare is slow, we might want to switch on BuiltinID here.
540b57cec5SDimitry Andric   unsigned BId = FD->getBuiltinID();
550b57cec5SDimitry Andric   if (BId != 0) {
560b57cec5SDimitry Andric     if (Name.empty())
570b57cec5SDimitry Andric       return true;
580b57cec5SDimitry Andric     StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId);
5981ad6265SDimitry Andric     size_t start = BName.find(Name);
6081ad6265SDimitry Andric     if (start != StringRef::npos) {
6181ad6265SDimitry Andric       // Accept exact match.
6281ad6265SDimitry Andric       if (BName.size() == Name.size())
630b57cec5SDimitry Andric         return true;
6481ad6265SDimitry Andric 
6581ad6265SDimitry Andric       //    v-- match starts here
6681ad6265SDimitry Andric       // ...xxxxx...
6781ad6265SDimitry Andric       //   _xxxxx_
6881ad6265SDimitry Andric       //   ^     ^ lookbehind and lookahead characters
6981ad6265SDimitry Andric 
7081ad6265SDimitry Andric       const auto MatchPredecessor = [=]() -> bool {
7181ad6265SDimitry Andric         return start <= 0 || !llvm::isAlpha(BName[start - 1]);
7281ad6265SDimitry Andric       };
7381ad6265SDimitry Andric       const auto MatchSuccessor = [=]() -> bool {
7481ad6265SDimitry Andric         std::size_t LookbehindPlace = start + Name.size();
7581ad6265SDimitry Andric         return LookbehindPlace >= BName.size() ||
7681ad6265SDimitry Andric                !llvm::isAlpha(BName[LookbehindPlace]);
7781ad6265SDimitry Andric       };
7881ad6265SDimitry Andric 
7981ad6265SDimitry Andric       if (MatchPredecessor() && MatchSuccessor())
8081ad6265SDimitry Andric         return true;
8181ad6265SDimitry Andric     }
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   const IdentifierInfo *II = FD->getIdentifier();
850b57cec5SDimitry Andric   // If this is a special C++ name without IdentifierInfo, it can't be a
860b57cec5SDimitry Andric   // C library function.
870b57cec5SDimitry Andric   if (!II)
880b57cec5SDimitry Andric     return false;
890b57cec5SDimitry Andric 
90*0fca6ea1SDimitry Andric   // C library functions are either declared directly within a TU (the common
91*0fca6ea1SDimitry Andric   // case) or they are accessed through the namespace `std` (when they are used
92*0fca6ea1SDimitry Andric   // in C++ via headers like <cstdlib>).
93*0fca6ea1SDimitry Andric   const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
94*0fca6ea1SDimitry Andric   if (!(DC->isTranslationUnit() || DC->isStdNamespace()))
950b57cec5SDimitry Andric     return false;
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   // If this function is not externally visible, it is not a C library function.
980b57cec5SDimitry Andric   // Note that we make an exception for inline functions, which may be
990b57cec5SDimitry Andric   // declared in header files without external linkage.
1000b57cec5SDimitry Andric   if (!FD->isInlined() && !FD->isExternallyVisible())
1010b57cec5SDimitry Andric     return false;
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   if (Name.empty())
1040b57cec5SDimitry Andric     return true;
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric   StringRef FName = II->getName();
107*0fca6ea1SDimitry Andric   if (FName == Name)
1080b57cec5SDimitry Andric     return true;
1090b57cec5SDimitry Andric 
1105f757f3fSDimitry Andric   if (FName.starts_with("__inline") && FName.contains(Name))
1110b57cec5SDimitry Andric     return true;
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   return false;
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
116*0fca6ea1SDimitry Andric bool CheckerContext::isHardenedVariantOf(const FunctionDecl *FD,
117*0fca6ea1SDimitry Andric                                          StringRef Name) {
118*0fca6ea1SDimitry Andric   const IdentifierInfo *II = FD->getIdentifier();
119*0fca6ea1SDimitry Andric   if (!II)
120*0fca6ea1SDimitry Andric     return false;
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric   auto CompletelyMatchesParts = [II](auto... Parts) -> bool {
123*0fca6ea1SDimitry Andric     StringRef FName = II->getName();
124*0fca6ea1SDimitry Andric     return (FName.consume_front(Parts) && ...) && FName.empty();
125*0fca6ea1SDimitry Andric   };
126*0fca6ea1SDimitry Andric 
127*0fca6ea1SDimitry Andric   return CompletelyMatchesParts("__", Name, "_chk") ||
128*0fca6ea1SDimitry Andric          CompletelyMatchesParts("__builtin_", "__", Name, "_chk");
129*0fca6ea1SDimitry Andric }
130*0fca6ea1SDimitry Andric 
1310b57cec5SDimitry Andric StringRef CheckerContext::getMacroNameOrSpelling(SourceLocation &Loc) {
1320b57cec5SDimitry Andric   if (Loc.isMacroID())
1330b57cec5SDimitry Andric     return Lexer::getImmediateMacroName(Loc, getSourceManager(),
1340b57cec5SDimitry Andric                                              getLangOpts());
135e8d8bef9SDimitry Andric   SmallString<16> buf;
1360b57cec5SDimitry Andric   return Lexer::getSpelling(Loc, buf, getSourceManager(), getLangOpts());
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric /// Evaluate comparison and return true if it's known that condition is true
1400b57cec5SDimitry Andric static bool evalComparison(SVal LHSVal, BinaryOperatorKind ComparisonOp,
1410b57cec5SDimitry Andric                            SVal RHSVal, ProgramStateRef State) {
1420b57cec5SDimitry Andric   if (LHSVal.isUnknownOrUndef())
1430b57cec5SDimitry Andric     return false;
1440b57cec5SDimitry Andric   ProgramStateManager &Mgr = State->getStateManager();
14581ad6265SDimitry Andric   if (!isa<NonLoc>(LHSVal)) {
1460b57cec5SDimitry Andric     LHSVal = Mgr.getStoreManager().getBinding(State->getStore(),
1470b57cec5SDimitry Andric                                               LHSVal.castAs<Loc>());
14881ad6265SDimitry Andric     if (LHSVal.isUnknownOrUndef() || !isa<NonLoc>(LHSVal))
1490b57cec5SDimitry Andric       return false;
1500b57cec5SDimitry Andric   }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   SValBuilder &Bldr = Mgr.getSValBuilder();
1530b57cec5SDimitry Andric   SVal Eval = Bldr.evalBinOp(State, ComparisonOp, LHSVal, RHSVal,
1540b57cec5SDimitry Andric                              Bldr.getConditionType());
1550b57cec5SDimitry Andric   if (Eval.isUnknownOrUndef())
1560b57cec5SDimitry Andric     return false;
1570b57cec5SDimitry Andric   ProgramStateRef StTrue, StFalse;
1580b57cec5SDimitry Andric   std::tie(StTrue, StFalse) = State->assume(Eval.castAs<DefinedSVal>());
1590b57cec5SDimitry Andric   return StTrue && !StFalse;
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric bool CheckerContext::isGreaterOrEqual(const Expr *E, unsigned long long Val) {
1630b57cec5SDimitry Andric   DefinedSVal V = getSValBuilder().makeIntVal(Val, getASTContext().LongLongTy);
1640b57cec5SDimitry Andric   return evalComparison(getSVal(E), BO_GE, V, getState());
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric bool CheckerContext::isNegative(const Expr *E) {
1680b57cec5SDimitry Andric   DefinedSVal V = getSValBuilder().makeIntVal(0, false);
1690b57cec5SDimitry Andric   return evalComparison(getSVal(E), BO_LT, V, getState());
1700b57cec5SDimitry Andric }
171