1 //===-- UncheckedOptionalAccessModel.h --------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines a dataflow analysis that detects unsafe uses of optional 10 // values. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_UNCHECKEDOPTIONALACCESSMODEL_H 15 #define CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_UNCHECKEDOPTIONALACCESSMODEL_H 16 17 #include "clang/AST/ASTContext.h" 18 #include "clang/Analysis/CFG.h" 19 #include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h" 20 #include "clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h" 21 #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" 22 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 23 #include "clang/Analysis/FlowSensitive/NoopLattice.h" 24 #include "clang/Basic/SourceLocation.h" 25 #include "llvm/ADT/SmallVector.h" 26 27 namespace clang { 28 namespace dataflow { 29 30 // FIXME: Explore using an allowlist-approach, where constructs supported by the 31 // analysis are always enabled and additional constructs are enabled through the 32 // `Options`. 33 struct UncheckedOptionalAccessModelOptions { 34 /// In generating diagnostics, ignore optionals reachable through overloaded 35 /// `operator*` or `operator->` (other than those of the optional type 36 /// itself). The analysis does not equate the results of such calls, so it 37 /// can't identify when their results are used safely (across calls), 38 /// resulting in false positives in all such cases. Note: this option does not 39 /// cover access through `operator[]`. 40 /// 41 /// FIXME: we now cache and equate the result of const accessors 42 /// that look like unique_ptr, have both `->` (returning a pointer type) and 43 /// `*` (returning a reference type). This includes mixing `->` and 44 /// `*` in a sequence of calls as long as the object is not modified. Once we 45 /// are confident in this const accessor caching, we shouldn't need the 46 /// IgnoreSmartPointerDereference option anymore. 47 bool IgnoreSmartPointerDereference = false; 48 }; 49 50 using UncheckedOptionalAccessLattice = CachedConstAccessorsLattice<NoopLattice>; 51 52 /// Dataflow analysis that models whether optionals hold values or not. 53 /// 54 /// Models the `std::optional`, `absl::optional`, and `base::Optional` types. 55 class UncheckedOptionalAccessModel 56 : public DataflowAnalysis<UncheckedOptionalAccessModel, 57 UncheckedOptionalAccessLattice> { 58 public: 59 UncheckedOptionalAccessModel(ASTContext &Ctx, dataflow::Environment &Env); 60 61 /// Returns a matcher for the optional classes covered by this model. 62 static ast_matchers::DeclarationMatcher optionalClassDecl(); 63 64 static UncheckedOptionalAccessLattice initialElement() { return {}; } 65 66 void transfer(const CFGElement &Elt, UncheckedOptionalAccessLattice &L, 67 Environment &Env); 68 69 private: 70 CFGMatchSwitch<TransferState<UncheckedOptionalAccessLattice>> 71 TransferMatchSwitch; 72 }; 73 74 class UncheckedOptionalAccessDiagnoser { 75 public: 76 UncheckedOptionalAccessDiagnoser( 77 UncheckedOptionalAccessModelOptions Options = {}); 78 79 llvm::SmallVector<SourceLocation> 80 operator()(const CFGElement &Elt, ASTContext &Ctx, 81 const TransferStateForDiagnostics<UncheckedOptionalAccessLattice> 82 &State) { 83 return DiagnoseMatchSwitch(Elt, Ctx, State.Env); 84 } 85 86 private: 87 CFGMatchSwitch<const Environment, llvm::SmallVector<SourceLocation>> 88 DiagnoseMatchSwitch; 89 }; 90 91 } // namespace dataflow 92 } // namespace clang 93 94 #endif // CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_UNCHECKEDOPTIONALACCESSMODEL_H 95