llvm/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

//===- BugReporterVisitors.cpp - Helpers for reporting bugs ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
//  This file defines a set of BugReporter "visitors" which can be used to
//  enhance the diagnostics reported for a bug.
//
//===----------------------------------------------------------------------===//

#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/Analyses/Dominators.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <deque>
#include <memory>
#include <optional>
#include <stack>
#include <string>
#include <utility>

usingnamespaceclang;
usingnamespaceento;
usingnamespacebugreporter;

//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//

static const Expr *peelOffPointerArithmetic(const BinaryOperator *B) {}

/// \return A subexpression of @c Ex which represents the
/// expression-of-interest.
static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N);

/// Given that expression S represents a pointer that would be dereferenced,
/// try to find a sub-expression from which the pointer came from.
/// This is used for tracking down origins of a null or undefined value:
/// "this is null because that is null because that is null" etc.
/// We wipe away field and element offsets because they merely add offsets.
/// We also wipe away all casts except lvalue-to-rvalue casts, because the
/// latter represent an actual pointer dereference; however, we remove
/// the final lvalue-to-rvalue cast before returning from this function
/// because it demonstrates more clearly from where the pointer rvalue was
/// loaded. Examples:
///   x->y.z      ==>  x (lvalue)
///   foo()->y.z  ==>  foo() (rvalue)
const Expr *bugreporter::getDerefExpr(const Stmt *S) {}

static const VarDecl *getVarDeclForExpression(const Expr *E) {}

static const MemRegion *
getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
                             bool LookingForReference = true) {}

/// Comparing internal representations of symbolic values (via
/// SVal::operator==()) is a valid way to check if the value was updated,
/// unless it's a LazyCompoundVal that may have a different internal
/// representation every time it is loaded from the state. In this function we
/// do an approximate comparison for lazy compound values, checking that they
/// are the immediate snapshots of the tracked region's bindings within the
/// node's respective states but not really checking that these snapshots
/// actually contain the same set of bindings.
static bool hasVisibleUpdate(const ExplodedNode *LeftNode, SVal LeftVal,
                             const ExplodedNode *RightNode, SVal RightVal) {}

static std::optional<SVal> getSValForVar(const Expr *CondVarExpr,
                                         const ExplodedNode *N) {}

static std::optional<const llvm::APSInt *>
getConcreteIntegerValue(const Expr *CondVarExpr, const ExplodedNode *N) {}

static bool isVarAnInterestingCondition(const Expr *CondVarExpr,
                                        const ExplodedNode *N,
                                        const PathSensitiveBugReport *B) {}

static bool isInterestingExpr(const Expr *E, const ExplodedNode *N,
                              const PathSensitiveBugReport *B) {}

/// \return name of the macro inside the location \p Loc.
static StringRef getMacroName(SourceLocation Loc,
    BugReporterContext &BRC) {}

/// \return Whether given spelling location corresponds to an expansion
/// of a function-like macro.
static bool isFunctionMacroExpansion(SourceLocation Loc,
                                const SourceManager &SM) {}

/// \return Whether \c RegionOfInterest was modified at \p N,
/// where \p ValueAfter is \c RegionOfInterest's value at the end of the
/// stack frame.
static bool wasRegionOfInterestModifiedAt(const SubRegion *RegionOfInterest,
                                          const ExplodedNode *N,
                                          SVal ValueAfter) {}

//===----------------------------------------------------------------------===//
// Implementation of BugReporterVisitor.
//===----------------------------------------------------------------------===//

PathDiagnosticPieceRef BugReporterVisitor::getEndPath(BugReporterContext &,
                                                      const ExplodedNode *,
                                                      PathSensitiveBugReport &) {}

void BugReporterVisitor::finalizeVisitor(BugReporterContext &,
                                         const ExplodedNode *,
                                         PathSensitiveBugReport &) {}

PathDiagnosticPieceRef
BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC,
                                      const ExplodedNode *EndPathNode,
                                      const PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// Implementation of NoStateChangeFuncVisitor.
//===----------------------------------------------------------------------===//

bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) {}

void NoStateChangeFuncVisitor::markFrameAsModifying(
    const StackFrameContext *SCtx) {}

static const ExplodedNode *getMatchingCallExitEnd(const ExplodedNode *N) {}

void NoStateChangeFuncVisitor::findModifyingFrames(
    const ExplodedNode *const CallExitBeginN) {}

PathDiagnosticPieceRef NoStateChangeFuncVisitor::VisitNode(
    const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) {}

//===----------------------------------------------------------------------===//
// Implementation of NoStoreFuncVisitor.
//===----------------------------------------------------------------------===//

namespace {
/// Put a diagnostic on return statement of all inlined functions
/// for which  the region of interest \p RegionOfInterest was passed into,
/// but not written inside, and it has caused an undefined read or a null
/// pointer dereference outside.
class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {};
} // namespace

/// \return Whether the method declaration \p Parent
/// syntactically has a binary operation writing into the ivar \p Ivar.
static bool potentiallyWritesIntoIvar(const Decl *Parent,
                                      const ObjCIvarDecl *Ivar) {}

/// Attempts to find the region of interest in a given CXX decl,
/// by either following the base classes or fields.
/// Dereferences fields up to a given recursion limit.
/// Note that \p Vec is passed by value, leading to quadratic copying cost,
/// but it's OK in practice since its length is limited to DEREFERENCE_LIMIT.
/// \return A chain fields leading to the region of interest or std::nullopt.
const std::optional<NoStoreFuncVisitor::RegionVector>
NoStoreFuncVisitor::findRegionOfInterestInRecord(
    const RecordDecl *RD, ProgramStateRef State, const MemRegion *R,
    const NoStoreFuncVisitor::RegionVector &Vec /* = {} */,
    int depth /* = 0 */) {}

PathDiagnosticPieceRef
NoStoreFuncVisitor::maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
                                             const ObjCMethodCall &Call,
                                             const ExplodedNode *N) {}

PathDiagnosticPieceRef
NoStoreFuncVisitor::maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
                                            const CXXConstructorCall &Call,
                                            const ExplodedNode *N) {}

/// \return whether \p Ty points to a const type, or is a const reference.
static bool isPointerToConst(QualType Ty) {}

PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNoteForParameters(
    PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N) {}

bool NoStoreFuncVisitor::wasModifiedBeforeCallExit(
    const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN) {}

static llvm::StringLiteral WillBeUsedForACondition =;

PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote(
    PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N,
    const RegionVector &FieldChain, const MemRegion *MatchedRegion,
    StringRef FirstElement, bool FirstIsReferenceType,
    unsigned IndirectionLevel) {}

bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector &FieldChain,
                                               const MemRegion *MatchedRegion,
                                               StringRef FirstElement,
                                               bool FirstIsReferenceType,
                                               unsigned IndirectionLevel,
                                               llvm::raw_svector_ostream &os) {}

StringRef NoStoreFuncVisitor::prettyPrintFirstElement(
    StringRef FirstElement, bool MoreItemsExpected, int IndirectionLevel,
    llvm::raw_svector_ostream &os) {}

//===----------------------------------------------------------------------===//
// Implementation of MacroNullReturnSuppressionVisitor.
//===----------------------------------------------------------------------===//

namespace {

/// Suppress null-pointer-dereference bugs where dereferenced null was returned
/// the macro.
class MacroNullReturnSuppressionVisitor final : public BugReporterVisitor {};

} // end of anonymous namespace

namespace {

/// Emits an extra note at the return statement of an interesting stack frame.
///
/// The returned value is marked as an interesting value, and if it's null,
/// adds a visitor to track where it became null.
///
/// This visitor is intended to be used when another visitor discovers that an
/// interesting value comes from an inlined function call.
class ReturnVisitor : public TrackingBugReporterVisitor {};

//===----------------------------------------------------------------------===//
//                               StoreSiteFinder
//===----------------------------------------------------------------------===//

/// Finds last store into the given region,
/// which is different from a given symbolic value.
class StoreSiteFinder final : public TrackingBugReporterVisitor {};
} // namespace

void StoreSiteFinder::Profile(llvm::FoldingSetNodeID &ID) const {}

/// Returns true if \p N represents the DeclStmt declaring and initializing
/// \p VR.
static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {}

static bool isObjCPointer(const MemRegion *R) {}

static bool isObjCPointer(const ValueDecl *D) {}

/// Show diagnostics for initializing or declaring a region \p R with a bad value.
static void showBRDiagnostics(llvm::raw_svector_ostream &OS, StoreInfo SI) {}

/// Display diagnostics for passing bad region as a parameter.
static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
                                   StoreInfo SI) {}

/// Show default diagnostics for storing bad region.
static void showBRDefaultDiagnostics(llvm::raw_svector_ostream &OS,
                                     StoreInfo SI) {}

static bool isTrivialCopyOrMoveCtor(const CXXConstructExpr *CE) {}

static const Expr *tryExtractInitializerFromList(const InitListExpr *ILE,
                                                 const MemRegion *R) {}

PathDiagnosticPieceRef StoreSiteFinder::VisitNode(const ExplodedNode *Succ,
                                                  BugReporterContext &BRC,
                                                  PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// Implementation of TrackConstraintBRVisitor.
//===----------------------------------------------------------------------===//

void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const {}

/// Return the tag associated with this visitor.  This tag will be used
/// to make all PathDiagnosticPieces created by this visitor.
const char *TrackConstraintBRVisitor::getTag() {}

bool TrackConstraintBRVisitor::isZeroCheck() const {}

bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {}

PathDiagnosticPieceRef TrackConstraintBRVisitor::VisitNode(
    const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &) {}

//===----------------------------------------------------------------------===//
// Implementation of SuppressInlineDefensiveChecksVisitor.
//===----------------------------------------------------------------------===//

SuppressInlineDefensiveChecksVisitor::
SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
    :{}

void SuppressInlineDefensiveChecksVisitor::Profile(
    llvm::FoldingSetNodeID &ID) const {}

const char *SuppressInlineDefensiveChecksVisitor::getTag() {}

PathDiagnosticPieceRef
SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
                                                BugReporterContext &BRC,
                                                PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// TrackControlDependencyCondBRVisitor.
//===----------------------------------------------------------------------===//

namespace {
/// Tracks the expressions that are a control dependency of the node that was
/// supplied to the constructor.
/// For example:
///
///   cond = 1;
///   if (cond)
///     10 / 0;
///
/// An error is emitted at line 3. This visitor realizes that the branch
/// on line 2 is a control dependency of line 3, and tracks it's condition via
/// trackExpressionValue().
class TrackControlDependencyCondBRVisitor final
    : public TrackingBugReporterVisitor {};
} // end of anonymous namespace

static std::shared_ptr<PathDiagnosticEventPiece>
constructDebugPieceForTrackedCondition(const Expr *Cond,
                                       const ExplodedNode *N,
                                       BugReporterContext &BRC) {}

static bool isAssertlikeBlock(const CFGBlock *B, ASTContext &Context) {}

PathDiagnosticPieceRef
TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
                                               BugReporterContext &BRC,
                                               PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// Implementation of trackExpressionValue.
//===----------------------------------------------------------------------===//

static const Expr *peelOffOuterExpr(const Expr *Ex, const ExplodedNode *N) {}

/// Find the ExplodedNode where the lvalue (the value of 'Ex')
/// was computed.
static const ExplodedNode* findNodeForExpression(const ExplodedNode *N,
                                                 const Expr *Inner) {}

//===----------------------------------------------------------------------===//
//                            Tracker implementation
//===----------------------------------------------------------------------===//

PathDiagnosticPieceRef StoreHandler::constructNote(StoreInfo SI,
                                                   BugReporterContext &BRC,
                                                   StringRef NodeText) {}

namespace {
class DefaultStoreHandler final : public StoreHandler {};

class ControlDependencyHandler final : public ExpressionHandler {};

class NilReceiverHandler final : public ExpressionHandler {};

class ArrayIndexHandler final : public ExpressionHandler {};

// TODO: extract it into more handlers
class InterestingLValueHandler final : public ExpressionHandler {};

/// Adds a ReturnVisitor if the given statement represents a call that was
/// inlined.
///
/// This will search back through the ExplodedGraph, starting from the given
/// node, looking for when the given statement was processed. If it turns out
/// the statement is a call that was inlined, we add the visitor to the
/// bug report, so it can print a note later.
class InlinedFunctionCallHandler final : public ExpressionHandler {};

class DefaultExpressionHandler final : public ExpressionHandler {};

/// Attempts to add visitors to track an RValue expression back to its point of
/// origin.
class PRValueHandler final : public ExpressionHandler {};
} // namespace

Tracker::Tracker(PathSensitiveBugReport &Report) :{}

Tracker::Result Tracker::track(const Expr *E, const ExplodedNode *N,
                               TrackingOptions Opts) {}

Tracker::Result Tracker::track(SVal V, const MemRegion *R, TrackingOptions Opts,
                               const StackFrameContext *Origin) {}

PathDiagnosticPieceRef Tracker::handle(StoreInfo SI, BugReporterContext &BRC,
                                       TrackingOptions Opts) {}

bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode,
                                       const Expr *E,

                                       PathSensitiveBugReport &Report,
                                       TrackingOptions Opts) {}

void bugreporter::trackStoredValue(SVal V, const MemRegion *R,
                                   PathSensitiveBugReport &Report,
                                   TrackingOptions Opts,
                                   const StackFrameContext *Origin) {}

//===----------------------------------------------------------------------===//
// Implementation of NulReceiverBRVisitor.
//===----------------------------------------------------------------------===//

const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
                                                 const ExplodedNode *N) {}

PathDiagnosticPieceRef
NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
                                PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// Visitor that tries to report interesting diagnostics from conditions.
//===----------------------------------------------------------------------===//

/// Return the tag associated with this visitor.  This tag will be used
/// to make all PathDiagnosticPieces created by this visitor.
const char *ConditionBRVisitor::getTag() {}

PathDiagnosticPieceRef
ConditionBRVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
                              PathSensitiveBugReport &BR) {}

PathDiagnosticPieceRef
ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
                                  BugReporterContext &BRC,
                                  PathSensitiveBugReport &BR) {}

PathDiagnosticPieceRef ConditionBRVisitor::VisitTerminator(
    const Stmt *Term, const ExplodedNode *N, const CFGBlock *srcBlk,
    const CFGBlock *dstBlk, PathSensitiveBugReport &R,
    BugReporterContext &BRC) {}

PathDiagnosticPieceRef
ConditionBRVisitor::VisitTrueTest(const Expr *Cond, BugReporterContext &BRC,
                                  PathSensitiveBugReport &R,
                                  const ExplodedNode *N, bool TookTrue) {}

bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *ParentEx,
                                      raw_ostream &Out, BugReporterContext &BRC,
                                      PathSensitiveBugReport &report,
                                      const ExplodedNode *N,
                                      std::optional<bool> &prunable,
                                      bool IsSameFieldName) {}

PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
    const Expr *Cond, const BinaryOperator *BExpr, BugReporterContext &BRC,
    PathSensitiveBugReport &R, const ExplodedNode *N, bool TookTrue,
    bool IsAssuming) {}

PathDiagnosticPieceRef ConditionBRVisitor::VisitConditionVariable(
    StringRef LhsString, const Expr *CondVarExpr, BugReporterContext &BRC,
    PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue) {}

PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
    const Expr *Cond, const DeclRefExpr *DRE, BugReporterContext &BRC,
    PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
    bool IsAssuming) {}

PathDiagnosticPieceRef ConditionBRVisitor::VisitTrueTest(
    const Expr *Cond, const MemberExpr *ME, BugReporterContext &BRC,
    PathSensitiveBugReport &report, const ExplodedNode *N, bool TookTrue,
    bool IsAssuming) {}

bool ConditionBRVisitor::printValue(const Expr *CondVarExpr, raw_ostream &Out,
                                    const ExplodedNode *N, bool TookTrue,
                                    bool IsAssuming) {}

constexpr llvm::StringLiteral ConditionBRVisitor::GenericTrueMessage;
constexpr llvm::StringLiteral ConditionBRVisitor::GenericFalseMessage;

bool ConditionBRVisitor::isPieceMessageGeneric(
    const PathDiagnosticPiece *Piece) {}

//===----------------------------------------------------------------------===//
// Implementation of LikelyFalsePositiveSuppressionBRVisitor.
//===----------------------------------------------------------------------===//

void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
    BugReporterContext &BRC, const ExplodedNode *N,
    PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// Implementation of UndefOrNullArgVisitor.
//===----------------------------------------------------------------------===//

PathDiagnosticPieceRef
UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
                                 PathSensitiveBugReport &BR) {}

//===----------------------------------------------------------------------===//
// Implementation of TagVisitor.
//===----------------------------------------------------------------------===//

int NoteTag::Kind =;

void TagVisitor::Profile(llvm::FoldingSetNodeID &ID) const {}

PathDiagnosticPieceRef TagVisitor::VisitNode(const ExplodedNode *N,
                                             BugReporterContext &BRC,
                                             PathSensitiveBugReport &R) {}