| 1 | //=======- RawPtrRefSafetyModel.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 | #ifndef LLVM_CLANG_ANALYZER_WEBKIT_RAWPTRREFSAFETYMODEL_H |
| 10 | #define LLVM_CLANG_ANALYZER_WEBKIT_RAWPTRREFSAFETYMODEL_H |
| 11 | |
| 12 | #include "DiagOutputUtils.h" |
| 13 | #include "PtrTypesSemantics.h" |
| 14 | #include "clang/AST/Type.h" |
| 15 | #include "llvm/Support/raw_ostream.h" |
| 16 | #include <memory> |
| 17 | #include <optional> |
| 18 | #include <string> |
| 19 | |
| 20 | namespace clang { |
| 21 | class CXXRecordDecl; |
| 22 | class Decl; |
| 23 | class Expr; |
| 24 | class QualType; |
| 25 | class SourceManager; |
| 26 | |
| 27 | /// Models one WebKit pointer-safety policy: ref-counted (RefPtr), checked |
| 28 | /// (CheckedPtr), or retainable (RetainPtr/OSPtr). |
| 29 | /// |
| 30 | /// It captures the family-specific "what is a safe/unsafe pointer" questions |
| 31 | /// that are shared by the various RawPtrRef* checkers, independently of how |
| 32 | /// each checker traverses the AST (call arguments, local variables, members, |
| 33 | /// lambda captures, ...). This lets a single policy be defined once and reused |
| 34 | /// across every traversal. |
| 35 | class PtrRefSafetyModel { |
| 36 | public: |
| 37 | virtual ~PtrRefSafetyModel() = default; |
| 38 | |
| 39 | /// \returns whether \p QT itself is an unsafe (smart-pointer-capable but not |
| 40 | /// managed) type, false if not, std::nullopt if inconclusive. |
| 41 | virtual std::optional<bool> isUnsafeType(QualType QT) const = 0; |
| 42 | |
| 43 | /// \returns whether \p QT is a pointer/reference/view to an analyzed type, |
| 44 | /// false if not, std::nullopt if inconclusive. \p IgnoreARC requests that |
| 45 | /// Objective-C ARC be ignored when deciding retainability. |
| 46 | virtual std::optional<bool> isUnsafePtr(QualType QT, |
| 47 | bool IgnoreARC = false) const = 0; |
| 48 | |
| 49 | /// \returns whether \p Record is a safe smart pointer for this policy. |
| 50 | virtual bool isSafePtr(const CXXRecordDecl *Record) const = 0; |
| 51 | |
| 52 | /// \returns whether \p T is a safe smart pointer type for this policy. |
| 53 | virtual bool isSafePtrType(QualType T) const = 0; |
| 54 | |
| 55 | /// \returns whether \p Name is the name of a safe smart pointer class for |
| 56 | /// this policy. |
| 57 | virtual bool isPtrType(const std::string &Name) const = 0; |
| 58 | |
| 59 | /// \returns whether \p Origin is known to produce a safe value for this |
| 60 | /// policy. \p PtrIsLifetimeBoundToOrigin is whether the traversal that |
| 61 | /// reached \p Origin followed at least one [[clang::lifetimebound]] edge. |
| 62 | /// \p SinkType is the type of the variable or parameter that receives the |
| 63 | /// value, if known. \p SinkMayEscape is whether the receiving location may |
| 64 | /// outlive the scope that encloses \p Origin, as an escaping lambda capture |
| 65 | /// does. |
| 66 | virtual bool isSafeExpr(const Expr *Origin, bool PtrIsLifetimeBoundToOrigin, |
| 67 | QualType SinkType, bool SinkMayEscape) const { |
| 68 | return false; |
| 69 | } |
| 70 | |
| 71 | /// \returns whether this policy checks for destruction of an object's |
| 72 | /// interior while the object itself stays alive (borrow checking), rather |
| 73 | /// than for deallocation of the object (the smart pointer policies). |
| 74 | virtual bool checksForInteriorDestruction() const { return false; } |
| 75 | |
| 76 | /// \returns whether this policy checks assignment through indirection, such |
| 77 | /// as *out = _ or arr[0] = _. (Direct assignment to a named variable is |
| 78 | /// always checked.) |
| 79 | /// |
| 80 | /// FIXME: Make this flag true in all analyses and then remove it. |
| 81 | virtual bool recognizesIndirectStores() const { return false; } |
| 82 | |
| 83 | /// \returns whether \p D refers to a declaration that is safe by construction |
| 84 | /// for this policy (e.g. immortal system-header globals). |
| 85 | virtual bool isSafeDecl(const Decl *, const SourceManager &) const { |
| 86 | return false; |
| 87 | } |
| 88 | |
| 89 | /// \returns a human readable name for the safe type category, used in |
| 90 | /// diagnostics (e.g. "RefPtr-capable type"). |
| 91 | virtual const char *typeName() const = 0; |
| 92 | |
| 93 | /// Prints a phrase describing why the reported value is unsafe, completing a |
| 94 | /// sentence of the form "Local variable 'x' is a ". \p Origin is the |
| 95 | /// expression the value was traced back to, or null when the trace found |
| 96 | /// none. \p SinkType is the type of the reported location. |
| 97 | virtual void describeHazard(llvm::raw_ostream &Os, const Expr *, |
| 98 | QualType SinkType) const { |
| 99 | auto *VarType = SinkType.getTypePtr(); |
| 100 | auto *DesugaredType = VarType->getUnqualifiedDesugaredType(); |
| 101 | bool IsPtr = isa<PointerType, ObjCObjectPointerType>(Val: DesugaredType); |
| 102 | Os << "raw " << (IsPtr ? "pointer" : "reference" ) << " to " ; |
| 103 | Os << typeName() << " " ; |
| 104 | printTypeName(Os, QT: SinkType); |
| 105 | } |
| 106 | |
| 107 | /// \returns the RetainTypeChecker backing this policy, or nullptr if the |
| 108 | /// policy does not track retain/OS types. |
| 109 | virtual RetainTypeChecker *retainTypeChecker() const { return nullptr; } |
| 110 | }; |
| 111 | |
| 112 | /// Applies the memory-management exemptions that hold for a variable, member, |
| 113 | /// or lambda capture (but not for a call argument) before consulting \p Model: |
| 114 | /// a __strong / __weak Objective-C storage location is memory managed and thus |
| 115 | /// safe. \returns whether \p T is an unsafe pointer in such a storage context. |
| 116 | std::optional<bool> isUnsafePtrForStorage(const PtrRefSafetyModel &Model, |
| 117 | QualType T, bool IgnoreARC = false); |
| 118 | |
| 119 | /// \returns a policy that treats ref-counted / checked pointers as safe. |
| 120 | std::unique_ptr<PtrRefSafetyModel> makeRefPtrSafetyModel(); |
| 121 | |
| 122 | /// \returns a policy that treats checked pointers as safe. |
| 123 | std::unique_ptr<PtrRefSafetyModel> makeCheckedPtrSafetyModel(); |
| 124 | |
| 125 | /// \returns a policy that treats RetainPtr / OSPtr as safe. |
| 126 | std::unique_ptr<PtrRefSafetyModel> makeRetainPtrSafetyModel(); |
| 127 | |
| 128 | /// \returns a policy that treats a loan on a CanBorrow object's interior as |
| 129 | /// safe only when it is guarded by const or a Borrow<T>. |
| 130 | std::unique_ptr<PtrRefSafetyModel> makeBorrowSafetyModel(); |
| 131 | |
| 132 | } // namespace clang |
| 133 | |
| 134 | #endif |
| 135 | |