| File: | clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp |
| Warning: | line 1453, column 17 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | //= CStringChecker.cpp - Checks calls to C string functions --------*- 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 defines CStringChecker, which is an assortment of checks on calls | ||||||||||||
| 10 | // to functions in <string.h>. | ||||||||||||
| 11 | // | ||||||||||||
| 12 | //===----------------------------------------------------------------------===// | ||||||||||||
| 13 | |||||||||||||
| 14 | #include "InterCheckerAPI.h" | ||||||||||||
| 15 | #include "clang/Basic/CharInfo.h" | ||||||||||||
| 16 | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" | ||||||||||||
| 17 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | ||||||||||||
| 18 | #include "clang/StaticAnalyzer/Core/Checker.h" | ||||||||||||
| 19 | #include "clang/StaticAnalyzer/Core/CheckerManager.h" | ||||||||||||
| 20 | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | ||||||||||||
| 21 | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | ||||||||||||
| 22 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" | ||||||||||||
| 23 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" | ||||||||||||
| 24 | #include "llvm/ADT/STLExtras.h" | ||||||||||||
| 25 | #include "llvm/ADT/SmallString.h" | ||||||||||||
| 26 | #include "llvm/ADT/StringExtras.h" | ||||||||||||
| 27 | #include "llvm/Support/raw_ostream.h" | ||||||||||||
| 28 | |||||||||||||
| 29 | using namespace clang; | ||||||||||||
| 30 | using namespace ento; | ||||||||||||
| 31 | |||||||||||||
| 32 | namespace { | ||||||||||||
| 33 | struct AnyArgExpr { | ||||||||||||
| 34 | // FIXME: Remove constructor in C++17 to turn it into an aggregate. | ||||||||||||
| 35 | AnyArgExpr(const Expr *Expression, unsigned ArgumentIndex) | ||||||||||||
| 36 | : Expression{Expression}, ArgumentIndex{ArgumentIndex} {} | ||||||||||||
| 37 | const Expr *Expression; | ||||||||||||
| 38 | unsigned ArgumentIndex; | ||||||||||||
| 39 | }; | ||||||||||||
| 40 | |||||||||||||
| 41 | struct SourceArgExpr : AnyArgExpr { | ||||||||||||
| 42 | using AnyArgExpr::AnyArgExpr; // FIXME: Remove using in C++17. | ||||||||||||
| 43 | }; | ||||||||||||
| 44 | |||||||||||||
| 45 | struct DestinationArgExpr : AnyArgExpr { | ||||||||||||
| 46 | using AnyArgExpr::AnyArgExpr; // FIXME: Same. | ||||||||||||
| 47 | }; | ||||||||||||
| 48 | |||||||||||||
| 49 | struct SizeArgExpr : AnyArgExpr { | ||||||||||||
| 50 | using AnyArgExpr::AnyArgExpr; // FIXME: Same. | ||||||||||||
| 51 | }; | ||||||||||||
| 52 | |||||||||||||
| 53 | using ErrorMessage = SmallString<128>; | ||||||||||||
| 54 | enum class AccessKind { write, read }; | ||||||||||||
| 55 | |||||||||||||
| 56 | static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription, | ||||||||||||
| 57 | AccessKind Access) { | ||||||||||||
| 58 | ErrorMessage Message; | ||||||||||||
| 59 | llvm::raw_svector_ostream Os(Message); | ||||||||||||
| 60 | |||||||||||||
| 61 | // Function classification like: Memory copy function | ||||||||||||
| 62 | Os << toUppercase(FunctionDescription.front()) | ||||||||||||
| 63 | << &FunctionDescription.data()[1]; | ||||||||||||
| 64 | |||||||||||||
| 65 | if (Access == AccessKind::write) { | ||||||||||||
| 66 | Os << " overflows the destination buffer"; | ||||||||||||
| 67 | } else { // read access | ||||||||||||
| 68 | Os << " accesses out-of-bound array element"; | ||||||||||||
| 69 | } | ||||||||||||
| 70 | |||||||||||||
| 71 | return Message; | ||||||||||||
| 72 | } | ||||||||||||
| 73 | |||||||||||||
| 74 | enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 }; | ||||||||||||
| 75 | class CStringChecker : public Checker< eval::Call, | ||||||||||||
| 76 | check::PreStmt<DeclStmt>, | ||||||||||||
| 77 | check::LiveSymbols, | ||||||||||||
| 78 | check::DeadSymbols, | ||||||||||||
| 79 | check::RegionChanges | ||||||||||||
| 80 | > { | ||||||||||||
| 81 | mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, | ||||||||||||
| 82 | BT_NotCString, BT_AdditionOverflow; | ||||||||||||
| 83 | |||||||||||||
| 84 | mutable const char *CurrentFunctionDescription; | ||||||||||||
| 85 | |||||||||||||
| 86 | public: | ||||||||||||
| 87 | /// The filter is used to filter out the diagnostics which are not enabled by | ||||||||||||
| 88 | /// the user. | ||||||||||||
| 89 | struct CStringChecksFilter { | ||||||||||||
| 90 | DefaultBool CheckCStringNullArg; | ||||||||||||
| 91 | DefaultBool CheckCStringOutOfBounds; | ||||||||||||
| 92 | DefaultBool CheckCStringBufferOverlap; | ||||||||||||
| 93 | DefaultBool CheckCStringNotNullTerm; | ||||||||||||
| 94 | |||||||||||||
| 95 | CheckerNameRef CheckNameCStringNullArg; | ||||||||||||
| 96 | CheckerNameRef CheckNameCStringOutOfBounds; | ||||||||||||
| 97 | CheckerNameRef CheckNameCStringBufferOverlap; | ||||||||||||
| 98 | CheckerNameRef CheckNameCStringNotNullTerm; | ||||||||||||
| 99 | }; | ||||||||||||
| 100 | |||||||||||||
| 101 | CStringChecksFilter Filter; | ||||||||||||
| 102 | |||||||||||||
| 103 | static void *getTag() { static int tag; return &tag; } | ||||||||||||
| 104 | |||||||||||||
| 105 | bool evalCall(const CallEvent &Call, CheckerContext &C) const; | ||||||||||||
| 106 | void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; | ||||||||||||
| 107 | void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const; | ||||||||||||
| 108 | void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; | ||||||||||||
| 109 | |||||||||||||
| 110 | ProgramStateRef | ||||||||||||
| 111 | checkRegionChanges(ProgramStateRef state, | ||||||||||||
| 112 | const InvalidatedSymbols *, | ||||||||||||
| 113 | ArrayRef<const MemRegion *> ExplicitRegions, | ||||||||||||
| 114 | ArrayRef<const MemRegion *> Regions, | ||||||||||||
| 115 | const LocationContext *LCtx, | ||||||||||||
| 116 | const CallEvent *Call) const; | ||||||||||||
| 117 | |||||||||||||
| 118 | typedef void (CStringChecker::*FnCheck)(CheckerContext &, | ||||||||||||
| 119 | const CallExpr *) const; | ||||||||||||
| 120 | CallDescriptionMap<FnCheck> Callbacks = { | ||||||||||||
| 121 | {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy}, | ||||||||||||
| 122 | {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy}, | ||||||||||||
| 123 | {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp}, | ||||||||||||
| 124 | {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove}, | ||||||||||||
| 125 | {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset}, | ||||||||||||
| 126 | {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset}, | ||||||||||||
| 127 | {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy}, | ||||||||||||
| 128 | {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy}, | ||||||||||||
| 129 | {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy}, | ||||||||||||
| 130 | {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy}, | ||||||||||||
| 131 | {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat}, | ||||||||||||
| 132 | {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat}, | ||||||||||||
| 133 | {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat}, | ||||||||||||
| 134 | {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength}, | ||||||||||||
| 135 | {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength}, | ||||||||||||
| 136 | {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp}, | ||||||||||||
| 137 | {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp}, | ||||||||||||
| 138 | {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp}, | ||||||||||||
| 139 | {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp}, | ||||||||||||
| 140 | {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep}, | ||||||||||||
| 141 | {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy}, | ||||||||||||
| 142 | {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp}, | ||||||||||||
| 143 | {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero}, | ||||||||||||
| 144 | {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero}, | ||||||||||||
| 145 | }; | ||||||||||||
| 146 | |||||||||||||
| 147 | // These require a bit of special handling. | ||||||||||||
| 148 | CallDescription StdCopy{{"std", "copy"}, 3}, | ||||||||||||
| 149 | StdCopyBackward{{"std", "copy_backward"}, 3}; | ||||||||||||
| 150 | |||||||||||||
| 151 | FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const; | ||||||||||||
| 152 | void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 153 | void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 154 | void evalMemmove(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 155 | void evalBcopy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 156 | void evalCopyCommon(CheckerContext &C, const CallExpr *CE, | ||||||||||||
| 157 | ProgramStateRef state, SizeArgExpr Size, | ||||||||||||
| 158 | DestinationArgExpr Dest, SourceArgExpr Source, | ||||||||||||
| 159 | bool Restricted, bool IsMempcpy) const; | ||||||||||||
| 160 | |||||||||||||
| 161 | void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 162 | |||||||||||||
| 163 | void evalstrLength(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 164 | void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 165 | void evalstrLengthCommon(CheckerContext &C, | ||||||||||||
| 166 | const CallExpr *CE, | ||||||||||||
| 167 | bool IsStrnlen = false) const; | ||||||||||||
| 168 | |||||||||||||
| 169 | void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 170 | void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 171 | void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 172 | void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 173 | void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd, | ||||||||||||
| 174 | bool IsBounded, ConcatFnKind appendK, | ||||||||||||
| 175 | bool returnPtr = true) const; | ||||||||||||
| 176 | |||||||||||||
| 177 | void evalStrcat(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 178 | void evalStrncat(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 179 | void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 180 | |||||||||||||
| 181 | void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 182 | void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 183 | void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 184 | void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 185 | void evalStrcmpCommon(CheckerContext &C, | ||||||||||||
| 186 | const CallExpr *CE, | ||||||||||||
| 187 | bool IsBounded = false, | ||||||||||||
| 188 | bool IgnoreCase = false) const; | ||||||||||||
| 189 | |||||||||||||
| 190 | void evalStrsep(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 191 | |||||||||||||
| 192 | void evalStdCopy(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 193 | void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 194 | void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 195 | void evalMemset(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 196 | void evalBzero(CheckerContext &C, const CallExpr *CE) const; | ||||||||||||
| 197 | |||||||||||||
| 198 | // Utility methods | ||||||||||||
| 199 | std::pair<ProgramStateRef , ProgramStateRef > | ||||||||||||
| 200 | static assumeZero(CheckerContext &C, | ||||||||||||
| 201 | ProgramStateRef state, SVal V, QualType Ty); | ||||||||||||
| 202 | |||||||||||||
| 203 | static ProgramStateRef setCStringLength(ProgramStateRef state, | ||||||||||||
| 204 | const MemRegion *MR, | ||||||||||||
| 205 | SVal strLength); | ||||||||||||
| 206 | static SVal getCStringLengthForRegion(CheckerContext &C, | ||||||||||||
| 207 | ProgramStateRef &state, | ||||||||||||
| 208 | const Expr *Ex, | ||||||||||||
| 209 | const MemRegion *MR, | ||||||||||||
| 210 | bool hypothetical); | ||||||||||||
| 211 | SVal getCStringLength(CheckerContext &C, | ||||||||||||
| 212 | ProgramStateRef &state, | ||||||||||||
| 213 | const Expr *Ex, | ||||||||||||
| 214 | SVal Buf, | ||||||||||||
| 215 | bool hypothetical = false) const; | ||||||||||||
| 216 | |||||||||||||
| 217 | const StringLiteral *getCStringLiteral(CheckerContext &C, | ||||||||||||
| 218 | ProgramStateRef &state, | ||||||||||||
| 219 | const Expr *expr, | ||||||||||||
| 220 | SVal val) const; | ||||||||||||
| 221 | |||||||||||||
| 222 | static ProgramStateRef InvalidateBuffer(CheckerContext &C, | ||||||||||||
| 223 | ProgramStateRef state, | ||||||||||||
| 224 | const Expr *Ex, SVal V, | ||||||||||||
| 225 | bool IsSourceBuffer, | ||||||||||||
| 226 | const Expr *Size); | ||||||||||||
| 227 | |||||||||||||
| 228 | static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, | ||||||||||||
| 229 | const MemRegion *MR); | ||||||||||||
| 230 | |||||||||||||
| 231 | static bool memsetAux(const Expr *DstBuffer, SVal CharE, | ||||||||||||
| 232 | const Expr *Size, CheckerContext &C, | ||||||||||||
| 233 | ProgramStateRef &State); | ||||||||||||
| 234 | |||||||||||||
| 235 | // Re-usable checks | ||||||||||||
| 236 | ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State, | ||||||||||||
| 237 | AnyArgExpr Arg, SVal l) const; | ||||||||||||
| 238 | ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state, | ||||||||||||
| 239 | AnyArgExpr Buffer, SVal Element, | ||||||||||||
| 240 | AccessKind Access) const; | ||||||||||||
| 241 | ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State, | ||||||||||||
| 242 | AnyArgExpr Buffer, SizeArgExpr Size, | ||||||||||||
| 243 | AccessKind Access) const; | ||||||||||||
| 244 | ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state, | ||||||||||||
| 245 | SizeArgExpr Size, AnyArgExpr First, | ||||||||||||
| 246 | AnyArgExpr Second) const; | ||||||||||||
| 247 | void emitOverlapBug(CheckerContext &C, | ||||||||||||
| 248 | ProgramStateRef state, | ||||||||||||
| 249 | const Stmt *First, | ||||||||||||
| 250 | const Stmt *Second) const; | ||||||||||||
| 251 | |||||||||||||
| 252 | void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, | ||||||||||||
| 253 | StringRef WarningMsg) const; | ||||||||||||
| 254 | void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State, | ||||||||||||
| 255 | const Stmt *S, StringRef WarningMsg) const; | ||||||||||||
| 256 | void emitNotCStringBug(CheckerContext &C, ProgramStateRef State, | ||||||||||||
| 257 | const Stmt *S, StringRef WarningMsg) const; | ||||||||||||
| 258 | void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const; | ||||||||||||
| 259 | |||||||||||||
| 260 | ProgramStateRef checkAdditionOverflow(CheckerContext &C, | ||||||||||||
| 261 | ProgramStateRef state, | ||||||||||||
| 262 | NonLoc left, | ||||||||||||
| 263 | NonLoc right) const; | ||||||||||||
| 264 | |||||||||||||
| 265 | // Return true if the destination buffer of the copy function may be in bound. | ||||||||||||
| 266 | // Expects SVal of Size to be positive and unsigned. | ||||||||||||
| 267 | // Expects SVal of FirstBuf to be a FieldRegion. | ||||||||||||
| 268 | static bool IsFirstBufInBound(CheckerContext &C, | ||||||||||||
| 269 | ProgramStateRef state, | ||||||||||||
| 270 | const Expr *FirstBuf, | ||||||||||||
| 271 | const Expr *Size); | ||||||||||||
| 272 | }; | ||||||||||||
| 273 | |||||||||||||
| 274 | } //end anonymous namespace | ||||||||||||
| 275 | |||||||||||||
| 276 | REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)namespace { class CStringLength {}; using CStringLengthTy = llvm ::ImmutableMap<const MemRegion *, SVal>; } namespace clang { namespace ento { template <> struct ProgramStateTrait <CStringLength> : public ProgramStatePartialTrait<CStringLengthTy > { static void *GDMIndex() { static int Index; return & Index; } }; } } | ||||||||||||
| 277 | |||||||||||||
| 278 | //===----------------------------------------------------------------------===// | ||||||||||||
| 279 | // Individual checks and utility methods. | ||||||||||||
| 280 | //===----------------------------------------------------------------------===// | ||||||||||||
| 281 | |||||||||||||
| 282 | std::pair<ProgramStateRef , ProgramStateRef > | ||||||||||||
| 283 | CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, | ||||||||||||
| 284 | QualType Ty) { | ||||||||||||
| 285 | Optional<DefinedSVal> val = V.getAs<DefinedSVal>(); | ||||||||||||
| 286 | if (!val) | ||||||||||||
| 287 | return std::pair<ProgramStateRef , ProgramStateRef >(state, state); | ||||||||||||
| 288 | |||||||||||||
| 289 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 290 | DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); | ||||||||||||
| 291 | return state->assume(svalBuilder.evalEQ(state, *val, zero)); | ||||||||||||
| 292 | } | ||||||||||||
| 293 | |||||||||||||
| 294 | ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, | ||||||||||||
| 295 | ProgramStateRef State, | ||||||||||||
| 296 | AnyArgExpr Arg, SVal l) const { | ||||||||||||
| 297 | // If a previous check has failed, propagate the failure. | ||||||||||||
| 298 | if (!State) | ||||||||||||
| 299 | return nullptr; | ||||||||||||
| 300 | |||||||||||||
| 301 | ProgramStateRef stateNull, stateNonNull; | ||||||||||||
| 302 | std::tie(stateNull, stateNonNull) = | ||||||||||||
| 303 | assumeZero(C, State, l, Arg.Expression->getType()); | ||||||||||||
| 304 | |||||||||||||
| 305 | if (stateNull && !stateNonNull) { | ||||||||||||
| 306 | if (Filter.CheckCStringNullArg) { | ||||||||||||
| 307 | SmallString<80> buf; | ||||||||||||
| 308 | llvm::raw_svector_ostream OS(buf); | ||||||||||||
| 309 | assert(CurrentFunctionDescription)(static_cast <bool> (CurrentFunctionDescription) ? void (0) : __assert_fail ("CurrentFunctionDescription", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 309, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 310 | OS << "Null pointer passed as " << (Arg.ArgumentIndex + 1) | ||||||||||||
| 311 | << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) << " argument to " | ||||||||||||
| 312 | << CurrentFunctionDescription; | ||||||||||||
| 313 | |||||||||||||
| 314 | emitNullArgBug(C, stateNull, Arg.Expression, OS.str()); | ||||||||||||
| 315 | } | ||||||||||||
| 316 | return nullptr; | ||||||||||||
| 317 | } | ||||||||||||
| 318 | |||||||||||||
| 319 | // From here on, assume that the value is non-null. | ||||||||||||
| 320 | assert(stateNonNull)(static_cast <bool> (stateNonNull) ? void (0) : __assert_fail ("stateNonNull", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 320, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 321 | return stateNonNull; | ||||||||||||
| 322 | } | ||||||||||||
| 323 | |||||||||||||
| 324 | // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? | ||||||||||||
| 325 | ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, | ||||||||||||
| 326 | ProgramStateRef state, | ||||||||||||
| 327 | AnyArgExpr Buffer, SVal Element, | ||||||||||||
| 328 | AccessKind Access) const { | ||||||||||||
| 329 | |||||||||||||
| 330 | // If a previous check has failed, propagate the failure. | ||||||||||||
| 331 | if (!state) | ||||||||||||
| 332 | return nullptr; | ||||||||||||
| 333 | |||||||||||||
| 334 | // Check for out of bound array element access. | ||||||||||||
| 335 | const MemRegion *R = Element.getAsRegion(); | ||||||||||||
| 336 | if (!R) | ||||||||||||
| 337 | return state; | ||||||||||||
| 338 | |||||||||||||
| 339 | const auto *ER = dyn_cast<ElementRegion>(R); | ||||||||||||
| 340 | if (!ER) | ||||||||||||
| 341 | return state; | ||||||||||||
| 342 | |||||||||||||
| 343 | if (ER->getValueType() != C.getASTContext().CharTy) | ||||||||||||
| 344 | return state; | ||||||||||||
| 345 | |||||||||||||
| 346 | // Get the size of the array. | ||||||||||||
| 347 | const auto *superReg = cast<SubRegion>(ER->getSuperRegion()); | ||||||||||||
| 348 | DefinedOrUnknownSVal Size = | ||||||||||||
| 349 | getDynamicExtent(state, superReg, C.getSValBuilder()); | ||||||||||||
| 350 | |||||||||||||
| 351 | // Get the index of the accessed element. | ||||||||||||
| 352 | DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 353 | |||||||||||||
| 354 | ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); | ||||||||||||
| 355 | ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); | ||||||||||||
| 356 | if (StOutBound && !StInBound) { | ||||||||||||
| 357 | // These checks are either enabled by the CString out-of-bounds checker | ||||||||||||
| 358 | // explicitly or implicitly by the Malloc checker. | ||||||||||||
| 359 | // In the latter case we only do modeling but do not emit warning. | ||||||||||||
| 360 | if (!Filter.CheckCStringOutOfBounds) | ||||||||||||
| 361 | return nullptr; | ||||||||||||
| 362 | |||||||||||||
| 363 | // Emit a bug report. | ||||||||||||
| 364 | ErrorMessage Message = | ||||||||||||
| 365 | createOutOfBoundErrorMsg(CurrentFunctionDescription, Access); | ||||||||||||
| 366 | emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message); | ||||||||||||
| 367 | return nullptr; | ||||||||||||
| 368 | } | ||||||||||||
| 369 | |||||||||||||
| 370 | // Array bound check succeeded. From this point forward the array bound | ||||||||||||
| 371 | // should always succeed. | ||||||||||||
| 372 | return StInBound; | ||||||||||||
| 373 | } | ||||||||||||
| 374 | |||||||||||||
| 375 | ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, | ||||||||||||
| 376 | ProgramStateRef State, | ||||||||||||
| 377 | AnyArgExpr Buffer, | ||||||||||||
| 378 | SizeArgExpr Size, | ||||||||||||
| 379 | AccessKind Access) const { | ||||||||||||
| 380 | // If a previous check has failed, propagate the failure. | ||||||||||||
| 381 | if (!State) | ||||||||||||
| 382 | return nullptr; | ||||||||||||
| 383 | |||||||||||||
| 384 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 385 | ASTContext &Ctx = svalBuilder.getContext(); | ||||||||||||
| 386 | |||||||||||||
| 387 | QualType SizeTy = Size.Expression->getType(); | ||||||||||||
| 388 | QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); | ||||||||||||
| 389 | |||||||||||||
| 390 | // Check that the first buffer is non-null. | ||||||||||||
| 391 | SVal BufVal = C.getSVal(Buffer.Expression); | ||||||||||||
| 392 | State = checkNonNull(C, State, Buffer, BufVal); | ||||||||||||
| 393 | if (!State) | ||||||||||||
| 394 | return nullptr; | ||||||||||||
| 395 | |||||||||||||
| 396 | // If out-of-bounds checking is turned off, skip the rest. | ||||||||||||
| 397 | if (!Filter.CheckCStringOutOfBounds) | ||||||||||||
| 398 | return State; | ||||||||||||
| 399 | |||||||||||||
| 400 | // Get the access length and make sure it is known. | ||||||||||||
| 401 | // FIXME: This assumes the caller has already checked that the access length | ||||||||||||
| 402 | // is positive. And that it's unsigned. | ||||||||||||
| 403 | SVal LengthVal = C.getSVal(Size.Expression); | ||||||||||||
| 404 | Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); | ||||||||||||
| 405 | if (!Length) | ||||||||||||
| 406 | return State; | ||||||||||||
| 407 | |||||||||||||
| 408 | // Compute the offset of the last element to be accessed: size-1. | ||||||||||||
| 409 | NonLoc One = svalBuilder.makeIntVal(1, SizeTy).castAs<NonLoc>(); | ||||||||||||
| 410 | SVal Offset = svalBuilder.evalBinOpNN(State, BO_Sub, *Length, One, SizeTy); | ||||||||||||
| 411 | if (Offset.isUnknown()) | ||||||||||||
| 412 | return nullptr; | ||||||||||||
| 413 | NonLoc LastOffset = Offset.castAs<NonLoc>(); | ||||||||||||
| 414 | |||||||||||||
| 415 | // Check that the first buffer is sufficiently long. | ||||||||||||
| 416 | SVal BufStart = | ||||||||||||
| 417 | svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType()); | ||||||||||||
| 418 | if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { | ||||||||||||
| 419 | |||||||||||||
| 420 | SVal BufEnd = | ||||||||||||
| 421 | svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy); | ||||||||||||
| 422 | |||||||||||||
| 423 | State = CheckLocation(C, State, Buffer, BufEnd, Access); | ||||||||||||
| 424 | |||||||||||||
| 425 | // If the buffer isn't large enough, abort. | ||||||||||||
| 426 | if (!State) | ||||||||||||
| 427 | return nullptr; | ||||||||||||
| 428 | } | ||||||||||||
| 429 | |||||||||||||
| 430 | // Large enough or not, return this state! | ||||||||||||
| 431 | return State; | ||||||||||||
| 432 | } | ||||||||||||
| 433 | |||||||||||||
| 434 | ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, | ||||||||||||
| 435 | ProgramStateRef state, | ||||||||||||
| 436 | SizeArgExpr Size, AnyArgExpr First, | ||||||||||||
| 437 | AnyArgExpr Second) const { | ||||||||||||
| 438 | if (!Filter.CheckCStringBufferOverlap) | ||||||||||||
| 439 | return state; | ||||||||||||
| 440 | |||||||||||||
| 441 | // Do a simple check for overlap: if the two arguments are from the same | ||||||||||||
| 442 | // buffer, see if the end of the first is greater than the start of the second | ||||||||||||
| 443 | // or vice versa. | ||||||||||||
| 444 | |||||||||||||
| 445 | // If a previous check has failed, propagate the failure. | ||||||||||||
| 446 | if (!state) | ||||||||||||
| 447 | return nullptr; | ||||||||||||
| 448 | |||||||||||||
| 449 | ProgramStateRef stateTrue, stateFalse; | ||||||||||||
| 450 | |||||||||||||
| 451 | // Get the buffer values and make sure they're known locations. | ||||||||||||
| 452 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 453 | SVal firstVal = state->getSVal(First.Expression, LCtx); | ||||||||||||
| 454 | SVal secondVal = state->getSVal(Second.Expression, LCtx); | ||||||||||||
| 455 | |||||||||||||
| 456 | Optional<Loc> firstLoc = firstVal.getAs<Loc>(); | ||||||||||||
| 457 | if (!firstLoc) | ||||||||||||
| 458 | return state; | ||||||||||||
| 459 | |||||||||||||
| 460 | Optional<Loc> secondLoc = secondVal.getAs<Loc>(); | ||||||||||||
| 461 | if (!secondLoc) | ||||||||||||
| 462 | return state; | ||||||||||||
| 463 | |||||||||||||
| 464 | // Are the two values the same? | ||||||||||||
| 465 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 466 | std::tie(stateTrue, stateFalse) = | ||||||||||||
| 467 | state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); | ||||||||||||
| 468 | |||||||||||||
| 469 | if (stateTrue && !stateFalse) { | ||||||||||||
| 470 | // If the values are known to be equal, that's automatically an overlap. | ||||||||||||
| 471 | emitOverlapBug(C, stateTrue, First.Expression, Second.Expression); | ||||||||||||
| 472 | return nullptr; | ||||||||||||
| 473 | } | ||||||||||||
| 474 | |||||||||||||
| 475 | // assume the two expressions are not equal. | ||||||||||||
| 476 | assert(stateFalse)(static_cast <bool> (stateFalse) ? void (0) : __assert_fail ("stateFalse", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 476, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 477 | state = stateFalse; | ||||||||||||
| 478 | |||||||||||||
| 479 | // Which value comes first? | ||||||||||||
| 480 | QualType cmpTy = svalBuilder.getConditionType(); | ||||||||||||
| 481 | SVal reverse = | ||||||||||||
| 482 | svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy); | ||||||||||||
| 483 | Optional<DefinedOrUnknownSVal> reverseTest = | ||||||||||||
| 484 | reverse.getAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 485 | if (!reverseTest) | ||||||||||||
| 486 | return state; | ||||||||||||
| 487 | |||||||||||||
| 488 | std::tie(stateTrue, stateFalse) = state->assume(*reverseTest); | ||||||||||||
| 489 | if (stateTrue) { | ||||||||||||
| 490 | if (stateFalse) { | ||||||||||||
| 491 | // If we don't know which one comes first, we can't perform this test. | ||||||||||||
| 492 | return state; | ||||||||||||
| 493 | } else { | ||||||||||||
| 494 | // Switch the values so that firstVal is before secondVal. | ||||||||||||
| 495 | std::swap(firstLoc, secondLoc); | ||||||||||||
| 496 | |||||||||||||
| 497 | // Switch the Exprs as well, so that they still correspond. | ||||||||||||
| 498 | std::swap(First, Second); | ||||||||||||
| 499 | } | ||||||||||||
| 500 | } | ||||||||||||
| 501 | |||||||||||||
| 502 | // Get the length, and make sure it too is known. | ||||||||||||
| 503 | SVal LengthVal = state->getSVal(Size.Expression, LCtx); | ||||||||||||
| 504 | Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); | ||||||||||||
| 505 | if (!Length) | ||||||||||||
| 506 | return state; | ||||||||||||
| 507 | |||||||||||||
| 508 | // Convert the first buffer's start address to char*. | ||||||||||||
| 509 | // Bail out if the cast fails. | ||||||||||||
| 510 | ASTContext &Ctx = svalBuilder.getContext(); | ||||||||||||
| 511 | QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); | ||||||||||||
| 512 | SVal FirstStart = | ||||||||||||
| 513 | svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType()); | ||||||||||||
| 514 | Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); | ||||||||||||
| 515 | if (!FirstStartLoc) | ||||||||||||
| 516 | return state; | ||||||||||||
| 517 | |||||||||||||
| 518 | // Compute the end of the first buffer. Bail out if THAT fails. | ||||||||||||
| 519 | SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc, | ||||||||||||
| 520 | *Length, CharPtrTy); | ||||||||||||
| 521 | Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>(); | ||||||||||||
| 522 | if (!FirstEndLoc) | ||||||||||||
| 523 | return state; | ||||||||||||
| 524 | |||||||||||||
| 525 | // Is the end of the first buffer past the start of the second buffer? | ||||||||||||
| 526 | SVal Overlap = | ||||||||||||
| 527 | svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy); | ||||||||||||
| 528 | Optional<DefinedOrUnknownSVal> OverlapTest = | ||||||||||||
| 529 | Overlap.getAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 530 | if (!OverlapTest) | ||||||||||||
| 531 | return state; | ||||||||||||
| 532 | |||||||||||||
| 533 | std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); | ||||||||||||
| 534 | |||||||||||||
| 535 | if (stateTrue && !stateFalse) { | ||||||||||||
| 536 | // Overlap! | ||||||||||||
| 537 | emitOverlapBug(C, stateTrue, First.Expression, Second.Expression); | ||||||||||||
| 538 | return nullptr; | ||||||||||||
| 539 | } | ||||||||||||
| 540 | |||||||||||||
| 541 | // assume the two expressions don't overlap. | ||||||||||||
| 542 | assert(stateFalse)(static_cast <bool> (stateFalse) ? void (0) : __assert_fail ("stateFalse", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 542, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 543 | return stateFalse; | ||||||||||||
| 544 | } | ||||||||||||
| 545 | |||||||||||||
| 546 | void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, | ||||||||||||
| 547 | const Stmt *First, const Stmt *Second) const { | ||||||||||||
| 548 | ExplodedNode *N = C.generateErrorNode(state); | ||||||||||||
| 549 | if (!N) | ||||||||||||
| 550 | return; | ||||||||||||
| 551 | |||||||||||||
| 552 | if (!BT_Overlap) | ||||||||||||
| 553 | BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, | ||||||||||||
| 554 | categories::UnixAPI, "Improper arguments")); | ||||||||||||
| 555 | |||||||||||||
| 556 | // Generate a report for this bug. | ||||||||||||
| 557 | auto report = std::make_unique<PathSensitiveBugReport>( | ||||||||||||
| 558 | *BT_Overlap, "Arguments must not be overlapping buffers", N); | ||||||||||||
| 559 | report->addRange(First->getSourceRange()); | ||||||||||||
| 560 | report->addRange(Second->getSourceRange()); | ||||||||||||
| 561 | |||||||||||||
| 562 | C.emitReport(std::move(report)); | ||||||||||||
| 563 | } | ||||||||||||
| 564 | |||||||||||||
| 565 | void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, | ||||||||||||
| 566 | const Stmt *S, StringRef WarningMsg) const { | ||||||||||||
| 567 | if (ExplodedNode *N = C.generateErrorNode(State)) { | ||||||||||||
| 568 | if (!BT_Null) | ||||||||||||
| 569 | BT_Null.reset(new BuiltinBug( | ||||||||||||
| 570 | Filter.CheckNameCStringNullArg, categories::UnixAPI, | ||||||||||||
| 571 | "Null pointer argument in call to byte string function")); | ||||||||||||
| 572 | |||||||||||||
| 573 | BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get()); | ||||||||||||
| 574 | auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); | ||||||||||||
| 575 | Report->addRange(S->getSourceRange()); | ||||||||||||
| 576 | if (const auto *Ex = dyn_cast<Expr>(S)) | ||||||||||||
| 577 | bugreporter::trackExpressionValue(N, Ex, *Report); | ||||||||||||
| 578 | C.emitReport(std::move(Report)); | ||||||||||||
| 579 | } | ||||||||||||
| 580 | } | ||||||||||||
| 581 | |||||||||||||
| 582 | void CStringChecker::emitOutOfBoundsBug(CheckerContext &C, | ||||||||||||
| 583 | ProgramStateRef State, const Stmt *S, | ||||||||||||
| 584 | StringRef WarningMsg) const { | ||||||||||||
| 585 | if (ExplodedNode *N = C.generateErrorNode(State)) { | ||||||||||||
| 586 | if (!BT_Bounds) | ||||||||||||
| 587 | BT_Bounds.reset(new BuiltinBug( | ||||||||||||
| 588 | Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds | ||||||||||||
| 589 | : Filter.CheckNameCStringNullArg, | ||||||||||||
| 590 | "Out-of-bound array access", | ||||||||||||
| 591 | "Byte string function accesses out-of-bound array element")); | ||||||||||||
| 592 | |||||||||||||
| 593 | BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get()); | ||||||||||||
| 594 | |||||||||||||
| 595 | // FIXME: It would be nice to eventually make this diagnostic more clear, | ||||||||||||
| 596 | // e.g., by referencing the original declaration or by saying *why* this | ||||||||||||
| 597 | // reference is outside the range. | ||||||||||||
| 598 | auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); | ||||||||||||
| 599 | Report->addRange(S->getSourceRange()); | ||||||||||||
| 600 | C.emitReport(std::move(Report)); | ||||||||||||
| 601 | } | ||||||||||||
| 602 | } | ||||||||||||
| 603 | |||||||||||||
| 604 | void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, | ||||||||||||
| 605 | const Stmt *S, | ||||||||||||
| 606 | StringRef WarningMsg) const { | ||||||||||||
| 607 | if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { | ||||||||||||
| 608 | if (!BT_NotCString) | ||||||||||||
| 609 | BT_NotCString.reset(new BuiltinBug( | ||||||||||||
| 610 | Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, | ||||||||||||
| 611 | "Argument is not a null-terminated string.")); | ||||||||||||
| 612 | |||||||||||||
| 613 | auto Report = | ||||||||||||
| 614 | std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); | ||||||||||||
| 615 | |||||||||||||
| 616 | Report->addRange(S->getSourceRange()); | ||||||||||||
| 617 | C.emitReport(std::move(Report)); | ||||||||||||
| 618 | } | ||||||||||||
| 619 | } | ||||||||||||
| 620 | |||||||||||||
| 621 | void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, | ||||||||||||
| 622 | ProgramStateRef State) const { | ||||||||||||
| 623 | if (ExplodedNode *N = C.generateErrorNode(State)) { | ||||||||||||
| 624 | if (!BT_NotCString) | ||||||||||||
| 625 | BT_NotCString.reset( | ||||||||||||
| 626 | new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", | ||||||||||||
| 627 | "Sum of expressions causes overflow.")); | ||||||||||||
| 628 | |||||||||||||
| 629 | // This isn't a great error message, but this should never occur in real | ||||||||||||
| 630 | // code anyway -- you'd have to create a buffer longer than a size_t can | ||||||||||||
| 631 | // represent, which is sort of a contradiction. | ||||||||||||
| 632 | const char *WarningMsg = | ||||||||||||
| 633 | "This expression will create a string whose length is too big to " | ||||||||||||
| 634 | "be represented as a size_t"; | ||||||||||||
| 635 | |||||||||||||
| 636 | auto Report = | ||||||||||||
| 637 | std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); | ||||||||||||
| 638 | C.emitReport(std::move(Report)); | ||||||||||||
| 639 | } | ||||||||||||
| 640 | } | ||||||||||||
| 641 | |||||||||||||
| 642 | ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, | ||||||||||||
| 643 | ProgramStateRef state, | ||||||||||||
| 644 | NonLoc left, | ||||||||||||
| 645 | NonLoc right) const { | ||||||||||||
| 646 | // If out-of-bounds checking is turned off, skip the rest. | ||||||||||||
| 647 | if (!Filter.CheckCStringOutOfBounds) | ||||||||||||
| 648 | return state; | ||||||||||||
| 649 | |||||||||||||
| 650 | // If a previous check has failed, propagate the failure. | ||||||||||||
| 651 | if (!state) | ||||||||||||
| 652 | return nullptr; | ||||||||||||
| 653 | |||||||||||||
| 654 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 655 | BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); | ||||||||||||
| 656 | |||||||||||||
| 657 | QualType sizeTy = svalBuilder.getContext().getSizeType(); | ||||||||||||
| 658 | const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); | ||||||||||||
| 659 | NonLoc maxVal = svalBuilder.makeIntVal(maxValInt); | ||||||||||||
| 660 | |||||||||||||
| 661 | SVal maxMinusRight; | ||||||||||||
| 662 | if (right.getAs<nonloc::ConcreteInt>()) { | ||||||||||||
| 663 | maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right, | ||||||||||||
| 664 | sizeTy); | ||||||||||||
| 665 | } else { | ||||||||||||
| 666 | // Try switching the operands. (The order of these two assignments is | ||||||||||||
| 667 | // important!) | ||||||||||||
| 668 | maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, | ||||||||||||
| 669 | sizeTy); | ||||||||||||
| 670 | left = right; | ||||||||||||
| 671 | } | ||||||||||||
| 672 | |||||||||||||
| 673 | if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) { | ||||||||||||
| 674 | QualType cmpTy = svalBuilder.getConditionType(); | ||||||||||||
| 675 | // If left > max - right, we have an overflow. | ||||||||||||
| 676 | SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, | ||||||||||||
| 677 | *maxMinusRightNL, cmpTy); | ||||||||||||
| 678 | |||||||||||||
| 679 | ProgramStateRef stateOverflow, stateOkay; | ||||||||||||
| 680 | std::tie(stateOverflow, stateOkay) = | ||||||||||||
| 681 | state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); | ||||||||||||
| 682 | |||||||||||||
| 683 | if (stateOverflow && !stateOkay) { | ||||||||||||
| 684 | // We have an overflow. Emit a bug report. | ||||||||||||
| 685 | emitAdditionOverflowBug(C, stateOverflow); | ||||||||||||
| 686 | return nullptr; | ||||||||||||
| 687 | } | ||||||||||||
| 688 | |||||||||||||
| 689 | // From now on, assume an overflow didn't occur. | ||||||||||||
| 690 | assert(stateOkay)(static_cast <bool> (stateOkay) ? void (0) : __assert_fail ("stateOkay", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 690, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 691 | state = stateOkay; | ||||||||||||
| 692 | } | ||||||||||||
| 693 | |||||||||||||
| 694 | return state; | ||||||||||||
| 695 | } | ||||||||||||
| 696 | |||||||||||||
| 697 | ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state, | ||||||||||||
| 698 | const MemRegion *MR, | ||||||||||||
| 699 | SVal strLength) { | ||||||||||||
| 700 | assert(!strLength.isUndef() && "Attempt to set an undefined string length")(static_cast <bool> (!strLength.isUndef() && "Attempt to set an undefined string length" ) ? void (0) : __assert_fail ("!strLength.isUndef() && \"Attempt to set an undefined string length\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 700, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 701 | |||||||||||||
| 702 | MR = MR->StripCasts(); | ||||||||||||
| 703 | |||||||||||||
| 704 | switch (MR->getKind()) { | ||||||||||||
| 705 | case MemRegion::StringRegionKind: | ||||||||||||
| 706 | // FIXME: This can happen if we strcpy() into a string region. This is | ||||||||||||
| 707 | // undefined [C99 6.4.5p6], but we should still warn about it. | ||||||||||||
| 708 | return state; | ||||||||||||
| 709 | |||||||||||||
| 710 | case MemRegion::SymbolicRegionKind: | ||||||||||||
| 711 | case MemRegion::AllocaRegionKind: | ||||||||||||
| 712 | case MemRegion::NonParamVarRegionKind: | ||||||||||||
| 713 | case MemRegion::ParamVarRegionKind: | ||||||||||||
| 714 | case MemRegion::FieldRegionKind: | ||||||||||||
| 715 | case MemRegion::ObjCIvarRegionKind: | ||||||||||||
| 716 | // These are the types we can currently track string lengths for. | ||||||||||||
| 717 | break; | ||||||||||||
| 718 | |||||||||||||
| 719 | case MemRegion::ElementRegionKind: | ||||||||||||
| 720 | // FIXME: Handle element regions by upper-bounding the parent region's | ||||||||||||
| 721 | // string length. | ||||||||||||
| 722 | return state; | ||||||||||||
| 723 | |||||||||||||
| 724 | default: | ||||||||||||
| 725 | // Other regions (mostly non-data) can't have a reliable C string length. | ||||||||||||
| 726 | // For now, just ignore the change. | ||||||||||||
| 727 | // FIXME: These are rare but not impossible. We should output some kind of | ||||||||||||
| 728 | // warning for things like strcpy((char[]){'a', 0}, "b"); | ||||||||||||
| 729 | return state; | ||||||||||||
| 730 | } | ||||||||||||
| 731 | |||||||||||||
| 732 | if (strLength.isUnknown()) | ||||||||||||
| 733 | return state->remove<CStringLength>(MR); | ||||||||||||
| 734 | |||||||||||||
| 735 | return state->set<CStringLength>(MR, strLength); | ||||||||||||
| 736 | } | ||||||||||||
| 737 | |||||||||||||
| 738 | SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, | ||||||||||||
| 739 | ProgramStateRef &state, | ||||||||||||
| 740 | const Expr *Ex, | ||||||||||||
| 741 | const MemRegion *MR, | ||||||||||||
| 742 | bool hypothetical) { | ||||||||||||
| 743 | if (!hypothetical) { | ||||||||||||
| 744 | // If there's a recorded length, go ahead and return it. | ||||||||||||
| 745 | const SVal *Recorded = state->get<CStringLength>(MR); | ||||||||||||
| 746 | if (Recorded) | ||||||||||||
| 747 | return *Recorded; | ||||||||||||
| 748 | } | ||||||||||||
| 749 | |||||||||||||
| 750 | // Otherwise, get a new symbol and update the state. | ||||||||||||
| 751 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 752 | QualType sizeTy = svalBuilder.getContext().getSizeType(); | ||||||||||||
| 753 | SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), | ||||||||||||
| 754 | MR, Ex, sizeTy, | ||||||||||||
| 755 | C.getLocationContext(), | ||||||||||||
| 756 | C.blockCount()); | ||||||||||||
| 757 | |||||||||||||
| 758 | if (!hypothetical) { | ||||||||||||
| 759 | if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { | ||||||||||||
| 760 | // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 | ||||||||||||
| 761 | BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); | ||||||||||||
| 762 | const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); | ||||||||||||
| 763 | llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); | ||||||||||||
| 764 | const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, | ||||||||||||
| 765 | fourInt); | ||||||||||||
| 766 | NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); | ||||||||||||
| 767 | SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, | ||||||||||||
| 768 | maxLength, sizeTy); | ||||||||||||
| 769 | state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); | ||||||||||||
| 770 | } | ||||||||||||
| 771 | state = state->set<CStringLength>(MR, strLength); | ||||||||||||
| 772 | } | ||||||||||||
| 773 | |||||||||||||
| 774 | return strLength; | ||||||||||||
| 775 | } | ||||||||||||
| 776 | |||||||||||||
| 777 | SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, | ||||||||||||
| 778 | const Expr *Ex, SVal Buf, | ||||||||||||
| 779 | bool hypothetical) const { | ||||||||||||
| 780 | const MemRegion *MR = Buf.getAsRegion(); | ||||||||||||
| 781 | if (!MR) { | ||||||||||||
| 782 | // If we can't get a region, see if it's something we /know/ isn't a | ||||||||||||
| 783 | // C string. In the context of locations, the only time we can issue such | ||||||||||||
| 784 | // a warning is for labels. | ||||||||||||
| 785 | if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { | ||||||||||||
| 786 | if (Filter.CheckCStringNotNullTerm) { | ||||||||||||
| 787 | SmallString<120> buf; | ||||||||||||
| 788 | llvm::raw_svector_ostream os(buf); | ||||||||||||
| 789 | assert(CurrentFunctionDescription)(static_cast <bool> (CurrentFunctionDescription) ? void (0) : __assert_fail ("CurrentFunctionDescription", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 789, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 790 | os << "Argument to " << CurrentFunctionDescription | ||||||||||||
| 791 | << " is the address of the label '" << Label->getLabel()->getName() | ||||||||||||
| 792 | << "', which is not a null-terminated string"; | ||||||||||||
| 793 | |||||||||||||
| 794 | emitNotCStringBug(C, state, Ex, os.str()); | ||||||||||||
| 795 | } | ||||||||||||
| 796 | return UndefinedVal(); | ||||||||||||
| 797 | } | ||||||||||||
| 798 | |||||||||||||
| 799 | // If it's not a region and not a label, give up. | ||||||||||||
| 800 | return UnknownVal(); | ||||||||||||
| 801 | } | ||||||||||||
| 802 | |||||||||||||
| 803 | // If we have a region, strip casts from it and see if we can figure out | ||||||||||||
| 804 | // its length. For anything we can't figure out, just return UnknownVal. | ||||||||||||
| 805 | MR = MR->StripCasts(); | ||||||||||||
| 806 | |||||||||||||
| 807 | switch (MR->getKind()) { | ||||||||||||
| 808 | case MemRegion::StringRegionKind: { | ||||||||||||
| 809 | // Modifying the contents of string regions is undefined [C99 6.4.5p6], | ||||||||||||
| 810 | // so we can assume that the byte length is the correct C string length. | ||||||||||||
| 811 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 812 | QualType sizeTy = svalBuilder.getContext().getSizeType(); | ||||||||||||
| 813 | const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral(); | ||||||||||||
| 814 | return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); | ||||||||||||
| 815 | } | ||||||||||||
| 816 | case MemRegion::SymbolicRegionKind: | ||||||||||||
| 817 | case MemRegion::AllocaRegionKind: | ||||||||||||
| 818 | case MemRegion::NonParamVarRegionKind: | ||||||||||||
| 819 | case MemRegion::ParamVarRegionKind: | ||||||||||||
| 820 | case MemRegion::FieldRegionKind: | ||||||||||||
| 821 | case MemRegion::ObjCIvarRegionKind: | ||||||||||||
| 822 | return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); | ||||||||||||
| 823 | case MemRegion::CompoundLiteralRegionKind: | ||||||||||||
| 824 | // FIXME: Can we track this? Is it necessary? | ||||||||||||
| 825 | return UnknownVal(); | ||||||||||||
| 826 | case MemRegion::ElementRegionKind: | ||||||||||||
| 827 | // FIXME: How can we handle this? It's not good enough to subtract the | ||||||||||||
| 828 | // offset from the base string length; consider "123\x00567" and &a[5]. | ||||||||||||
| 829 | return UnknownVal(); | ||||||||||||
| 830 | default: | ||||||||||||
| 831 | // Other regions (mostly non-data) can't have a reliable C string length. | ||||||||||||
| 832 | // In this case, an error is emitted and UndefinedVal is returned. | ||||||||||||
| 833 | // The caller should always be prepared to handle this case. | ||||||||||||
| 834 | if (Filter.CheckCStringNotNullTerm) { | ||||||||||||
| 835 | SmallString<120> buf; | ||||||||||||
| 836 | llvm::raw_svector_ostream os(buf); | ||||||||||||
| 837 | |||||||||||||
| 838 | assert(CurrentFunctionDescription)(static_cast <bool> (CurrentFunctionDescription) ? void (0) : __assert_fail ("CurrentFunctionDescription", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 838, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 839 | os << "Argument to " << CurrentFunctionDescription << " is "; | ||||||||||||
| 840 | |||||||||||||
| 841 | if (SummarizeRegion(os, C.getASTContext(), MR)) | ||||||||||||
| 842 | os << ", which is not a null-terminated string"; | ||||||||||||
| 843 | else | ||||||||||||
| 844 | os << "not a null-terminated string"; | ||||||||||||
| 845 | |||||||||||||
| 846 | emitNotCStringBug(C, state, Ex, os.str()); | ||||||||||||
| 847 | } | ||||||||||||
| 848 | return UndefinedVal(); | ||||||||||||
| 849 | } | ||||||||||||
| 850 | } | ||||||||||||
| 851 | |||||||||||||
| 852 | const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, | ||||||||||||
| 853 | ProgramStateRef &state, const Expr *expr, SVal val) const { | ||||||||||||
| 854 | |||||||||||||
| 855 | // Get the memory region pointed to by the val. | ||||||||||||
| 856 | const MemRegion *bufRegion = val.getAsRegion(); | ||||||||||||
| 857 | if (!bufRegion) | ||||||||||||
| 858 | return nullptr; | ||||||||||||
| 859 | |||||||||||||
| 860 | // Strip casts off the memory region. | ||||||||||||
| 861 | bufRegion = bufRegion->StripCasts(); | ||||||||||||
| 862 | |||||||||||||
| 863 | // Cast the memory region to a string region. | ||||||||||||
| 864 | const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); | ||||||||||||
| 865 | if (!strRegion) | ||||||||||||
| 866 | return nullptr; | ||||||||||||
| 867 | |||||||||||||
| 868 | // Return the actual string in the string region. | ||||||||||||
| 869 | return strRegion->getStringLiteral(); | ||||||||||||
| 870 | } | ||||||||||||
| 871 | |||||||||||||
| 872 | bool CStringChecker::IsFirstBufInBound(CheckerContext &C, | ||||||||||||
| 873 | ProgramStateRef state, | ||||||||||||
| 874 | const Expr *FirstBuf, | ||||||||||||
| 875 | const Expr *Size) { | ||||||||||||
| 876 | // If we do not know that the buffer is long enough we return 'true'. | ||||||||||||
| 877 | // Otherwise the parent region of this field region would also get | ||||||||||||
| 878 | // invalidated, which would lead to warnings based on an unknown state. | ||||||||||||
| 879 | |||||||||||||
| 880 | // Originally copied from CheckBufferAccess and CheckLocation. | ||||||||||||
| 881 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 882 | ASTContext &Ctx = svalBuilder.getContext(); | ||||||||||||
| 883 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 884 | |||||||||||||
| 885 | QualType sizeTy = Size->getType(); | ||||||||||||
| 886 | QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); | ||||||||||||
| 887 | SVal BufVal = state->getSVal(FirstBuf, LCtx); | ||||||||||||
| 888 | |||||||||||||
| 889 | SVal LengthVal = state->getSVal(Size, LCtx); | ||||||||||||
| 890 | Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); | ||||||||||||
| 891 | if (!Length) | ||||||||||||
| 892 | return true; // cf top comment. | ||||||||||||
| 893 | |||||||||||||
| 894 | // Compute the offset of the last element to be accessed: size-1. | ||||||||||||
| 895 | NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); | ||||||||||||
| 896 | SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); | ||||||||||||
| 897 | if (Offset.isUnknown()) | ||||||||||||
| 898 | return true; // cf top comment | ||||||||||||
| 899 | NonLoc LastOffset = Offset.castAs<NonLoc>(); | ||||||||||||
| 900 | |||||||||||||
| 901 | // Check that the first buffer is sufficiently long. | ||||||||||||
| 902 | SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); | ||||||||||||
| 903 | Optional<Loc> BufLoc = BufStart.getAs<Loc>(); | ||||||||||||
| 904 | if (!BufLoc) | ||||||||||||
| 905 | return true; // cf top comment. | ||||||||||||
| 906 | |||||||||||||
| 907 | SVal BufEnd = | ||||||||||||
| 908 | svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy); | ||||||||||||
| 909 | |||||||||||||
| 910 | // Check for out of bound array element access. | ||||||||||||
| 911 | const MemRegion *R = BufEnd.getAsRegion(); | ||||||||||||
| 912 | if (!R) | ||||||||||||
| 913 | return true; // cf top comment. | ||||||||||||
| 914 | |||||||||||||
| 915 | const ElementRegion *ER = dyn_cast<ElementRegion>(R); | ||||||||||||
| 916 | if (!ER) | ||||||||||||
| 917 | return true; // cf top comment. | ||||||||||||
| 918 | |||||||||||||
| 919 | // FIXME: Does this crash when a non-standard definition | ||||||||||||
| 920 | // of a library function is encountered? | ||||||||||||
| 921 | assert(ER->getValueType() == C.getASTContext().CharTy &&(static_cast <bool> (ER->getValueType() == C.getASTContext ().CharTy && "IsFirstBufInBound should only be called with char* ElementRegions" ) ? void (0) : __assert_fail ("ER->getValueType() == C.getASTContext().CharTy && \"IsFirstBufInBound should only be called with char* ElementRegions\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 922, __extension__ __PRETTY_FUNCTION__)) | ||||||||||||
| 922 | "IsFirstBufInBound should only be called with char* ElementRegions")(static_cast <bool> (ER->getValueType() == C.getASTContext ().CharTy && "IsFirstBufInBound should only be called with char* ElementRegions" ) ? void (0) : __assert_fail ("ER->getValueType() == C.getASTContext().CharTy && \"IsFirstBufInBound should only be called with char* ElementRegions\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 922, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 923 | |||||||||||||
| 924 | // Get the size of the array. | ||||||||||||
| 925 | const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); | ||||||||||||
| 926 | DefinedOrUnknownSVal SizeDV = getDynamicExtent(state, superReg, svalBuilder); | ||||||||||||
| 927 | |||||||||||||
| 928 | // Get the index of the accessed element. | ||||||||||||
| 929 | DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 930 | |||||||||||||
| 931 | ProgramStateRef StInBound = state->assumeInBound(Idx, SizeDV, true); | ||||||||||||
| 932 | |||||||||||||
| 933 | return static_cast<bool>(StInBound); | ||||||||||||
| 934 | } | ||||||||||||
| 935 | |||||||||||||
| 936 | ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, | ||||||||||||
| 937 | ProgramStateRef state, | ||||||||||||
| 938 | const Expr *E, SVal V, | ||||||||||||
| 939 | bool IsSourceBuffer, | ||||||||||||
| 940 | const Expr *Size) { | ||||||||||||
| 941 | Optional<Loc> L = V.getAs<Loc>(); | ||||||||||||
| 942 | if (!L) | ||||||||||||
| 943 | return state; | ||||||||||||
| 944 | |||||||||||||
| 945 | // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes | ||||||||||||
| 946 | // some assumptions about the value that CFRefCount can't. Even so, it should | ||||||||||||
| 947 | // probably be refactored. | ||||||||||||
| 948 | if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) { | ||||||||||||
| 949 | const MemRegion *R = MR->getRegion()->StripCasts(); | ||||||||||||
| 950 | |||||||||||||
| 951 | // Are we dealing with an ElementRegion? If so, we should be invalidating | ||||||||||||
| 952 | // the super-region. | ||||||||||||
| 953 | if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { | ||||||||||||
| 954 | R = ER->getSuperRegion(); | ||||||||||||
| 955 | // FIXME: What about layers of ElementRegions? | ||||||||||||
| 956 | } | ||||||||||||
| 957 | |||||||||||||
| 958 | // Invalidate this region. | ||||||||||||
| 959 | const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); | ||||||||||||
| 960 | |||||||||||||
| 961 | bool CausesPointerEscape = false; | ||||||||||||
| 962 | RegionAndSymbolInvalidationTraits ITraits; | ||||||||||||
| 963 | // Invalidate and escape only indirect regions accessible through the source | ||||||||||||
| 964 | // buffer. | ||||||||||||
| 965 | if (IsSourceBuffer) { | ||||||||||||
| 966 | ITraits.setTrait(R->getBaseRegion(), | ||||||||||||
| 967 | RegionAndSymbolInvalidationTraits::TK_PreserveContents); | ||||||||||||
| 968 | ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); | ||||||||||||
| 969 | CausesPointerEscape = true; | ||||||||||||
| 970 | } else { | ||||||||||||
| 971 | const MemRegion::Kind& K = R->getKind(); | ||||||||||||
| 972 | if (K == MemRegion::FieldRegionKind) | ||||||||||||
| 973 | if (Size && IsFirstBufInBound(C, state, E, Size)) { | ||||||||||||
| 974 | // If destination buffer is a field region and access is in bound, | ||||||||||||
| 975 | // do not invalidate its super region. | ||||||||||||
| 976 | ITraits.setTrait( | ||||||||||||
| 977 | R, | ||||||||||||
| 978 | RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); | ||||||||||||
| 979 | } | ||||||||||||
| 980 | } | ||||||||||||
| 981 | |||||||||||||
| 982 | return state->invalidateRegions(R, E, C.blockCount(), LCtx, | ||||||||||||
| 983 | CausesPointerEscape, nullptr, nullptr, | ||||||||||||
| 984 | &ITraits); | ||||||||||||
| 985 | } | ||||||||||||
| 986 | |||||||||||||
| 987 | // If we have a non-region value by chance, just remove the binding. | ||||||||||||
| 988 | // FIXME: is this necessary or correct? This handles the non-Region | ||||||||||||
| 989 | // cases. Is it ever valid to store to these? | ||||||||||||
| 990 | return state->killBinding(*L); | ||||||||||||
| 991 | } | ||||||||||||
| 992 | |||||||||||||
| 993 | bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, | ||||||||||||
| 994 | const MemRegion *MR) { | ||||||||||||
| 995 | switch (MR->getKind()) { | ||||||||||||
| 996 | case MemRegion::FunctionCodeRegionKind: { | ||||||||||||
| 997 | if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl()) | ||||||||||||
| 998 | os << "the address of the function '" << *FD << '\''; | ||||||||||||
| 999 | else | ||||||||||||
| 1000 | os << "the address of a function"; | ||||||||||||
| 1001 | return true; | ||||||||||||
| 1002 | } | ||||||||||||
| 1003 | case MemRegion::BlockCodeRegionKind: | ||||||||||||
| 1004 | os << "block text"; | ||||||||||||
| 1005 | return true; | ||||||||||||
| 1006 | case MemRegion::BlockDataRegionKind: | ||||||||||||
| 1007 | os << "a block"; | ||||||||||||
| 1008 | return true; | ||||||||||||
| 1009 | case MemRegion::CXXThisRegionKind: | ||||||||||||
| 1010 | case MemRegion::CXXTempObjectRegionKind: | ||||||||||||
| 1011 | os << "a C++ temp object of type " | ||||||||||||
| 1012 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); | ||||||||||||
| 1013 | return true; | ||||||||||||
| 1014 | case MemRegion::NonParamVarRegionKind: | ||||||||||||
| 1015 | os << "a variable of type" | ||||||||||||
| 1016 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); | ||||||||||||
| 1017 | return true; | ||||||||||||
| 1018 | case MemRegion::ParamVarRegionKind: | ||||||||||||
| 1019 | os << "a parameter of type" | ||||||||||||
| 1020 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); | ||||||||||||
| 1021 | return true; | ||||||||||||
| 1022 | case MemRegion::FieldRegionKind: | ||||||||||||
| 1023 | os << "a field of type " | ||||||||||||
| 1024 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); | ||||||||||||
| 1025 | return true; | ||||||||||||
| 1026 | case MemRegion::ObjCIvarRegionKind: | ||||||||||||
| 1027 | os << "an instance variable of type " | ||||||||||||
| 1028 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); | ||||||||||||
| 1029 | return true; | ||||||||||||
| 1030 | default: | ||||||||||||
| 1031 | return false; | ||||||||||||
| 1032 | } | ||||||||||||
| 1033 | } | ||||||||||||
| 1034 | |||||||||||||
| 1035 | bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, | ||||||||||||
| 1036 | const Expr *Size, CheckerContext &C, | ||||||||||||
| 1037 | ProgramStateRef &State) { | ||||||||||||
| 1038 | SVal MemVal = C.getSVal(DstBuffer); | ||||||||||||
| 1039 | SVal SizeVal = C.getSVal(Size); | ||||||||||||
| 1040 | const MemRegion *MR = MemVal.getAsRegion(); | ||||||||||||
| 1041 | if (!MR) | ||||||||||||
| 1042 | return false; | ||||||||||||
| 1043 | |||||||||||||
| 1044 | // We're about to model memset by producing a "default binding" in the Store. | ||||||||||||
| 1045 | // Our current implementation - RegionStore - doesn't support default bindings | ||||||||||||
| 1046 | // that don't cover the whole base region. So we should first get the offset | ||||||||||||
| 1047 | // and the base region to figure out whether the offset of buffer is 0. | ||||||||||||
| 1048 | RegionOffset Offset = MR->getAsOffset(); | ||||||||||||
| 1049 | const MemRegion *BR = Offset.getRegion(); | ||||||||||||
| 1050 | |||||||||||||
| 1051 | Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>(); | ||||||||||||
| 1052 | if (!SizeNL) | ||||||||||||
| 1053 | return false; | ||||||||||||
| 1054 | |||||||||||||
| 1055 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 1056 | ASTContext &Ctx = C.getASTContext(); | ||||||||||||
| 1057 | |||||||||||||
| 1058 | // void *memset(void *dest, int ch, size_t count); | ||||||||||||
| 1059 | // For now we can only handle the case of offset is 0 and concrete char value. | ||||||||||||
| 1060 | if (Offset.isValid() && !Offset.hasSymbolicOffset() && | ||||||||||||
| 1061 | Offset.getOffset() == 0) { | ||||||||||||
| 1062 | // Get the base region's size. | ||||||||||||
| 1063 | DefinedOrUnknownSVal SizeDV = getDynamicExtent(State, BR, svalBuilder); | ||||||||||||
| 1064 | |||||||||||||
| 1065 | ProgramStateRef StateWholeReg, StateNotWholeReg; | ||||||||||||
| 1066 | std::tie(StateWholeReg, StateNotWholeReg) = | ||||||||||||
| 1067 | State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL)); | ||||||||||||
| 1068 | |||||||||||||
| 1069 | // With the semantic of 'memset()', we should convert the CharVal to | ||||||||||||
| 1070 | // unsigned char. | ||||||||||||
| 1071 | CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy); | ||||||||||||
| 1072 | |||||||||||||
| 1073 | ProgramStateRef StateNullChar, StateNonNullChar; | ||||||||||||
| 1074 | std::tie(StateNullChar, StateNonNullChar) = | ||||||||||||
| 1075 | assumeZero(C, State, CharVal, Ctx.UnsignedCharTy); | ||||||||||||
| 1076 | |||||||||||||
| 1077 | if (StateWholeReg && !StateNotWholeReg && StateNullChar && | ||||||||||||
| 1078 | !StateNonNullChar) { | ||||||||||||
| 1079 | // If the 'memset()' acts on the whole region of destination buffer and | ||||||||||||
| 1080 | // the value of the second argument of 'memset()' is zero, bind the second | ||||||||||||
| 1081 | // argument's value to the destination buffer with 'default binding'. | ||||||||||||
| 1082 | // FIXME: Since there is no perfect way to bind the non-zero character, we | ||||||||||||
| 1083 | // can only deal with zero value here. In the future, we need to deal with | ||||||||||||
| 1084 | // the binding of non-zero value in the case of whole region. | ||||||||||||
| 1085 | State = State->bindDefaultZero(svalBuilder.makeLoc(BR), | ||||||||||||
| 1086 | C.getLocationContext()); | ||||||||||||
| 1087 | } else { | ||||||||||||
| 1088 | // If the destination buffer's extent is not equal to the value of | ||||||||||||
| 1089 | // third argument, just invalidate buffer. | ||||||||||||
| 1090 | State = InvalidateBuffer(C, State, DstBuffer, MemVal, | ||||||||||||
| 1091 | /*IsSourceBuffer*/ false, Size); | ||||||||||||
| 1092 | } | ||||||||||||
| 1093 | |||||||||||||
| 1094 | if (StateNullChar && !StateNonNullChar) { | ||||||||||||
| 1095 | // If the value of the second argument of 'memset()' is zero, set the | ||||||||||||
| 1096 | // string length of destination buffer to 0 directly. | ||||||||||||
| 1097 | State = setCStringLength(State, MR, | ||||||||||||
| 1098 | svalBuilder.makeZeroVal(Ctx.getSizeType())); | ||||||||||||
| 1099 | } else if (!StateNullChar && StateNonNullChar) { | ||||||||||||
| 1100 | SVal NewStrLen = svalBuilder.getMetadataSymbolVal( | ||||||||||||
| 1101 | CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(), | ||||||||||||
| 1102 | C.getLocationContext(), C.blockCount()); | ||||||||||||
| 1103 | |||||||||||||
| 1104 | // If the value of second argument is not zero, then the string length | ||||||||||||
| 1105 | // is at least the size argument. | ||||||||||||
| 1106 | SVal NewStrLenGESize = svalBuilder.evalBinOp( | ||||||||||||
| 1107 | State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType()); | ||||||||||||
| 1108 | |||||||||||||
| 1109 | State = setCStringLength( | ||||||||||||
| 1110 | State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true), | ||||||||||||
| 1111 | MR, NewStrLen); | ||||||||||||
| 1112 | } | ||||||||||||
| 1113 | } else { | ||||||||||||
| 1114 | // If the offset is not zero and char value is not concrete, we can do | ||||||||||||
| 1115 | // nothing but invalidate the buffer. | ||||||||||||
| 1116 | State = InvalidateBuffer(C, State, DstBuffer, MemVal, | ||||||||||||
| 1117 | /*IsSourceBuffer*/ false, Size); | ||||||||||||
| 1118 | } | ||||||||||||
| 1119 | return true; | ||||||||||||
| 1120 | } | ||||||||||||
| 1121 | |||||||||||||
| 1122 | //===----------------------------------------------------------------------===// | ||||||||||||
| 1123 | // evaluation of individual function calls. | ||||||||||||
| 1124 | //===----------------------------------------------------------------------===// | ||||||||||||
| 1125 | |||||||||||||
| 1126 | void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, | ||||||||||||
| 1127 | ProgramStateRef state, SizeArgExpr Size, | ||||||||||||
| 1128 | DestinationArgExpr Dest, | ||||||||||||
| 1129 | SourceArgExpr Source, bool Restricted, | ||||||||||||
| 1130 | bool IsMempcpy) const { | ||||||||||||
| 1131 | CurrentFunctionDescription = "memory copy function"; | ||||||||||||
| 1132 | |||||||||||||
| 1133 | // See if the size argument is zero. | ||||||||||||
| 1134 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 1135 | SVal sizeVal = state->getSVal(Size.Expression, LCtx); | ||||||||||||
| 1136 | QualType sizeTy = Size.Expression->getType(); | ||||||||||||
| 1137 | |||||||||||||
| 1138 | ProgramStateRef stateZeroSize, stateNonZeroSize; | ||||||||||||
| 1139 | std::tie(stateZeroSize, stateNonZeroSize) = | ||||||||||||
| 1140 | assumeZero(C, state, sizeVal, sizeTy); | ||||||||||||
| 1141 | |||||||||||||
| 1142 | // Get the value of the Dest. | ||||||||||||
| 1143 | SVal destVal = state->getSVal(Dest.Expression, LCtx); | ||||||||||||
| 1144 | |||||||||||||
| 1145 | // If the size is zero, there won't be any actual memory access, so | ||||||||||||
| 1146 | // just bind the return value to the destination buffer and return. | ||||||||||||
| 1147 | if (stateZeroSize && !stateNonZeroSize) { | ||||||||||||
| 1148 | stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal); | ||||||||||||
| 1149 | C.addTransition(stateZeroSize); | ||||||||||||
| 1150 | return; | ||||||||||||
| 1151 | } | ||||||||||||
| 1152 | |||||||||||||
| 1153 | // If the size can be nonzero, we have to check the other arguments. | ||||||||||||
| 1154 | if (stateNonZeroSize) { | ||||||||||||
| 1155 | state = stateNonZeroSize; | ||||||||||||
| 1156 | |||||||||||||
| 1157 | // Ensure the destination is not null. If it is NULL there will be a | ||||||||||||
| 1158 | // NULL pointer dereference. | ||||||||||||
| 1159 | state = checkNonNull(C, state, Dest, destVal); | ||||||||||||
| 1160 | if (!state) | ||||||||||||
| 1161 | return; | ||||||||||||
| 1162 | |||||||||||||
| 1163 | // Get the value of the Src. | ||||||||||||
| 1164 | SVal srcVal = state->getSVal(Source.Expression, LCtx); | ||||||||||||
| 1165 | |||||||||||||
| 1166 | // Ensure the source is not null. If it is NULL there will be a | ||||||||||||
| 1167 | // NULL pointer dereference. | ||||||||||||
| 1168 | state = checkNonNull(C, state, Source, srcVal); | ||||||||||||
| 1169 | if (!state) | ||||||||||||
| 1170 | return; | ||||||||||||
| 1171 | |||||||||||||
| 1172 | // Ensure the accesses are valid and that the buffers do not overlap. | ||||||||||||
| 1173 | state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write); | ||||||||||||
| 1174 | state = CheckBufferAccess(C, state, Source, Size, AccessKind::read); | ||||||||||||
| 1175 | |||||||||||||
| 1176 | if (Restricted) | ||||||||||||
| 1177 | state = CheckOverlap(C, state, Size, Dest, Source); | ||||||||||||
| 1178 | |||||||||||||
| 1179 | if (!state) | ||||||||||||
| 1180 | return; | ||||||||||||
| 1181 | |||||||||||||
| 1182 | // If this is mempcpy, get the byte after the last byte copied and | ||||||||||||
| 1183 | // bind the expr. | ||||||||||||
| 1184 | if (IsMempcpy) { | ||||||||||||
| 1185 | // Get the byte after the last byte copied. | ||||||||||||
| 1186 | SValBuilder &SvalBuilder = C.getSValBuilder(); | ||||||||||||
| 1187 | ASTContext &Ctx = SvalBuilder.getContext(); | ||||||||||||
| 1188 | QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); | ||||||||||||
| 1189 | SVal DestRegCharVal = | ||||||||||||
| 1190 | SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType()); | ||||||||||||
| 1191 | SVal lastElement = C.getSValBuilder().evalBinOp( | ||||||||||||
| 1192 | state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType()); | ||||||||||||
| 1193 | // If we don't know how much we copied, we can at least | ||||||||||||
| 1194 | // conjure a return value for later. | ||||||||||||
| 1195 | if (lastElement.isUnknown()) | ||||||||||||
| 1196 | lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, | ||||||||||||
| 1197 | C.blockCount()); | ||||||||||||
| 1198 | |||||||||||||
| 1199 | // The byte after the last byte copied is the return value. | ||||||||||||
| 1200 | state = state->BindExpr(CE, LCtx, lastElement); | ||||||||||||
| 1201 | } else { | ||||||||||||
| 1202 | // All other copies return the destination buffer. | ||||||||||||
| 1203 | // (Well, bcopy() has a void return type, but this won't hurt.) | ||||||||||||
| 1204 | state = state->BindExpr(CE, LCtx, destVal); | ||||||||||||
| 1205 | } | ||||||||||||
| 1206 | |||||||||||||
| 1207 | // Invalidate the destination (regular invalidation without pointer-escaping | ||||||||||||
| 1208 | // the address of the top-level region). | ||||||||||||
| 1209 | // FIXME: Even if we can't perfectly model the copy, we should see if we | ||||||||||||
| 1210 | // can use LazyCompoundVals to copy the source values into the destination. | ||||||||||||
| 1211 | // This would probably remove any existing bindings past the end of the | ||||||||||||
| 1212 | // copied region, but that's still an improvement over blank invalidation. | ||||||||||||
| 1213 | state = | ||||||||||||
| 1214 | InvalidateBuffer(C, state, Dest.Expression, C.getSVal(Dest.Expression), | ||||||||||||
| 1215 | /*IsSourceBuffer*/ false, Size.Expression); | ||||||||||||
| 1216 | |||||||||||||
| 1217 | // Invalidate the source (const-invalidation without const-pointer-escaping | ||||||||||||
| 1218 | // the address of the top-level region). | ||||||||||||
| 1219 | state = InvalidateBuffer(C, state, Source.Expression, | ||||||||||||
| 1220 | C.getSVal(Source.Expression), | ||||||||||||
| 1221 | /*IsSourceBuffer*/ true, nullptr); | ||||||||||||
| 1222 | |||||||||||||
| 1223 | C.addTransition(state); | ||||||||||||
| 1224 | } | ||||||||||||
| 1225 | } | ||||||||||||
| 1226 | |||||||||||||
| 1227 | void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1228 | // void *memcpy(void *restrict dst, const void *restrict src, size_t n); | ||||||||||||
| 1229 | // The return value is the address of the destination buffer. | ||||||||||||
| 1230 | DestinationArgExpr Dest = {CE->getArg(0), 0}; | ||||||||||||
| 1231 | SourceArgExpr Src = {CE->getArg(1), 1}; | ||||||||||||
| 1232 | SizeArgExpr Size = {CE->getArg(2), 2}; | ||||||||||||
| 1233 | |||||||||||||
| 1234 | ProgramStateRef State = C.getState(); | ||||||||||||
| 1235 | |||||||||||||
| 1236 | constexpr bool IsRestricted = true; | ||||||||||||
| 1237 | constexpr bool IsMempcpy = false; | ||||||||||||
| 1238 | evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy); | ||||||||||||
| 1239 | } | ||||||||||||
| 1240 | |||||||||||||
| 1241 | void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1242 | // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); | ||||||||||||
| 1243 | // The return value is a pointer to the byte following the last written byte. | ||||||||||||
| 1244 | DestinationArgExpr Dest = {CE->getArg(0), 0}; | ||||||||||||
| 1245 | SourceArgExpr Src = {CE->getArg(1), 1}; | ||||||||||||
| 1246 | SizeArgExpr Size = {CE->getArg(2), 2}; | ||||||||||||
| 1247 | |||||||||||||
| 1248 | constexpr bool IsRestricted = true; | ||||||||||||
| 1249 | constexpr bool IsMempcpy = true; | ||||||||||||
| 1250 | evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); | ||||||||||||
| 1251 | } | ||||||||||||
| 1252 | |||||||||||||
| 1253 | void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1254 | // void *memmove(void *dst, const void *src, size_t n); | ||||||||||||
| 1255 | // The return value is the address of the destination buffer. | ||||||||||||
| 1256 | DestinationArgExpr Dest = {CE->getArg(0), 0}; | ||||||||||||
| 1257 | SourceArgExpr Src = {CE->getArg(1), 1}; | ||||||||||||
| 1258 | SizeArgExpr Size = {CE->getArg(2), 2}; | ||||||||||||
| 1259 | |||||||||||||
| 1260 | constexpr bool IsRestricted = false; | ||||||||||||
| 1261 | constexpr bool IsMempcpy = false; | ||||||||||||
| 1262 | evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); | ||||||||||||
| 1263 | } | ||||||||||||
| 1264 | |||||||||||||
| 1265 | void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1266 | // void bcopy(const void *src, void *dst, size_t n); | ||||||||||||
| 1267 | SourceArgExpr Src(CE->getArg(0), 0); | ||||||||||||
| 1268 | DestinationArgExpr Dest = {CE->getArg(1), 1}; | ||||||||||||
| 1269 | SizeArgExpr Size = {CE->getArg(2), 2}; | ||||||||||||
| 1270 | |||||||||||||
| 1271 | constexpr bool IsRestricted = false; | ||||||||||||
| 1272 | constexpr bool IsMempcpy = false; | ||||||||||||
| 1273 | evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); | ||||||||||||
| 1274 | } | ||||||||||||
| 1275 | |||||||||||||
| 1276 | void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1277 | // int memcmp(const void *s1, const void *s2, size_t n); | ||||||||||||
| 1278 | CurrentFunctionDescription = "memory comparison function"; | ||||||||||||
| 1279 | |||||||||||||
| 1280 | AnyArgExpr Left = {CE->getArg(0), 0}; | ||||||||||||
| 1281 | AnyArgExpr Right = {CE->getArg(1), 1}; | ||||||||||||
| 1282 | SizeArgExpr Size = {CE->getArg(2), 2}; | ||||||||||||
| 1283 | |||||||||||||
| 1284 | ProgramStateRef State = C.getState(); | ||||||||||||
| 1285 | SValBuilder &Builder = C.getSValBuilder(); | ||||||||||||
| 1286 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 1287 | |||||||||||||
| 1288 | // See if the size argument is zero. | ||||||||||||
| 1289 | SVal sizeVal = State->getSVal(Size.Expression, LCtx); | ||||||||||||
| 1290 | QualType sizeTy = Size.Expression->getType(); | ||||||||||||
| 1291 | |||||||||||||
| 1292 | ProgramStateRef stateZeroSize, stateNonZeroSize; | ||||||||||||
| 1293 | std::tie(stateZeroSize, stateNonZeroSize) = | ||||||||||||
| 1294 | assumeZero(C, State, sizeVal, sizeTy); | ||||||||||||
| 1295 | |||||||||||||
| 1296 | // If the size can be zero, the result will be 0 in that case, and we don't | ||||||||||||
| 1297 | // have to check either of the buffers. | ||||||||||||
| 1298 | if (stateZeroSize) { | ||||||||||||
| 1299 | State = stateZeroSize; | ||||||||||||
| 1300 | State = State->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType())); | ||||||||||||
| 1301 | C.addTransition(State); | ||||||||||||
| 1302 | } | ||||||||||||
| 1303 | |||||||||||||
| 1304 | // If the size can be nonzero, we have to check the other arguments. | ||||||||||||
| 1305 | if (stateNonZeroSize) { | ||||||||||||
| 1306 | State = stateNonZeroSize; | ||||||||||||
| 1307 | // If we know the two buffers are the same, we know the result is 0. | ||||||||||||
| 1308 | // First, get the two buffers' addresses. Another checker will have already | ||||||||||||
| 1309 | // made sure they're not undefined. | ||||||||||||
| 1310 | DefinedOrUnknownSVal LV = | ||||||||||||
| 1311 | State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 1312 | DefinedOrUnknownSVal RV = | ||||||||||||
| 1313 | State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 1314 | |||||||||||||
| 1315 | // See if they are the same. | ||||||||||||
| 1316 | ProgramStateRef SameBuffer, NotSameBuffer; | ||||||||||||
| 1317 | std::tie(SameBuffer, NotSameBuffer) = | ||||||||||||
| 1318 | State->assume(Builder.evalEQ(State, LV, RV)); | ||||||||||||
| 1319 | |||||||||||||
| 1320 | // If the two arguments are the same buffer, we know the result is 0, | ||||||||||||
| 1321 | // and we only need to check one size. | ||||||||||||
| 1322 | if (SameBuffer && !NotSameBuffer) { | ||||||||||||
| 1323 | State = SameBuffer; | ||||||||||||
| 1324 | State = CheckBufferAccess(C, State, Left, Size, AccessKind::read); | ||||||||||||
| 1325 | if (State) { | ||||||||||||
| 1326 | State = | ||||||||||||
| 1327 | SameBuffer->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType())); | ||||||||||||
| 1328 | C.addTransition(State); | ||||||||||||
| 1329 | } | ||||||||||||
| 1330 | return; | ||||||||||||
| 1331 | } | ||||||||||||
| 1332 | |||||||||||||
| 1333 | // If the two arguments might be different buffers, we have to check | ||||||||||||
| 1334 | // the size of both of them. | ||||||||||||
| 1335 | assert(NotSameBuffer)(static_cast <bool> (NotSameBuffer) ? void (0) : __assert_fail ("NotSameBuffer", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1335, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1336 | State = CheckBufferAccess(C, State, Right, Size, AccessKind::read); | ||||||||||||
| 1337 | State = CheckBufferAccess(C, State, Left, Size, AccessKind::read); | ||||||||||||
| 1338 | if (State) { | ||||||||||||
| 1339 | // The return value is the comparison result, which we don't know. | ||||||||||||
| 1340 | SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); | ||||||||||||
| 1341 | State = State->BindExpr(CE, LCtx, CmpV); | ||||||||||||
| 1342 | C.addTransition(State); | ||||||||||||
| 1343 | } | ||||||||||||
| 1344 | } | ||||||||||||
| 1345 | } | ||||||||||||
| 1346 | |||||||||||||
| 1347 | void CStringChecker::evalstrLength(CheckerContext &C, | ||||||||||||
| 1348 | const CallExpr *CE) const { | ||||||||||||
| 1349 | // size_t strlen(const char *s); | ||||||||||||
| 1350 | evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); | ||||||||||||
| 1351 | } | ||||||||||||
| 1352 | |||||||||||||
| 1353 | void CStringChecker::evalstrnLength(CheckerContext &C, | ||||||||||||
| 1354 | const CallExpr *CE) const { | ||||||||||||
| 1355 | // size_t strnlen(const char *s, size_t maxlen); | ||||||||||||
| 1356 | evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); | ||||||||||||
| |||||||||||||
| 1357 | } | ||||||||||||
| 1358 | |||||||||||||
| 1359 | void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, | ||||||||||||
| 1360 | bool IsStrnlen) const { | ||||||||||||
| 1361 | CurrentFunctionDescription = "string length function"; | ||||||||||||
| 1362 | ProgramStateRef state = C.getState(); | ||||||||||||
| 1363 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 1364 | |||||||||||||
| 1365 | if (IsStrnlen
| ||||||||||||
| 1366 | const Expr *maxlenExpr = CE->getArg(1); | ||||||||||||
| 1367 | SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); | ||||||||||||
| 1368 | |||||||||||||
| 1369 | ProgramStateRef stateZeroSize, stateNonZeroSize; | ||||||||||||
| 1370 | std::tie(stateZeroSize, stateNonZeroSize) = | ||||||||||||
| 1371 | assumeZero(C, state, maxlenVal, maxlenExpr->getType()); | ||||||||||||
| 1372 | |||||||||||||
| 1373 | // If the size can be zero, the result will be 0 in that case, and we don't | ||||||||||||
| 1374 | // have to check the string itself. | ||||||||||||
| 1375 | if (stateZeroSize) { | ||||||||||||
| 1376 | SVal zero = C.getSValBuilder().makeZeroVal(CE->getType()); | ||||||||||||
| 1377 | stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero); | ||||||||||||
| 1378 | C.addTransition(stateZeroSize); | ||||||||||||
| 1379 | } | ||||||||||||
| 1380 | |||||||||||||
| 1381 | // If the size is GUARANTEED to be zero, we're done! | ||||||||||||
| 1382 | if (!stateNonZeroSize) | ||||||||||||
| 1383 | return; | ||||||||||||
| 1384 | |||||||||||||
| 1385 | // Otherwise, record the assumption that the size is nonzero. | ||||||||||||
| 1386 | state = stateNonZeroSize; | ||||||||||||
| 1387 | } | ||||||||||||
| 1388 | |||||||||||||
| 1389 | // Check that the string argument is non-null. | ||||||||||||
| 1390 | AnyArgExpr Arg = {CE->getArg(0), 0}; | ||||||||||||
| 1391 | SVal ArgVal = state->getSVal(Arg.Expression, LCtx); | ||||||||||||
| 1392 | state = checkNonNull(C, state, Arg, ArgVal); | ||||||||||||
| 1393 | |||||||||||||
| 1394 | if (!state) | ||||||||||||
| 1395 | return; | ||||||||||||
| 1396 | |||||||||||||
| 1397 | SVal strLength = getCStringLength(C, state, Arg.Expression, ArgVal); | ||||||||||||
| 1398 | |||||||||||||
| 1399 | // If the argument isn't a valid C string, there's no valid state to | ||||||||||||
| 1400 | // transition to. | ||||||||||||
| 1401 | if (strLength.isUndef()) | ||||||||||||
| 1402 | return; | ||||||||||||
| 1403 | |||||||||||||
| 1404 | DefinedOrUnknownSVal result = UnknownVal(); | ||||||||||||
| 1405 | |||||||||||||
| 1406 | // If the check is for strnlen() then bind the return value to no more than | ||||||||||||
| 1407 | // the maxlen value. | ||||||||||||
| 1408 | if (IsStrnlen
| ||||||||||||
| 1409 | QualType cmpTy = C.getSValBuilder().getConditionType(); | ||||||||||||
| 1410 | |||||||||||||
| 1411 | // It's a little unfortunate to be getting this again, | ||||||||||||
| 1412 | // but it's not that expensive... | ||||||||||||
| 1413 | const Expr *maxlenExpr = CE->getArg(1); | ||||||||||||
| 1414 | SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); | ||||||||||||
| 1415 | |||||||||||||
| 1416 | Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); | ||||||||||||
| 1417 | Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>(); | ||||||||||||
| 1418 | |||||||||||||
| 1419 | if (strLengthNL && maxlenValNL) { | ||||||||||||
| 1420 | ProgramStateRef stateStringTooLong, stateStringNotTooLong; | ||||||||||||
| 1421 | |||||||||||||
| 1422 | // Check if the strLength is greater than the maxlen. | ||||||||||||
| 1423 | std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume( | ||||||||||||
| 1424 | C.getSValBuilder() | ||||||||||||
| 1425 | .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) | ||||||||||||
| 1426 | .castAs<DefinedOrUnknownSVal>()); | ||||||||||||
| 1427 | |||||||||||||
| 1428 | if (stateStringTooLong && !stateStringNotTooLong) { | ||||||||||||
| 1429 | // If the string is longer than maxlen, return maxlen. | ||||||||||||
| 1430 | result = *maxlenValNL; | ||||||||||||
| 1431 | } else if (stateStringNotTooLong && !stateStringTooLong) { | ||||||||||||
| 1432 | // If the string is shorter than maxlen, return its length. | ||||||||||||
| 1433 | result = *strLengthNL; | ||||||||||||
| 1434 | } | ||||||||||||
| 1435 | } | ||||||||||||
| 1436 | |||||||||||||
| 1437 | if (result.isUnknown()) { | ||||||||||||
| 1438 | // If we don't have enough information for a comparison, there's | ||||||||||||
| 1439 | // no guarantee the full string length will actually be returned. | ||||||||||||
| 1440 | // All we know is the return value is the min of the string length | ||||||||||||
| 1441 | // and the limit. This is better than nothing. | ||||||||||||
| 1442 | result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, | ||||||||||||
| 1443 | C.blockCount()); | ||||||||||||
| 1444 | NonLoc resultNL = result.castAs<NonLoc>(); | ||||||||||||
| 1445 | |||||||||||||
| 1446 | if (strLengthNL) { | ||||||||||||
| 1447 | state = state->assume(C.getSValBuilder().evalBinOpNN( | ||||||||||||
| 1448 | state, BO_LE, resultNL, *strLengthNL, cmpTy) | ||||||||||||
| 1449 | .castAs<DefinedOrUnknownSVal>(), true); | ||||||||||||
| 1450 | } | ||||||||||||
| 1451 | |||||||||||||
| 1452 | if (maxlenValNL) { | ||||||||||||
| 1453 | state = state->assume(C.getSValBuilder().evalBinOpNN( | ||||||||||||
| |||||||||||||
| 1454 | state, BO_LE, resultNL, *maxlenValNL, cmpTy) | ||||||||||||
| 1455 | .castAs<DefinedOrUnknownSVal>(), true); | ||||||||||||
| 1456 | } | ||||||||||||
| 1457 | } | ||||||||||||
| 1458 | |||||||||||||
| 1459 | } else { | ||||||||||||
| 1460 | // This is a plain strlen(), not strnlen(). | ||||||||||||
| 1461 | result = strLength.castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 1462 | |||||||||||||
| 1463 | // If we don't know the length of the string, conjure a return | ||||||||||||
| 1464 | // value, so it can be used in constraints, at least. | ||||||||||||
| 1465 | if (result.isUnknown()) { | ||||||||||||
| 1466 | result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, | ||||||||||||
| 1467 | C.blockCount()); | ||||||||||||
| 1468 | } | ||||||||||||
| 1469 | } | ||||||||||||
| 1470 | |||||||||||||
| 1471 | // Bind the return value. | ||||||||||||
| 1472 | assert(!result.isUnknown() && "Should have conjured a value by now")(static_cast <bool> (!result.isUnknown() && "Should have conjured a value by now" ) ? void (0) : __assert_fail ("!result.isUnknown() && \"Should have conjured a value by now\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1472, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1473 | state = state->BindExpr(CE, LCtx, result); | ||||||||||||
| 1474 | C.addTransition(state); | ||||||||||||
| 1475 | } | ||||||||||||
| 1476 | |||||||||||||
| 1477 | void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1478 | // char *strcpy(char *restrict dst, const char *restrict src); | ||||||||||||
| 1479 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1480 | /* ReturnEnd = */ false, | ||||||||||||
| 1481 | /* IsBounded = */ false, | ||||||||||||
| 1482 | /* appendK = */ ConcatFnKind::none); | ||||||||||||
| 1483 | } | ||||||||||||
| 1484 | |||||||||||||
| 1485 | void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1486 | // char *strncpy(char *restrict dst, const char *restrict src, size_t n); | ||||||||||||
| 1487 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1488 | /* ReturnEnd = */ false, | ||||||||||||
| 1489 | /* IsBounded = */ true, | ||||||||||||
| 1490 | /* appendK = */ ConcatFnKind::none); | ||||||||||||
| 1491 | } | ||||||||||||
| 1492 | |||||||||||||
| 1493 | void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1494 | // char *stpcpy(char *restrict dst, const char *restrict src); | ||||||||||||
| 1495 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1496 | /* ReturnEnd = */ true, | ||||||||||||
| 1497 | /* IsBounded = */ false, | ||||||||||||
| 1498 | /* appendK = */ ConcatFnKind::none); | ||||||||||||
| 1499 | } | ||||||||||||
| 1500 | |||||||||||||
| 1501 | void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1502 | // size_t strlcpy(char *dest, const char *src, size_t size); | ||||||||||||
| 1503 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1504 | /* ReturnEnd = */ true, | ||||||||||||
| 1505 | /* IsBounded = */ true, | ||||||||||||
| 1506 | /* appendK = */ ConcatFnKind::none, | ||||||||||||
| 1507 | /* returnPtr = */ false); | ||||||||||||
| 1508 | } | ||||||||||||
| 1509 | |||||||||||||
| 1510 | void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1511 | // char *strcat(char *restrict s1, const char *restrict s2); | ||||||||||||
| 1512 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1513 | /* ReturnEnd = */ false, | ||||||||||||
| 1514 | /* IsBounded = */ false, | ||||||||||||
| 1515 | /* appendK = */ ConcatFnKind::strcat); | ||||||||||||
| 1516 | } | ||||||||||||
| 1517 | |||||||||||||
| 1518 | void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1519 | //char *strncat(char *restrict s1, const char *restrict s2, size_t n); | ||||||||||||
| 1520 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1521 | /* ReturnEnd = */ false, | ||||||||||||
| 1522 | /* IsBounded = */ true, | ||||||||||||
| 1523 | /* appendK = */ ConcatFnKind::strcat); | ||||||||||||
| 1524 | } | ||||||||||||
| 1525 | |||||||||||||
| 1526 | void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1527 | // size_t strlcat(char *dst, const char *src, size_t size); | ||||||||||||
| 1528 | // It will append at most size - strlen(dst) - 1 bytes, | ||||||||||||
| 1529 | // NULL-terminating the result. | ||||||||||||
| 1530 | evalStrcpyCommon(C, CE, | ||||||||||||
| 1531 | /* ReturnEnd = */ false, | ||||||||||||
| 1532 | /* IsBounded = */ true, | ||||||||||||
| 1533 | /* appendK = */ ConcatFnKind::strlcat, | ||||||||||||
| 1534 | /* returnPtr = */ false); | ||||||||||||
| 1535 | } | ||||||||||||
| 1536 | |||||||||||||
| 1537 | void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, | ||||||||||||
| 1538 | bool ReturnEnd, bool IsBounded, | ||||||||||||
| 1539 | ConcatFnKind appendK, | ||||||||||||
| 1540 | bool returnPtr) const { | ||||||||||||
| 1541 | if (appendK == ConcatFnKind::none) | ||||||||||||
| 1542 | CurrentFunctionDescription = "string copy function"; | ||||||||||||
| 1543 | else | ||||||||||||
| 1544 | CurrentFunctionDescription = "string concatenation function"; | ||||||||||||
| 1545 | |||||||||||||
| 1546 | ProgramStateRef state = C.getState(); | ||||||||||||
| 1547 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 1548 | |||||||||||||
| 1549 | // Check that the destination is non-null. | ||||||||||||
| 1550 | DestinationArgExpr Dst = {CE->getArg(0), 0}; | ||||||||||||
| 1551 | SVal DstVal = state->getSVal(Dst.Expression, LCtx); | ||||||||||||
| 1552 | state = checkNonNull(C, state, Dst, DstVal); | ||||||||||||
| 1553 | if (!state) | ||||||||||||
| 1554 | return; | ||||||||||||
| 1555 | |||||||||||||
| 1556 | // Check that the source is non-null. | ||||||||||||
| 1557 | SourceArgExpr srcExpr = {CE->getArg(1), 1}; | ||||||||||||
| 1558 | SVal srcVal = state->getSVal(srcExpr.Expression, LCtx); | ||||||||||||
| 1559 | state = checkNonNull(C, state, srcExpr, srcVal); | ||||||||||||
| 1560 | if (!state) | ||||||||||||
| 1561 | return; | ||||||||||||
| 1562 | |||||||||||||
| 1563 | // Get the string length of the source. | ||||||||||||
| 1564 | SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal); | ||||||||||||
| 1565 | Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); | ||||||||||||
| 1566 | |||||||||||||
| 1567 | // Get the string length of the destination buffer. | ||||||||||||
| 1568 | SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal); | ||||||||||||
| 1569 | Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); | ||||||||||||
| 1570 | |||||||||||||
| 1571 | // If the source isn't a valid C string, give up. | ||||||||||||
| 1572 | if (strLength.isUndef()) | ||||||||||||
| 1573 | return; | ||||||||||||
| 1574 | |||||||||||||
| 1575 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 1576 | QualType cmpTy = svalBuilder.getConditionType(); | ||||||||||||
| 1577 | QualType sizeTy = svalBuilder.getContext().getSizeType(); | ||||||||||||
| 1578 | |||||||||||||
| 1579 | // These two values allow checking two kinds of errors: | ||||||||||||
| 1580 | // - actual overflows caused by a source that doesn't fit in the destination | ||||||||||||
| 1581 | // - potential overflows caused by a bound that could exceed the destination | ||||||||||||
| 1582 | SVal amountCopied = UnknownVal(); | ||||||||||||
| 1583 | SVal maxLastElementIndex = UnknownVal(); | ||||||||||||
| 1584 | const char *boundWarning = nullptr; | ||||||||||||
| 1585 | |||||||||||||
| 1586 | // FIXME: Why do we choose the srcExpr if the access has no size? | ||||||||||||
| 1587 | // Note that the 3rd argument of the call would be the size parameter. | ||||||||||||
| 1588 | SizeArgExpr SrcExprAsSizeDummy = {srcExpr.Expression, srcExpr.ArgumentIndex}; | ||||||||||||
| 1589 | state = CheckOverlap( | ||||||||||||
| 1590 | C, state, | ||||||||||||
| 1591 | (IsBounded ? SizeArgExpr{CE->getArg(2), 2} : SrcExprAsSizeDummy), Dst, | ||||||||||||
| 1592 | srcExpr); | ||||||||||||
| 1593 | |||||||||||||
| 1594 | if (!state) | ||||||||||||
| 1595 | return; | ||||||||||||
| 1596 | |||||||||||||
| 1597 | // If the function is strncpy, strncat, etc... it is bounded. | ||||||||||||
| 1598 | if (IsBounded) { | ||||||||||||
| 1599 | // Get the max number of characters to copy. | ||||||||||||
| 1600 | SizeArgExpr lenExpr = {CE->getArg(2), 2}; | ||||||||||||
| 1601 | SVal lenVal = state->getSVal(lenExpr.Expression, LCtx); | ||||||||||||
| 1602 | |||||||||||||
| 1603 | // Protect against misdeclared strncpy(). | ||||||||||||
| 1604 | lenVal = | ||||||||||||
| 1605 | svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType()); | ||||||||||||
| 1606 | |||||||||||||
| 1607 | Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); | ||||||||||||
| 1608 | |||||||||||||
| 1609 | // If we know both values, we might be able to figure out how much | ||||||||||||
| 1610 | // we're copying. | ||||||||||||
| 1611 | if (strLengthNL && lenValNL) { | ||||||||||||
| 1612 | switch (appendK) { | ||||||||||||
| 1613 | case ConcatFnKind::none: | ||||||||||||
| 1614 | case ConcatFnKind::strcat: { | ||||||||||||
| 1615 | ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; | ||||||||||||
| 1616 | // Check if the max number to copy is less than the length of the src. | ||||||||||||
| 1617 | // If the bound is equal to the source length, strncpy won't null- | ||||||||||||
| 1618 | // terminate the result! | ||||||||||||
| 1619 | std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( | ||||||||||||
| 1620 | svalBuilder | ||||||||||||
| 1621 | .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) | ||||||||||||
| 1622 | .castAs<DefinedOrUnknownSVal>()); | ||||||||||||
| 1623 | |||||||||||||
| 1624 | if (stateSourceTooLong && !stateSourceNotTooLong) { | ||||||||||||
| 1625 | // Max number to copy is less than the length of the src, so the | ||||||||||||
| 1626 | // actual strLength copied is the max number arg. | ||||||||||||
| 1627 | state = stateSourceTooLong; | ||||||||||||
| 1628 | amountCopied = lenVal; | ||||||||||||
| 1629 | |||||||||||||
| 1630 | } else if (!stateSourceTooLong && stateSourceNotTooLong) { | ||||||||||||
| 1631 | // The source buffer entirely fits in the bound. | ||||||||||||
| 1632 | state = stateSourceNotTooLong; | ||||||||||||
| 1633 | amountCopied = strLength; | ||||||||||||
| 1634 | } | ||||||||||||
| 1635 | break; | ||||||||||||
| 1636 | } | ||||||||||||
| 1637 | case ConcatFnKind::strlcat: | ||||||||||||
| 1638 | if (!dstStrLengthNL) | ||||||||||||
| 1639 | return; | ||||||||||||
| 1640 | |||||||||||||
| 1641 | // amountCopied = min (size - dstLen - 1 , srcLen) | ||||||||||||
| 1642 | SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, | ||||||||||||
| 1643 | *dstStrLengthNL, sizeTy); | ||||||||||||
| 1644 | if (!freeSpace.getAs<NonLoc>()) | ||||||||||||
| 1645 | return; | ||||||||||||
| 1646 | freeSpace = | ||||||||||||
| 1647 | svalBuilder.evalBinOp(state, BO_Sub, freeSpace, | ||||||||||||
| 1648 | svalBuilder.makeIntVal(1, sizeTy), sizeTy); | ||||||||||||
| 1649 | Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>(); | ||||||||||||
| 1650 | |||||||||||||
| 1651 | // While unlikely, it is possible that the subtraction is | ||||||||||||
| 1652 | // too complex to compute, let's check whether it succeeded. | ||||||||||||
| 1653 | if (!freeSpaceNL) | ||||||||||||
| 1654 | return; | ||||||||||||
| 1655 | SVal hasEnoughSpace = svalBuilder.evalBinOpNN( | ||||||||||||
| 1656 | state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy); | ||||||||||||
| 1657 | |||||||||||||
| 1658 | ProgramStateRef TrueState, FalseState; | ||||||||||||
| 1659 | std::tie(TrueState, FalseState) = | ||||||||||||
| 1660 | state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>()); | ||||||||||||
| 1661 | |||||||||||||
| 1662 | // srcStrLength <= size - dstStrLength -1 | ||||||||||||
| 1663 | if (TrueState && !FalseState) { | ||||||||||||
| 1664 | amountCopied = strLength; | ||||||||||||
| 1665 | } | ||||||||||||
| 1666 | |||||||||||||
| 1667 | // srcStrLength > size - dstStrLength -1 | ||||||||||||
| 1668 | if (!TrueState && FalseState) { | ||||||||||||
| 1669 | amountCopied = freeSpace; | ||||||||||||
| 1670 | } | ||||||||||||
| 1671 | |||||||||||||
| 1672 | if (TrueState && FalseState) | ||||||||||||
| 1673 | amountCopied = UnknownVal(); | ||||||||||||
| 1674 | break; | ||||||||||||
| 1675 | } | ||||||||||||
| 1676 | } | ||||||||||||
| 1677 | // We still want to know if the bound is known to be too large. | ||||||||||||
| 1678 | if (lenValNL) { | ||||||||||||
| 1679 | switch (appendK) { | ||||||||||||
| 1680 | case ConcatFnKind::strcat: | ||||||||||||
| 1681 | // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) | ||||||||||||
| 1682 | |||||||||||||
| 1683 | // Get the string length of the destination. If the destination is | ||||||||||||
| 1684 | // memory that can't have a string length, we shouldn't be copying | ||||||||||||
| 1685 | // into it anyway. | ||||||||||||
| 1686 | if (dstStrLength.isUndef()) | ||||||||||||
| 1687 | return; | ||||||||||||
| 1688 | |||||||||||||
| 1689 | if (dstStrLengthNL) { | ||||||||||||
| 1690 | maxLastElementIndex = svalBuilder.evalBinOpNN( | ||||||||||||
| 1691 | state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy); | ||||||||||||
| 1692 | |||||||||||||
| 1693 | boundWarning = "Size argument is greater than the free space in the " | ||||||||||||
| 1694 | "destination buffer"; | ||||||||||||
| 1695 | } | ||||||||||||
| 1696 | break; | ||||||||||||
| 1697 | case ConcatFnKind::none: | ||||||||||||
| 1698 | case ConcatFnKind::strlcat: | ||||||||||||
| 1699 | // For strncpy and strlcat, this is just checking | ||||||||||||
| 1700 | // that lenVal <= sizeof(dst). | ||||||||||||
| 1701 | // (Yes, strncpy and strncat differ in how they treat termination. | ||||||||||||
| 1702 | // strncat ALWAYS terminates, but strncpy doesn't.) | ||||||||||||
| 1703 | |||||||||||||
| 1704 | // We need a special case for when the copy size is zero, in which | ||||||||||||
| 1705 | // case strncpy will do no work at all. Our bounds check uses n-1 | ||||||||||||
| 1706 | // as the last element accessed, so n == 0 is problematic. | ||||||||||||
| 1707 | ProgramStateRef StateZeroSize, StateNonZeroSize; | ||||||||||||
| 1708 | std::tie(StateZeroSize, StateNonZeroSize) = | ||||||||||||
| 1709 | assumeZero(C, state, *lenValNL, sizeTy); | ||||||||||||
| 1710 | |||||||||||||
| 1711 | // If the size is known to be zero, we're done. | ||||||||||||
| 1712 | if (StateZeroSize && !StateNonZeroSize) { | ||||||||||||
| 1713 | if (returnPtr) { | ||||||||||||
| 1714 | StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); | ||||||||||||
| 1715 | } else { | ||||||||||||
| 1716 | if (appendK == ConcatFnKind::none) { | ||||||||||||
| 1717 | // strlcpy returns strlen(src) | ||||||||||||
| 1718 | StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength); | ||||||||||||
| 1719 | } else { | ||||||||||||
| 1720 | // strlcat returns strlen(src) + strlen(dst) | ||||||||||||
| 1721 | SVal retSize = svalBuilder.evalBinOp( | ||||||||||||
| 1722 | state, BO_Add, strLength, dstStrLength, sizeTy); | ||||||||||||
| 1723 | StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize); | ||||||||||||
| 1724 | } | ||||||||||||
| 1725 | } | ||||||||||||
| 1726 | C.addTransition(StateZeroSize); | ||||||||||||
| 1727 | return; | ||||||||||||
| 1728 | } | ||||||||||||
| 1729 | |||||||||||||
| 1730 | // Otherwise, go ahead and figure out the last element we'll touch. | ||||||||||||
| 1731 | // We don't record the non-zero assumption here because we can't | ||||||||||||
| 1732 | // be sure. We won't warn on a possible zero. | ||||||||||||
| 1733 | NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); | ||||||||||||
| 1734 | maxLastElementIndex = | ||||||||||||
| 1735 | svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); | ||||||||||||
| 1736 | boundWarning = "Size argument is greater than the length of the " | ||||||||||||
| 1737 | "destination buffer"; | ||||||||||||
| 1738 | break; | ||||||||||||
| 1739 | } | ||||||||||||
| 1740 | } | ||||||||||||
| 1741 | } else { | ||||||||||||
| 1742 | // The function isn't bounded. The amount copied should match the length | ||||||||||||
| 1743 | // of the source buffer. | ||||||||||||
| 1744 | amountCopied = strLength; | ||||||||||||
| 1745 | } | ||||||||||||
| 1746 | |||||||||||||
| 1747 | assert(state)(static_cast <bool> (state) ? void (0) : __assert_fail ( "state", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1747, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1748 | |||||||||||||
| 1749 | // This represents the number of characters copied into the destination | ||||||||||||
| 1750 | // buffer. (It may not actually be the strlen if the destination buffer | ||||||||||||
| 1751 | // is not terminated.) | ||||||||||||
| 1752 | SVal finalStrLength = UnknownVal(); | ||||||||||||
| 1753 | SVal strlRetVal = UnknownVal(); | ||||||||||||
| 1754 | |||||||||||||
| 1755 | if (appendK == ConcatFnKind::none && !returnPtr) { | ||||||||||||
| 1756 | // strlcpy returns the sizeof(src) | ||||||||||||
| 1757 | strlRetVal = strLength; | ||||||||||||
| 1758 | } | ||||||||||||
| 1759 | |||||||||||||
| 1760 | // If this is an appending function (strcat, strncat...) then set the | ||||||||||||
| 1761 | // string length to strlen(src) + strlen(dst) since the buffer will | ||||||||||||
| 1762 | // ultimately contain both. | ||||||||||||
| 1763 | if (appendK != ConcatFnKind::none) { | ||||||||||||
| 1764 | // Get the string length of the destination. If the destination is memory | ||||||||||||
| 1765 | // that can't have a string length, we shouldn't be copying into it anyway. | ||||||||||||
| 1766 | if (dstStrLength.isUndef()) | ||||||||||||
| 1767 | return; | ||||||||||||
| 1768 | |||||||||||||
| 1769 | if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) { | ||||||||||||
| 1770 | strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL, | ||||||||||||
| 1771 | *dstStrLengthNL, sizeTy); | ||||||||||||
| 1772 | } | ||||||||||||
| 1773 | |||||||||||||
| 1774 | Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>(); | ||||||||||||
| 1775 | |||||||||||||
| 1776 | // If we know both string lengths, we might know the final string length. | ||||||||||||
| 1777 | if (amountCopiedNL && dstStrLengthNL) { | ||||||||||||
| 1778 | // Make sure the two lengths together don't overflow a size_t. | ||||||||||||
| 1779 | state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL); | ||||||||||||
| 1780 | if (!state) | ||||||||||||
| 1781 | return; | ||||||||||||
| 1782 | |||||||||||||
| 1783 | finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL, | ||||||||||||
| 1784 | *dstStrLengthNL, sizeTy); | ||||||||||||
| 1785 | } | ||||||||||||
| 1786 | |||||||||||||
| 1787 | // If we couldn't get a single value for the final string length, | ||||||||||||
| 1788 | // we can at least bound it by the individual lengths. | ||||||||||||
| 1789 | if (finalStrLength.isUnknown()) { | ||||||||||||
| 1790 | // Try to get a "hypothetical" string length symbol, which we can later | ||||||||||||
| 1791 | // set as a real value if that turns out to be the case. | ||||||||||||
| 1792 | finalStrLength = getCStringLength(C, state, CE, DstVal, true); | ||||||||||||
| 1793 | assert(!finalStrLength.isUndef())(static_cast <bool> (!finalStrLength.isUndef()) ? void ( 0) : __assert_fail ("!finalStrLength.isUndef()", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1793, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1794 | |||||||||||||
| 1795 | if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { | ||||||||||||
| 1796 | if (amountCopiedNL && appendK == ConcatFnKind::none) { | ||||||||||||
| 1797 | // we overwrite dst string with the src | ||||||||||||
| 1798 | // finalStrLength >= srcStrLength | ||||||||||||
| 1799 | SVal sourceInResult = svalBuilder.evalBinOpNN( | ||||||||||||
| 1800 | state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy); | ||||||||||||
| 1801 | state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), | ||||||||||||
| 1802 | true); | ||||||||||||
| 1803 | if (!state) | ||||||||||||
| 1804 | return; | ||||||||||||
| 1805 | } | ||||||||||||
| 1806 | |||||||||||||
| 1807 | if (dstStrLengthNL && appendK != ConcatFnKind::none) { | ||||||||||||
| 1808 | // we extend the dst string with the src | ||||||||||||
| 1809 | // finalStrLength >= dstStrLength | ||||||||||||
| 1810 | SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, | ||||||||||||
| 1811 | *finalStrLengthNL, | ||||||||||||
| 1812 | *dstStrLengthNL, | ||||||||||||
| 1813 | cmpTy); | ||||||||||||
| 1814 | state = | ||||||||||||
| 1815 | state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true); | ||||||||||||
| 1816 | if (!state) | ||||||||||||
| 1817 | return; | ||||||||||||
| 1818 | } | ||||||||||||
| 1819 | } | ||||||||||||
| 1820 | } | ||||||||||||
| 1821 | |||||||||||||
| 1822 | } else { | ||||||||||||
| 1823 | // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and | ||||||||||||
| 1824 | // the final string length will match the input string length. | ||||||||||||
| 1825 | finalStrLength = amountCopied; | ||||||||||||
| 1826 | } | ||||||||||||
| 1827 | |||||||||||||
| 1828 | SVal Result; | ||||||||||||
| 1829 | |||||||||||||
| 1830 | if (returnPtr) { | ||||||||||||
| 1831 | // The final result of the function will either be a pointer past the last | ||||||||||||
| 1832 | // copied element, or a pointer to the start of the destination buffer. | ||||||||||||
| 1833 | Result = (ReturnEnd ? UnknownVal() : DstVal); | ||||||||||||
| 1834 | } else { | ||||||||||||
| 1835 | if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none) | ||||||||||||
| 1836 | //strlcpy, strlcat | ||||||||||||
| 1837 | Result = strlRetVal; | ||||||||||||
| 1838 | else | ||||||||||||
| 1839 | Result = finalStrLength; | ||||||||||||
| 1840 | } | ||||||||||||
| 1841 | |||||||||||||
| 1842 | assert(state)(static_cast <bool> (state) ? void (0) : __assert_fail ( "state", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1842, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1843 | |||||||||||||
| 1844 | // If the destination is a MemRegion, try to check for a buffer overflow and | ||||||||||||
| 1845 | // record the new string length. | ||||||||||||
| 1846 | if (Optional<loc::MemRegionVal> dstRegVal = | ||||||||||||
| 1847 | DstVal.getAs<loc::MemRegionVal>()) { | ||||||||||||
| 1848 | QualType ptrTy = Dst.Expression->getType(); | ||||||||||||
| 1849 | |||||||||||||
| 1850 | // If we have an exact value on a bounded copy, use that to check for | ||||||||||||
| 1851 | // overflows, rather than our estimate about how much is actually copied. | ||||||||||||
| 1852 | if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { | ||||||||||||
| 1853 | SVal maxLastElement = | ||||||||||||
| 1854 | svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy); | ||||||||||||
| 1855 | |||||||||||||
| 1856 | state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write); | ||||||||||||
| 1857 | if (!state) | ||||||||||||
| 1858 | return; | ||||||||||||
| 1859 | } | ||||||||||||
| 1860 | |||||||||||||
| 1861 | // Then, if the final length is known... | ||||||||||||
| 1862 | if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) { | ||||||||||||
| 1863 | SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, | ||||||||||||
| 1864 | *knownStrLength, ptrTy); | ||||||||||||
| 1865 | |||||||||||||
| 1866 | // ...and we haven't checked the bound, we'll check the actual copy. | ||||||||||||
| 1867 | if (!boundWarning) { | ||||||||||||
| 1868 | state = CheckLocation(C, state, Dst, lastElement, AccessKind::write); | ||||||||||||
| 1869 | if (!state) | ||||||||||||
| 1870 | return; | ||||||||||||
| 1871 | } | ||||||||||||
| 1872 | |||||||||||||
| 1873 | // If this is a stpcpy-style copy, the last element is the return value. | ||||||||||||
| 1874 | if (returnPtr && ReturnEnd) | ||||||||||||
| 1875 | Result = lastElement; | ||||||||||||
| 1876 | } | ||||||||||||
| 1877 | |||||||||||||
| 1878 | // Invalidate the destination (regular invalidation without pointer-escaping | ||||||||||||
| 1879 | // the address of the top-level region). This must happen before we set the | ||||||||||||
| 1880 | // C string length because invalidation will clear the length. | ||||||||||||
| 1881 | // FIXME: Even if we can't perfectly model the copy, we should see if we | ||||||||||||
| 1882 | // can use LazyCompoundVals to copy the source values into the destination. | ||||||||||||
| 1883 | // This would probably remove any existing bindings past the end of the | ||||||||||||
| 1884 | // string, but that's still an improvement over blank invalidation. | ||||||||||||
| 1885 | state = InvalidateBuffer(C, state, Dst.Expression, *dstRegVal, | ||||||||||||
| 1886 | /*IsSourceBuffer*/ false, nullptr); | ||||||||||||
| 1887 | |||||||||||||
| 1888 | // Invalidate the source (const-invalidation without const-pointer-escaping | ||||||||||||
| 1889 | // the address of the top-level region). | ||||||||||||
| 1890 | state = InvalidateBuffer(C, state, srcExpr.Expression, srcVal, | ||||||||||||
| 1891 | /*IsSourceBuffer*/ true, nullptr); | ||||||||||||
| 1892 | |||||||||||||
| 1893 | // Set the C string length of the destination, if we know it. | ||||||||||||
| 1894 | if (IsBounded && (appendK == ConcatFnKind::none)) { | ||||||||||||
| 1895 | // strncpy is annoying in that it doesn't guarantee to null-terminate | ||||||||||||
| 1896 | // the result string. If the original string didn't fit entirely inside | ||||||||||||
| 1897 | // the bound (including the null-terminator), we don't know how long the | ||||||||||||
| 1898 | // result is. | ||||||||||||
| 1899 | if (amountCopied != strLength) | ||||||||||||
| 1900 | finalStrLength = UnknownVal(); | ||||||||||||
| 1901 | } | ||||||||||||
| 1902 | state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength); | ||||||||||||
| 1903 | } | ||||||||||||
| 1904 | |||||||||||||
| 1905 | assert(state)(static_cast <bool> (state) ? void (0) : __assert_fail ( "state", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1905, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1906 | |||||||||||||
| 1907 | if (returnPtr) { | ||||||||||||
| 1908 | // If this is a stpcpy-style copy, but we were unable to check for a buffer | ||||||||||||
| 1909 | // overflow, we still need a result. Conjure a return value. | ||||||||||||
| 1910 | if (ReturnEnd && Result.isUnknown()) { | ||||||||||||
| 1911 | Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); | ||||||||||||
| 1912 | } | ||||||||||||
| 1913 | } | ||||||||||||
| 1914 | // Set the return value. | ||||||||||||
| 1915 | state = state->BindExpr(CE, LCtx, Result); | ||||||||||||
| 1916 | C.addTransition(state); | ||||||||||||
| 1917 | } | ||||||||||||
| 1918 | |||||||||||||
| 1919 | void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1920 | //int strcmp(const char *s1, const char *s2); | ||||||||||||
| 1921 | evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false); | ||||||||||||
| 1922 | } | ||||||||||||
| 1923 | |||||||||||||
| 1924 | void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 1925 | //int strncmp(const char *s1, const char *s2, size_t n); | ||||||||||||
| 1926 | evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false); | ||||||||||||
| 1927 | } | ||||||||||||
| 1928 | |||||||||||||
| 1929 | void CStringChecker::evalStrcasecmp(CheckerContext &C, | ||||||||||||
| 1930 | const CallExpr *CE) const { | ||||||||||||
| 1931 | //int strcasecmp(const char *s1, const char *s2); | ||||||||||||
| 1932 | evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true); | ||||||||||||
| 1933 | } | ||||||||||||
| 1934 | |||||||||||||
| 1935 | void CStringChecker::evalStrncasecmp(CheckerContext &C, | ||||||||||||
| 1936 | const CallExpr *CE) const { | ||||||||||||
| 1937 | //int strncasecmp(const char *s1, const char *s2, size_t n); | ||||||||||||
| 1938 | evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true); | ||||||||||||
| 1939 | } | ||||||||||||
| 1940 | |||||||||||||
| 1941 | void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, | ||||||||||||
| 1942 | bool IsBounded, bool IgnoreCase) const { | ||||||||||||
| 1943 | CurrentFunctionDescription = "string comparison function"; | ||||||||||||
| 1944 | ProgramStateRef state = C.getState(); | ||||||||||||
| 1945 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 1946 | |||||||||||||
| 1947 | // Check that the first string is non-null | ||||||||||||
| 1948 | AnyArgExpr Left = {CE->getArg(0), 0}; | ||||||||||||
| 1949 | SVal LeftVal = state->getSVal(Left.Expression, LCtx); | ||||||||||||
| 1950 | state = checkNonNull(C, state, Left, LeftVal); | ||||||||||||
| 1951 | if (!state) | ||||||||||||
| 1952 | return; | ||||||||||||
| 1953 | |||||||||||||
| 1954 | // Check that the second string is non-null. | ||||||||||||
| 1955 | AnyArgExpr Right = {CE->getArg(1), 1}; | ||||||||||||
| 1956 | SVal RightVal = state->getSVal(Right.Expression, LCtx); | ||||||||||||
| 1957 | state = checkNonNull(C, state, Right, RightVal); | ||||||||||||
| 1958 | if (!state) | ||||||||||||
| 1959 | return; | ||||||||||||
| 1960 | |||||||||||||
| 1961 | // Get the string length of the first string or give up. | ||||||||||||
| 1962 | SVal LeftLength = getCStringLength(C, state, Left.Expression, LeftVal); | ||||||||||||
| 1963 | if (LeftLength.isUndef()) | ||||||||||||
| 1964 | return; | ||||||||||||
| 1965 | |||||||||||||
| 1966 | // Get the string length of the second string or give up. | ||||||||||||
| 1967 | SVal RightLength = getCStringLength(C, state, Right.Expression, RightVal); | ||||||||||||
| 1968 | if (RightLength.isUndef()) | ||||||||||||
| 1969 | return; | ||||||||||||
| 1970 | |||||||||||||
| 1971 | // If we know the two buffers are the same, we know the result is 0. | ||||||||||||
| 1972 | // First, get the two buffers' addresses. Another checker will have already | ||||||||||||
| 1973 | // made sure they're not undefined. | ||||||||||||
| 1974 | DefinedOrUnknownSVal LV = LeftVal.castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 1975 | DefinedOrUnknownSVal RV = RightVal.castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 1976 | |||||||||||||
| 1977 | // See if they are the same. | ||||||||||||
| 1978 | SValBuilder &svalBuilder = C.getSValBuilder(); | ||||||||||||
| 1979 | DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); | ||||||||||||
| 1980 | ProgramStateRef StSameBuf, StNotSameBuf; | ||||||||||||
| 1981 | std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); | ||||||||||||
| 1982 | |||||||||||||
| 1983 | // If the two arguments might be the same buffer, we know the result is 0, | ||||||||||||
| 1984 | // and we only need to check one size. | ||||||||||||
| 1985 | if (StSameBuf) { | ||||||||||||
| 1986 | StSameBuf = StSameBuf->BindExpr(CE, LCtx, | ||||||||||||
| 1987 | svalBuilder.makeZeroVal(CE->getType())); | ||||||||||||
| 1988 | C.addTransition(StSameBuf); | ||||||||||||
| 1989 | |||||||||||||
| 1990 | // If the two arguments are GUARANTEED to be the same, we're done! | ||||||||||||
| 1991 | if (!StNotSameBuf) | ||||||||||||
| 1992 | return; | ||||||||||||
| 1993 | } | ||||||||||||
| 1994 | |||||||||||||
| 1995 | assert(StNotSameBuf)(static_cast <bool> (StNotSameBuf) ? void (0) : __assert_fail ("StNotSameBuf", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 1995, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 1996 | state = StNotSameBuf; | ||||||||||||
| 1997 | |||||||||||||
| 1998 | // At this point we can go about comparing the two buffers. | ||||||||||||
| 1999 | // For now, we only do this if they're both known string literals. | ||||||||||||
| 2000 | |||||||||||||
| 2001 | // Attempt to extract string literals from both expressions. | ||||||||||||
| 2002 | const StringLiteral *LeftStrLiteral = | ||||||||||||
| 2003 | getCStringLiteral(C, state, Left.Expression, LeftVal); | ||||||||||||
| 2004 | const StringLiteral *RightStrLiteral = | ||||||||||||
| 2005 | getCStringLiteral(C, state, Right.Expression, RightVal); | ||||||||||||
| 2006 | bool canComputeResult = false; | ||||||||||||
| 2007 | SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, | ||||||||||||
| 2008 | C.blockCount()); | ||||||||||||
| 2009 | |||||||||||||
| 2010 | if (LeftStrLiteral && RightStrLiteral) { | ||||||||||||
| 2011 | StringRef LeftStrRef = LeftStrLiteral->getString(); | ||||||||||||
| 2012 | StringRef RightStrRef = RightStrLiteral->getString(); | ||||||||||||
| 2013 | |||||||||||||
| 2014 | if (IsBounded) { | ||||||||||||
| 2015 | // Get the max number of characters to compare. | ||||||||||||
| 2016 | const Expr *lenExpr = CE->getArg(2); | ||||||||||||
| 2017 | SVal lenVal = state->getSVal(lenExpr, LCtx); | ||||||||||||
| 2018 | |||||||||||||
| 2019 | // If the length is known, we can get the right substrings. | ||||||||||||
| 2020 | if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) { | ||||||||||||
| 2021 | // Create substrings of each to compare the prefix. | ||||||||||||
| 2022 | LeftStrRef = LeftStrRef.substr(0, (size_t)len->getZExtValue()); | ||||||||||||
| 2023 | RightStrRef = RightStrRef.substr(0, (size_t)len->getZExtValue()); | ||||||||||||
| 2024 | canComputeResult = true; | ||||||||||||
| 2025 | } | ||||||||||||
| 2026 | } else { | ||||||||||||
| 2027 | // This is a normal, unbounded strcmp. | ||||||||||||
| 2028 | canComputeResult = true; | ||||||||||||
| 2029 | } | ||||||||||||
| 2030 | |||||||||||||
| 2031 | if (canComputeResult) { | ||||||||||||
| 2032 | // Real strcmp stops at null characters. | ||||||||||||
| 2033 | size_t s1Term = LeftStrRef.find('\0'); | ||||||||||||
| 2034 | if (s1Term != StringRef::npos) | ||||||||||||
| 2035 | LeftStrRef = LeftStrRef.substr(0, s1Term); | ||||||||||||
| 2036 | |||||||||||||
| 2037 | size_t s2Term = RightStrRef.find('\0'); | ||||||||||||
| 2038 | if (s2Term != StringRef::npos) | ||||||||||||
| 2039 | RightStrRef = RightStrRef.substr(0, s2Term); | ||||||||||||
| 2040 | |||||||||||||
| 2041 | // Use StringRef's comparison methods to compute the actual result. | ||||||||||||
| 2042 | int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef) | ||||||||||||
| 2043 | : LeftStrRef.compare(RightStrRef); | ||||||||||||
| 2044 | |||||||||||||
| 2045 | // The strcmp function returns an integer greater than, equal to, or less | ||||||||||||
| 2046 | // than zero, [c11, p7.24.4.2]. | ||||||||||||
| 2047 | if (compareRes == 0) { | ||||||||||||
| 2048 | resultVal = svalBuilder.makeIntVal(compareRes, CE->getType()); | ||||||||||||
| 2049 | } | ||||||||||||
| 2050 | else { | ||||||||||||
| 2051 | DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType()); | ||||||||||||
| 2052 | // Constrain strcmp's result range based on the result of StringRef's | ||||||||||||
| 2053 | // comparison methods. | ||||||||||||
| 2054 | BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT; | ||||||||||||
| 2055 | SVal compareWithZero = | ||||||||||||
| 2056 | svalBuilder.evalBinOp(state, op, resultVal, zeroVal, | ||||||||||||
| 2057 | svalBuilder.getConditionType()); | ||||||||||||
| 2058 | DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>(); | ||||||||||||
| 2059 | state = state->assume(compareWithZeroVal, true); | ||||||||||||
| 2060 | } | ||||||||||||
| 2061 | } | ||||||||||||
| 2062 | } | ||||||||||||
| 2063 | |||||||||||||
| 2064 | state = state->BindExpr(CE, LCtx, resultVal); | ||||||||||||
| 2065 | |||||||||||||
| 2066 | // Record this as a possible path. | ||||||||||||
| 2067 | C.addTransition(state); | ||||||||||||
| 2068 | } | ||||||||||||
| 2069 | |||||||||||||
| 2070 | void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 2071 | //char *strsep(char **stringp, const char *delim); | ||||||||||||
| 2072 | // Sanity: does the search string parameter match the return type? | ||||||||||||
| 2073 | SourceArgExpr SearchStrPtr = {CE->getArg(0), 0}; | ||||||||||||
| 2074 | |||||||||||||
| 2075 | QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType(); | ||||||||||||
| 2076 | if (CharPtrTy.isNull() || | ||||||||||||
| 2077 | CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) | ||||||||||||
| 2078 | return; | ||||||||||||
| 2079 | |||||||||||||
| 2080 | CurrentFunctionDescription = "strsep()"; | ||||||||||||
| 2081 | ProgramStateRef State = C.getState(); | ||||||||||||
| 2082 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 2083 | |||||||||||||
| 2084 | // Check that the search string pointer is non-null (though it may point to | ||||||||||||
| 2085 | // a null string). | ||||||||||||
| 2086 | SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx); | ||||||||||||
| 2087 | State = checkNonNull(C, State, SearchStrPtr, SearchStrVal); | ||||||||||||
| 2088 | if (!State) | ||||||||||||
| 2089 | return; | ||||||||||||
| 2090 | |||||||||||||
| 2091 | // Check that the delimiter string is non-null. | ||||||||||||
| 2092 | AnyArgExpr DelimStr = {CE->getArg(1), 1}; | ||||||||||||
| 2093 | SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx); | ||||||||||||
| 2094 | State = checkNonNull(C, State, DelimStr, DelimStrVal); | ||||||||||||
| 2095 | if (!State) | ||||||||||||
| 2096 | return; | ||||||||||||
| 2097 | |||||||||||||
| 2098 | SValBuilder &SVB = C.getSValBuilder(); | ||||||||||||
| 2099 | SVal Result; | ||||||||||||
| 2100 | if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { | ||||||||||||
| 2101 | // Get the current value of the search string pointer, as a char*. | ||||||||||||
| 2102 | Result = State->getSVal(*SearchStrLoc, CharPtrTy); | ||||||||||||
| 2103 | |||||||||||||
| 2104 | // Invalidate the search string, representing the change of one delimiter | ||||||||||||
| 2105 | // character to NUL. | ||||||||||||
| 2106 | State = InvalidateBuffer(C, State, SearchStrPtr.Expression, Result, | ||||||||||||
| 2107 | /*IsSourceBuffer*/ false, nullptr); | ||||||||||||
| 2108 | |||||||||||||
| 2109 | // Overwrite the search string pointer. The new value is either an address | ||||||||||||
| 2110 | // further along in the same string, or NULL if there are no more tokens. | ||||||||||||
| 2111 | State = State->bindLoc(*SearchStrLoc, | ||||||||||||
| 2112 | SVB.conjureSymbolVal(getTag(), | ||||||||||||
| 2113 | CE, | ||||||||||||
| 2114 | LCtx, | ||||||||||||
| 2115 | CharPtrTy, | ||||||||||||
| 2116 | C.blockCount()), | ||||||||||||
| 2117 | LCtx); | ||||||||||||
| 2118 | } else { | ||||||||||||
| 2119 | assert(SearchStrVal.isUnknown())(static_cast <bool> (SearchStrVal.isUnknown()) ? void ( 0) : __assert_fail ("SearchStrVal.isUnknown()", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 2119, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 2120 | // Conjure a symbolic value. It's the best we can do. | ||||||||||||
| 2121 | Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); | ||||||||||||
| 2122 | } | ||||||||||||
| 2123 | |||||||||||||
| 2124 | // Set the return value, and finish. | ||||||||||||
| 2125 | State = State->BindExpr(CE, LCtx, Result); | ||||||||||||
| 2126 | C.addTransition(State); | ||||||||||||
| 2127 | } | ||||||||||||
| 2128 | |||||||||||||
| 2129 | // These should probably be moved into a C++ standard library checker. | ||||||||||||
| 2130 | void CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 2131 | evalStdCopyCommon(C, CE); | ||||||||||||
| 2132 | } | ||||||||||||
| 2133 | |||||||||||||
| 2134 | void CStringChecker::evalStdCopyBackward(CheckerContext &C, | ||||||||||||
| 2135 | const CallExpr *CE) const { | ||||||||||||
| 2136 | evalStdCopyCommon(C, CE); | ||||||||||||
| 2137 | } | ||||||||||||
| 2138 | |||||||||||||
| 2139 | void CStringChecker::evalStdCopyCommon(CheckerContext &C, | ||||||||||||
| 2140 | const CallExpr *CE) const { | ||||||||||||
| 2141 | if (!CE->getArg(2)->getType()->isPointerType()) | ||||||||||||
| 2142 | return; | ||||||||||||
| 2143 | |||||||||||||
| 2144 | ProgramStateRef State = C.getState(); | ||||||||||||
| 2145 | |||||||||||||
| 2146 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 2147 | |||||||||||||
| 2148 | // template <class _InputIterator, class _OutputIterator> | ||||||||||||
| 2149 | // _OutputIterator | ||||||||||||
| 2150 | // copy(_InputIterator __first, _InputIterator __last, | ||||||||||||
| 2151 | // _OutputIterator __result) | ||||||||||||
| 2152 | |||||||||||||
| 2153 | // Invalidate the destination buffer | ||||||||||||
| 2154 | const Expr *Dst = CE->getArg(2); | ||||||||||||
| 2155 | SVal DstVal = State->getSVal(Dst, LCtx); | ||||||||||||
| 2156 | State = InvalidateBuffer(C, State, Dst, DstVal, /*IsSource=*/false, | ||||||||||||
| 2157 | /*Size=*/nullptr); | ||||||||||||
| 2158 | |||||||||||||
| 2159 | SValBuilder &SVB = C.getSValBuilder(); | ||||||||||||
| 2160 | |||||||||||||
| 2161 | SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); | ||||||||||||
| 2162 | State = State->BindExpr(CE, LCtx, ResultVal); | ||||||||||||
| 2163 | |||||||||||||
| 2164 | C.addTransition(State); | ||||||||||||
| 2165 | } | ||||||||||||
| 2166 | |||||||||||||
| 2167 | void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 2168 | // void *memset(void *s, int c, size_t n); | ||||||||||||
| 2169 | CurrentFunctionDescription = "memory set function"; | ||||||||||||
| 2170 | |||||||||||||
| 2171 | DestinationArgExpr Buffer = {CE->getArg(0), 0}; | ||||||||||||
| 2172 | AnyArgExpr CharE = {CE->getArg(1), 1}; | ||||||||||||
| 2173 | SizeArgExpr Size = {CE->getArg(2), 2}; | ||||||||||||
| 2174 | |||||||||||||
| 2175 | ProgramStateRef State = C.getState(); | ||||||||||||
| 2176 | |||||||||||||
| 2177 | // See if the size argument is zero. | ||||||||||||
| 2178 | const LocationContext *LCtx = C.getLocationContext(); | ||||||||||||
| 2179 | SVal SizeVal = C.getSVal(Size.Expression); | ||||||||||||
| 2180 | QualType SizeTy = Size.Expression->getType(); | ||||||||||||
| 2181 | |||||||||||||
| 2182 | ProgramStateRef ZeroSize, NonZeroSize; | ||||||||||||
| 2183 | std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy); | ||||||||||||
| 2184 | |||||||||||||
| 2185 | // Get the value of the memory area. | ||||||||||||
| 2186 | SVal BufferPtrVal = C.getSVal(Buffer.Expression); | ||||||||||||
| 2187 | |||||||||||||
| 2188 | // If the size is zero, there won't be any actual memory access, so | ||||||||||||
| 2189 | // just bind the return value to the buffer and return. | ||||||||||||
| 2190 | if (ZeroSize && !NonZeroSize) { | ||||||||||||
| 2191 | ZeroSize = ZeroSize->BindExpr(CE, LCtx, BufferPtrVal); | ||||||||||||
| 2192 | C.addTransition(ZeroSize); | ||||||||||||
| 2193 | return; | ||||||||||||
| 2194 | } | ||||||||||||
| 2195 | |||||||||||||
| 2196 | // Ensure the memory area is not null. | ||||||||||||
| 2197 | // If it is NULL there will be a NULL pointer dereference. | ||||||||||||
| 2198 | State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal); | ||||||||||||
| 2199 | if (!State) | ||||||||||||
| 2200 | return; | ||||||||||||
| 2201 | |||||||||||||
| 2202 | State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write); | ||||||||||||
| 2203 | if (!State) | ||||||||||||
| 2204 | return; | ||||||||||||
| 2205 | |||||||||||||
| 2206 | // According to the values of the arguments, bind the value of the second | ||||||||||||
| 2207 | // argument to the destination buffer and set string length, or just | ||||||||||||
| 2208 | // invalidate the destination buffer. | ||||||||||||
| 2209 | if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression), | ||||||||||||
| 2210 | Size.Expression, C, State)) | ||||||||||||
| 2211 | return; | ||||||||||||
| 2212 | |||||||||||||
| 2213 | State = State->BindExpr(CE, LCtx, BufferPtrVal); | ||||||||||||
| 2214 | C.addTransition(State); | ||||||||||||
| 2215 | } | ||||||||||||
| 2216 | |||||||||||||
| 2217 | void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { | ||||||||||||
| 2218 | CurrentFunctionDescription = "memory clearance function"; | ||||||||||||
| 2219 | |||||||||||||
| 2220 | DestinationArgExpr Buffer = {CE->getArg(0), 0}; | ||||||||||||
| 2221 | SizeArgExpr Size = {CE->getArg(1), 1}; | ||||||||||||
| 2222 | SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); | ||||||||||||
| 2223 | |||||||||||||
| 2224 | ProgramStateRef State = C.getState(); | ||||||||||||
| 2225 | |||||||||||||
| 2226 | // See if the size argument is zero. | ||||||||||||
| 2227 | SVal SizeVal = C.getSVal(Size.Expression); | ||||||||||||
| 2228 | QualType SizeTy = Size.Expression->getType(); | ||||||||||||
| 2229 | |||||||||||||
| 2230 | ProgramStateRef StateZeroSize, StateNonZeroSize; | ||||||||||||
| 2231 | std::tie(StateZeroSize, StateNonZeroSize) = | ||||||||||||
| 2232 | assumeZero(C, State, SizeVal, SizeTy); | ||||||||||||
| 2233 | |||||||||||||
| 2234 | // If the size is zero, there won't be any actual memory access, | ||||||||||||
| 2235 | // In this case we just return. | ||||||||||||
| 2236 | if (StateZeroSize && !StateNonZeroSize) { | ||||||||||||
| 2237 | C.addTransition(StateZeroSize); | ||||||||||||
| 2238 | return; | ||||||||||||
| 2239 | } | ||||||||||||
| 2240 | |||||||||||||
| 2241 | // Get the value of the memory area. | ||||||||||||
| 2242 | SVal MemVal = C.getSVal(Buffer.Expression); | ||||||||||||
| 2243 | |||||||||||||
| 2244 | // Ensure the memory area is not null. | ||||||||||||
| 2245 | // If it is NULL there will be a NULL pointer dereference. | ||||||||||||
| 2246 | State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal); | ||||||||||||
| 2247 | if (!State) | ||||||||||||
| 2248 | return; | ||||||||||||
| 2249 | |||||||||||||
| 2250 | State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write); | ||||||||||||
| 2251 | if (!State) | ||||||||||||
| 2252 | return; | ||||||||||||
| 2253 | |||||||||||||
| 2254 | if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State)) | ||||||||||||
| 2255 | return; | ||||||||||||
| 2256 | |||||||||||||
| 2257 | C.addTransition(State); | ||||||||||||
| 2258 | } | ||||||||||||
| 2259 | |||||||||||||
| 2260 | //===----------------------------------------------------------------------===// | ||||||||||||
| 2261 | // The driver method, and other Checker callbacks. | ||||||||||||
| 2262 | //===----------------------------------------------------------------------===// | ||||||||||||
| 2263 | |||||||||||||
| 2264 | CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call, | ||||||||||||
| 2265 | CheckerContext &C) const { | ||||||||||||
| 2266 | const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); | ||||||||||||
| 2267 | if (!CE) | ||||||||||||
| 2268 | return nullptr; | ||||||||||||
| 2269 | |||||||||||||
| 2270 | const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); | ||||||||||||
| 2271 | if (!FD) | ||||||||||||
| 2272 | return nullptr; | ||||||||||||
| 2273 | |||||||||||||
| 2274 | if (Call.isCalled(StdCopy)) { | ||||||||||||
| 2275 | return &CStringChecker::evalStdCopy; | ||||||||||||
| 2276 | } else if (Call.isCalled(StdCopyBackward)) { | ||||||||||||
| 2277 | return &CStringChecker::evalStdCopyBackward; | ||||||||||||
| 2278 | } | ||||||||||||
| 2279 | |||||||||||||
| 2280 | // Pro-actively check that argument types are safe to do arithmetic upon. | ||||||||||||
| 2281 | // We do not want to crash if someone accidentally passes a structure | ||||||||||||
| 2282 | // into, say, a C++ overload of any of these functions. We could not check | ||||||||||||
| 2283 | // that for std::copy because they may have arguments of other types. | ||||||||||||
| 2284 | for (auto I : CE->arguments()) { | ||||||||||||
| 2285 | QualType T = I->getType(); | ||||||||||||
| 2286 | if (!T->isIntegralOrEnumerationType() && !T->isPointerType()) | ||||||||||||
| 2287 | return nullptr; | ||||||||||||
| 2288 | } | ||||||||||||
| 2289 | |||||||||||||
| 2290 | const FnCheck *Callback = Callbacks.lookup(Call); | ||||||||||||
| 2291 | if (Callback) | ||||||||||||
| 2292 | return *Callback; | ||||||||||||
| 2293 | |||||||||||||
| 2294 | return nullptr; | ||||||||||||
| 2295 | } | ||||||||||||
| 2296 | |||||||||||||
| 2297 | bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { | ||||||||||||
| 2298 | FnCheck Callback = identifyCall(Call, C); | ||||||||||||
| 2299 | |||||||||||||
| 2300 | // If the callee isn't a string function, let another checker handle it. | ||||||||||||
| 2301 | if (!Callback) | ||||||||||||
| 2302 | return false; | ||||||||||||
| 2303 | |||||||||||||
| 2304 | // Check and evaluate the call. | ||||||||||||
| 2305 | const auto *CE = cast<CallExpr>(Call.getOriginExpr()); | ||||||||||||
| 2306 | (this->*Callback)(C, CE); | ||||||||||||
| 2307 | |||||||||||||
| 2308 | // If the evaluate call resulted in no change, chain to the next eval call | ||||||||||||
| 2309 | // handler. | ||||||||||||
| 2310 | // Note, the custom CString evaluation calls assume that basic safety | ||||||||||||
| 2311 | // properties are held. However, if the user chooses to turn off some of these | ||||||||||||
| 2312 | // checks, we ignore the issues and leave the call evaluation to a generic | ||||||||||||
| 2313 | // handler. | ||||||||||||
| 2314 | return C.isDifferent(); | ||||||||||||
| 2315 | } | ||||||||||||
| 2316 | |||||||||||||
| 2317 | void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { | ||||||||||||
| 2318 | // Record string length for char a[] = "abc"; | ||||||||||||
| 2319 | ProgramStateRef state = C.getState(); | ||||||||||||
| 2320 | |||||||||||||
| 2321 | for (const auto *I : DS->decls()) { | ||||||||||||
| 2322 | const VarDecl *D = dyn_cast<VarDecl>(I); | ||||||||||||
| 2323 | if (!D) | ||||||||||||
| 2324 | continue; | ||||||||||||
| 2325 | |||||||||||||
| 2326 | // FIXME: Handle array fields of structs. | ||||||||||||
| 2327 | if (!D->getType()->isArrayType()) | ||||||||||||
| 2328 | continue; | ||||||||||||
| 2329 | |||||||||||||
| 2330 | const Expr *Init = D->getInit(); | ||||||||||||
| 2331 | if (!Init) | ||||||||||||
| 2332 | continue; | ||||||||||||
| 2333 | if (!isa<StringLiteral>(Init)) | ||||||||||||
| 2334 | continue; | ||||||||||||
| 2335 | |||||||||||||
| 2336 | Loc VarLoc = state->getLValue(D, C.getLocationContext()); | ||||||||||||
| 2337 | const MemRegion *MR = VarLoc.getAsRegion(); | ||||||||||||
| 2338 | if (!MR) | ||||||||||||
| 2339 | continue; | ||||||||||||
| 2340 | |||||||||||||
| 2341 | SVal StrVal = C.getSVal(Init); | ||||||||||||
| 2342 | assert(StrVal.isValid() && "Initializer string is unknown or undefined")(static_cast <bool> (StrVal.isValid() && "Initializer string is unknown or undefined" ) ? void (0) : __assert_fail ("StrVal.isValid() && \"Initializer string is unknown or undefined\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp" , 2342, __extension__ __PRETTY_FUNCTION__)); | ||||||||||||
| 2343 | DefinedOrUnknownSVal strLength = | ||||||||||||
| 2344 | getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>(); | ||||||||||||
| 2345 | |||||||||||||
| 2346 | state = state->set<CStringLength>(MR, strLength); | ||||||||||||
| 2347 | } | ||||||||||||
| 2348 | |||||||||||||
| 2349 | C.addTransition(state); | ||||||||||||
| 2350 | } | ||||||||||||
| 2351 | |||||||||||||
| 2352 | ProgramStateRef | ||||||||||||
| 2353 | CStringChecker::checkRegionChanges(ProgramStateRef state, | ||||||||||||
| 2354 | const InvalidatedSymbols *, | ||||||||||||
| 2355 | ArrayRef<const MemRegion *> ExplicitRegions, | ||||||||||||
| 2356 | ArrayRef<const MemRegion *> Regions, | ||||||||||||
| 2357 | const LocationContext *LCtx, | ||||||||||||
| 2358 | const CallEvent *Call) const { | ||||||||||||
| 2359 | CStringLengthTy Entries = state->get<CStringLength>(); | ||||||||||||
| 2360 | if (Entries.isEmpty()) | ||||||||||||
| 2361 | return state; | ||||||||||||
| 2362 | |||||||||||||
| 2363 | llvm::SmallPtrSet<const MemRegion *, 8> Invalidated; | ||||||||||||
| 2364 | llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; | ||||||||||||
| 2365 | |||||||||||||
| 2366 | // First build sets for the changed regions and their super-regions. | ||||||||||||
| 2367 | for (ArrayRef<const MemRegion *>::iterator | ||||||||||||
| 2368 | I = Regions.begin(), E = Regions.end(); I != E; ++I) { | ||||||||||||
| 2369 | const MemRegion *MR = *I; | ||||||||||||
| 2370 | Invalidated.insert(MR); | ||||||||||||
| 2371 | |||||||||||||
| 2372 | SuperRegions.insert(MR); | ||||||||||||
| 2373 | while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) { | ||||||||||||
| 2374 | MR = SR->getSuperRegion(); | ||||||||||||
| 2375 | SuperRegions.insert(MR); | ||||||||||||
| 2376 | } | ||||||||||||
| 2377 | } | ||||||||||||
| 2378 | |||||||||||||
| 2379 | CStringLengthTy::Factory &F = state->get_context<CStringLength>(); | ||||||||||||
| 2380 | |||||||||||||
| 2381 | // Then loop over the entries in the current state. | ||||||||||||
| 2382 | for (CStringLengthTy::iterator I = Entries.begin(), | ||||||||||||
| 2383 | E = Entries.end(); I != E; ++I) { | ||||||||||||
| 2384 | const MemRegion *MR = I.getKey(); | ||||||||||||
| 2385 | |||||||||||||
| 2386 | // Is this entry for a super-region of a changed region? | ||||||||||||
| 2387 | if (SuperRegions.count(MR)) { | ||||||||||||
| 2388 | Entries = F.remove(Entries, MR); | ||||||||||||
| 2389 | continue; | ||||||||||||
| 2390 | } | ||||||||||||
| 2391 | |||||||||||||
| 2392 | // Is this entry for a sub-region of a changed region? | ||||||||||||
| 2393 | const MemRegion *Super = MR; | ||||||||||||
| 2394 | while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) { | ||||||||||||
| 2395 | Super = SR->getSuperRegion(); | ||||||||||||
| 2396 | if (Invalidated.count(Super)) { | ||||||||||||
| 2397 | Entries = F.remove(Entries, MR); | ||||||||||||
| 2398 | break; | ||||||||||||
| 2399 | } | ||||||||||||
| 2400 | } | ||||||||||||
| 2401 | } | ||||||||||||
| 2402 | |||||||||||||
| 2403 | return state->set<CStringLength>(Entries); | ||||||||||||
| 2404 | } | ||||||||||||
| 2405 | |||||||||||||
| 2406 | void CStringChecker::checkLiveSymbols(ProgramStateRef state, | ||||||||||||
| 2407 | SymbolReaper &SR) const { | ||||||||||||
| 2408 | // Mark all symbols in our string length map as valid. | ||||||||||||
| 2409 | CStringLengthTy Entries = state->get<CStringLength>(); | ||||||||||||
| 2410 | |||||||||||||
| 2411 | for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); | ||||||||||||
| 2412 | I != E; ++I) { | ||||||||||||
| 2413 | SVal Len = I.getData(); | ||||||||||||
| 2414 | |||||||||||||
| 2415 | for (SymExpr::symbol_iterator si = Len.symbol_begin(), | ||||||||||||
| 2416 | se = Len.symbol_end(); si != se; ++si) | ||||||||||||
| 2417 | SR.markInUse(*si); | ||||||||||||
| 2418 | } | ||||||||||||
| 2419 | } | ||||||||||||
| 2420 | |||||||||||||
| 2421 | void CStringChecker::checkDeadSymbols(SymbolReaper &SR, | ||||||||||||
| 2422 | CheckerContext &C) const { | ||||||||||||
| 2423 | ProgramStateRef state = C.getState(); | ||||||||||||
| 2424 | CStringLengthTy Entries = state->get<CStringLength>(); | ||||||||||||
| 2425 | if (Entries.isEmpty()) | ||||||||||||
| 2426 | return; | ||||||||||||
| 2427 | |||||||||||||
| 2428 | CStringLengthTy::Factory &F = state->get_context<CStringLength>(); | ||||||||||||
| 2429 | for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); | ||||||||||||
| 2430 | I != E; ++I) { | ||||||||||||
| 2431 | SVal Len = I.getData(); | ||||||||||||
| 2432 | if (SymbolRef Sym = Len.getAsSymbol()) { | ||||||||||||
| 2433 | if (SR.isDead(Sym)) | ||||||||||||
| 2434 | Entries = F.remove(Entries, I.getKey()); | ||||||||||||
| 2435 | } | ||||||||||||
| 2436 | } | ||||||||||||
| 2437 | |||||||||||||
| 2438 | state = state->set<CStringLength>(Entries); | ||||||||||||
| 2439 | C.addTransition(state); | ||||||||||||
| 2440 | } | ||||||||||||
| 2441 | |||||||||||||
| 2442 | void ento::registerCStringModeling(CheckerManager &Mgr) { | ||||||||||||
| 2443 | Mgr.registerChecker<CStringChecker>(); | ||||||||||||
| 2444 | } | ||||||||||||
| 2445 | |||||||||||||
| 2446 | bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) { | ||||||||||||
| 2447 | return true; | ||||||||||||
| 2448 | } | ||||||||||||
| 2449 | |||||||||||||
| 2450 | #define REGISTER_CHECKER(name)void ento::registername(CheckerManager &mgr) { CStringChecker *checker = mgr.getChecker<CStringChecker>(); checker-> Filter.Checkname = true; checker->Filter.CheckNamename = mgr .getCurrentCheckerName(); } bool ento::shouldRegistername(const CheckerManager &mgr) { return true; } \ | ||||||||||||
| 2451 | void ento::register##name(CheckerManager &mgr) { \ | ||||||||||||
| 2452 | CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ | ||||||||||||
| 2453 | checker->Filter.Check##name = true; \ | ||||||||||||
| 2454 | checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ | ||||||||||||
| 2455 | } \ | ||||||||||||
| 2456 | \ | ||||||||||||
| 2457 | bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } | ||||||||||||
| 2458 | |||||||||||||
| 2459 | REGISTER_CHECKER(CStringNullArg)void ento::registerCStringNullArg(CheckerManager &mgr) { CStringChecker *checker = mgr.getChecker<CStringChecker>(); checker-> Filter.CheckCStringNullArg = true; checker->Filter.CheckNameCStringNullArg = mgr.getCurrentCheckerName(); } bool ento::shouldRegisterCStringNullArg (const CheckerManager &mgr) { return true; } | ||||||||||||
| 2460 | REGISTER_CHECKER(CStringOutOfBounds)void ento::registerCStringOutOfBounds(CheckerManager &mgr ) { CStringChecker *checker = mgr.getChecker<CStringChecker >(); checker->Filter.CheckCStringOutOfBounds = true; checker ->Filter.CheckNameCStringOutOfBounds = mgr.getCurrentCheckerName (); } bool ento::shouldRegisterCStringOutOfBounds(const CheckerManager &mgr) { return true; } | ||||||||||||
| 2461 | REGISTER_CHECKER(CStringBufferOverlap)void ento::registerCStringBufferOverlap(CheckerManager &mgr ) { CStringChecker *checker = mgr.getChecker<CStringChecker >(); checker->Filter.CheckCStringBufferOverlap = true; checker ->Filter.CheckNameCStringBufferOverlap = mgr.getCurrentCheckerName (); } bool ento::shouldRegisterCStringBufferOverlap(const CheckerManager &mgr) { return true; } | ||||||||||||
| 2462 | REGISTER_CHECKER(CStringNotNullTerm)void ento::registerCStringNotNullTerm(CheckerManager &mgr ) { CStringChecker *checker = mgr.getChecker<CStringChecker >(); checker->Filter.CheckCStringNotNullTerm = true; checker ->Filter.CheckNameCStringNotNullTerm = mgr.getCurrentCheckerName (); } bool ento::shouldRegisterCStringNotNullTerm(const CheckerManager &mgr) { return true; } |
| 1 | //==- llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer --*- 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 the RefCountedBase, ThreadSafeRefCountedBase, and |
| 10 | // IntrusiveRefCntPtr classes. |
| 11 | // |
| 12 | // IntrusiveRefCntPtr is a smart pointer to an object which maintains a |
| 13 | // reference count. (ThreadSafe)RefCountedBase is a mixin class that adds a |
| 14 | // refcount member variable and methods for updating the refcount. An object |
| 15 | // that inherits from (ThreadSafe)RefCountedBase deletes itself when its |
| 16 | // refcount hits zero. |
| 17 | // |
| 18 | // For example: |
| 19 | // |
| 20 | // class MyClass : public RefCountedBase<MyClass> {}; |
| 21 | // |
| 22 | // void foo() { |
| 23 | // // Constructing an IntrusiveRefCntPtr increases the pointee's refcount by |
| 24 | // // 1 (from 0 in this case). |
| 25 | // IntrusiveRefCntPtr<MyClass> Ptr1(new MyClass()); |
| 26 | // |
| 27 | // // Copying an IntrusiveRefCntPtr increases the pointee's refcount by 1. |
| 28 | // IntrusiveRefCntPtr<MyClass> Ptr2(Ptr1); |
| 29 | // |
| 30 | // // Constructing an IntrusiveRefCntPtr has no effect on the object's |
| 31 | // // refcount. After a move, the moved-from pointer is null. |
| 32 | // IntrusiveRefCntPtr<MyClass> Ptr3(std::move(Ptr1)); |
| 33 | // assert(Ptr1 == nullptr); |
| 34 | // |
| 35 | // // Clearing an IntrusiveRefCntPtr decreases the pointee's refcount by 1. |
| 36 | // Ptr2.reset(); |
| 37 | // |
| 38 | // // The object deletes itself when we return from the function, because |
| 39 | // // Ptr3's destructor decrements its refcount to 0. |
| 40 | // } |
| 41 | // |
| 42 | // You can use IntrusiveRefCntPtr with isa<T>(), dyn_cast<T>(), etc.: |
| 43 | // |
| 44 | // IntrusiveRefCntPtr<MyClass> Ptr(new MyClass()); |
| 45 | // OtherClass *Other = dyn_cast<OtherClass>(Ptr); // Ptr.get() not required |
| 46 | // |
| 47 | // IntrusiveRefCntPtr works with any class that |
| 48 | // |
| 49 | // - inherits from (ThreadSafe)RefCountedBase, |
| 50 | // - has Retain() and Release() methods, or |
| 51 | // - specializes IntrusiveRefCntPtrInfo. |
| 52 | // |
| 53 | //===----------------------------------------------------------------------===// |
| 54 | |
| 55 | #ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H |
| 56 | #define LLVM_ADT_INTRUSIVEREFCNTPTR_H |
| 57 | |
| 58 | #include <atomic> |
| 59 | #include <cassert> |
| 60 | #include <cstddef> |
| 61 | #include <memory> |
| 62 | |
| 63 | namespace llvm { |
| 64 | |
| 65 | /// A CRTP mixin class that adds reference counting to a type. |
| 66 | /// |
| 67 | /// The lifetime of an object which inherits from RefCountedBase is managed by |
| 68 | /// calls to Release() and Retain(), which increment and decrement the object's |
| 69 | /// refcount, respectively. When a Release() call decrements the refcount to 0, |
| 70 | /// the object deletes itself. |
| 71 | template <class Derived> class RefCountedBase { |
| 72 | mutable unsigned RefCount = 0; |
| 73 | |
| 74 | protected: |
| 75 | RefCountedBase() = default; |
| 76 | RefCountedBase(const RefCountedBase &) {} |
| 77 | RefCountedBase &operator=(const RefCountedBase &) = delete; |
| 78 | |
| 79 | #ifndef NDEBUG |
| 80 | ~RefCountedBase() { |
| 81 | assert(RefCount == 0 &&(static_cast <bool> (RefCount == 0 && "Destruction occured when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occured when there are still references to this.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h" , 82, __extension__ __PRETTY_FUNCTION__)) |
| 82 | "Destruction occured when there are still references to this.")(static_cast <bool> (RefCount == 0 && "Destruction occured when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occured when there are still references to this.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h" , 82, __extension__ __PRETTY_FUNCTION__)); |
| 83 | } |
| 84 | #else |
| 85 | // Default the destructor in release builds, A trivial destructor may enable |
| 86 | // better codegen. |
| 87 | ~RefCountedBase() = default; |
| 88 | #endif |
| 89 | |
| 90 | public: |
| 91 | void Retain() const { ++RefCount; } |
| 92 | |
| 93 | void Release() const { |
| 94 | assert(RefCount > 0 && "Reference count is already zero.")(static_cast <bool> (RefCount > 0 && "Reference count is already zero." ) ? void (0) : __assert_fail ("RefCount > 0 && \"Reference count is already zero.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h" , 94, __extension__ __PRETTY_FUNCTION__)); |
| 95 | if (--RefCount == 0) |
| 96 | delete static_cast<const Derived *>(this); |
| 97 | } |
| 98 | }; |
| 99 | |
| 100 | /// A thread-safe version of \c RefCountedBase. |
| 101 | template <class Derived> class ThreadSafeRefCountedBase { |
| 102 | mutable std::atomic<int> RefCount{0}; |
| 103 | |
| 104 | protected: |
| 105 | ThreadSafeRefCountedBase() = default; |
| 106 | ThreadSafeRefCountedBase(const ThreadSafeRefCountedBase &) {} |
| 107 | ThreadSafeRefCountedBase & |
| 108 | operator=(const ThreadSafeRefCountedBase &) = delete; |
| 109 | |
| 110 | #ifndef NDEBUG |
| 111 | ~ThreadSafeRefCountedBase() { |
| 112 | assert(RefCount == 0 &&(static_cast <bool> (RefCount == 0 && "Destruction occured when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occured when there are still references to this.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h" , 113, __extension__ __PRETTY_FUNCTION__)) |
| 113 | "Destruction occured when there are still references to this.")(static_cast <bool> (RefCount == 0 && "Destruction occured when there are still references to this." ) ? void (0) : __assert_fail ("RefCount == 0 && \"Destruction occured when there are still references to this.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h" , 113, __extension__ __PRETTY_FUNCTION__)); |
| 114 | } |
| 115 | #else |
| 116 | // Default the destructor in release builds, A trivial destructor may enable |
| 117 | // better codegen. |
| 118 | ~ThreadSafeRefCountedBase() = default; |
| 119 | #endif |
| 120 | |
| 121 | public: |
| 122 | void Retain() const { RefCount.fetch_add(1, std::memory_order_relaxed); } |
| 123 | |
| 124 | void Release() const { |
| 125 | int NewRefCount = RefCount.fetch_sub(1, std::memory_order_acq_rel) - 1; |
| 126 | assert(NewRefCount >= 0 && "Reference count was already zero.")(static_cast <bool> (NewRefCount >= 0 && "Reference count was already zero." ) ? void (0) : __assert_fail ("NewRefCount >= 0 && \"Reference count was already zero.\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/IntrusiveRefCntPtr.h" , 126, __extension__ __PRETTY_FUNCTION__)); |
| 127 | if (NewRefCount == 0) |
| 128 | delete static_cast<const Derived *>(this); |
| 129 | } |
| 130 | }; |
| 131 | |
| 132 | /// Class you can specialize to provide custom retain/release functionality for |
| 133 | /// a type. |
| 134 | /// |
| 135 | /// Usually specializing this class is not necessary, as IntrusiveRefCntPtr |
| 136 | /// works with any type which defines Retain() and Release() functions -- you |
| 137 | /// can define those functions yourself if RefCountedBase doesn't work for you. |
| 138 | /// |
| 139 | /// One case when you might want to specialize this type is if you have |
| 140 | /// - Foo.h defines type Foo and includes Bar.h, and |
| 141 | /// - Bar.h uses IntrusiveRefCntPtr<Foo> in inline functions. |
| 142 | /// |
| 143 | /// Because Foo.h includes Bar.h, Bar.h can't include Foo.h in order to pull in |
| 144 | /// the declaration of Foo. Without the declaration of Foo, normally Bar.h |
| 145 | /// wouldn't be able to use IntrusiveRefCntPtr<Foo>, which wants to call |
| 146 | /// T::Retain and T::Release. |
| 147 | /// |
| 148 | /// To resolve this, Bar.h could include a third header, FooFwd.h, which |
| 149 | /// forward-declares Foo and specializes IntrusiveRefCntPtrInfo<Foo>. Then |
| 150 | /// Bar.h could use IntrusiveRefCntPtr<Foo>, although it still couldn't call any |
| 151 | /// functions on Foo itself, because Foo would be an incomplete type. |
| 152 | template <typename T> struct IntrusiveRefCntPtrInfo { |
| 153 | static void retain(T *obj) { obj->Retain(); } |
| 154 | static void release(T *obj) { obj->Release(); } |
| 155 | }; |
| 156 | |
| 157 | /// A smart pointer to a reference-counted object that inherits from |
| 158 | /// RefCountedBase or ThreadSafeRefCountedBase. |
| 159 | /// |
| 160 | /// This class increments its pointee's reference count when it is created, and |
| 161 | /// decrements its refcount when it's destroyed (or is changed to point to a |
| 162 | /// different object). |
| 163 | template <typename T> class IntrusiveRefCntPtr { |
| 164 | T *Obj = nullptr; |
| 165 | |
| 166 | public: |
| 167 | using element_type = T; |
| 168 | |
| 169 | explicit IntrusiveRefCntPtr() = default; |
| 170 | IntrusiveRefCntPtr(T *obj) : Obj(obj) { retain(); } |
| 171 | IntrusiveRefCntPtr(const IntrusiveRefCntPtr &S) : Obj(S.Obj) { retain(); } |
| 172 | IntrusiveRefCntPtr(IntrusiveRefCntPtr &&S) : Obj(S.Obj) { S.Obj = nullptr; } |
| 173 | |
| 174 | template <class X, |
| 175 | std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> |
| 176 | IntrusiveRefCntPtr(IntrusiveRefCntPtr<X> S) : Obj(S.get()) { |
| 177 | S.Obj = nullptr; |
| 178 | } |
| 179 | |
| 180 | template <class X, |
| 181 | std::enable_if_t<std::is_convertible<X *, T *>::value, bool> = true> |
| 182 | IntrusiveRefCntPtr(std::unique_ptr<X> S) : Obj(S.release()) { |
| 183 | retain(); |
| 184 | } |
| 185 | |
| 186 | ~IntrusiveRefCntPtr() { release(); } |
| 187 | |
| 188 | IntrusiveRefCntPtr &operator=(IntrusiveRefCntPtr S) { |
| 189 | swap(S); |
| 190 | return *this; |
| 191 | } |
| 192 | |
| 193 | T &operator*() const { return *Obj; } |
| 194 | T *operator->() const { return Obj; } |
| 195 | T *get() const { return Obj; } |
| 196 | explicit operator bool() const { return Obj; } |
| 197 | |
| 198 | void swap(IntrusiveRefCntPtr &other) { |
| 199 | T *tmp = other.Obj; |
| 200 | other.Obj = Obj; |
| 201 | Obj = tmp; |
| 202 | } |
| 203 | |
| 204 | void reset() { |
| 205 | release(); |
| 206 | Obj = nullptr; |
| 207 | } |
| 208 | |
| 209 | void resetWithoutRelease() { Obj = nullptr; } |
| 210 | |
| 211 | private: |
| 212 | void retain() { |
| 213 | if (Obj) |
| 214 | IntrusiveRefCntPtrInfo<T>::retain(Obj); |
| 215 | } |
| 216 | |
| 217 | void release() { |
| 218 | if (Obj) |
| 219 | IntrusiveRefCntPtrInfo<T>::release(Obj); |
| 220 | } |
| 221 | |
| 222 | template <typename X> friend class IntrusiveRefCntPtr; |
| 223 | }; |
| 224 | |
| 225 | template <class T, class U> |
| 226 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, |
| 227 | const IntrusiveRefCntPtr<U> &B) { |
| 228 | return A.get() == B.get(); |
| 229 | } |
| 230 | |
| 231 | template <class T, class U> |
| 232 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, |
| 233 | const IntrusiveRefCntPtr<U> &B) { |
| 234 | return A.get() != B.get(); |
| 235 | } |
| 236 | |
| 237 | template <class T, class U> |
| 238 | inline bool operator==(const IntrusiveRefCntPtr<T> &A, U *B) { |
| 239 | return A.get() == B; |
| 240 | } |
| 241 | |
| 242 | template <class T, class U> |
| 243 | inline bool operator!=(const IntrusiveRefCntPtr<T> &A, U *B) { |
| 244 | return A.get() != B; |
| 245 | } |
| 246 | |
| 247 | template <class T, class U> |
| 248 | inline bool operator==(T *A, const IntrusiveRefCntPtr<U> &B) { |
| 249 | return A == B.get(); |
| 250 | } |
| 251 | |
| 252 | template <class T, class U> |
| 253 | inline bool operator!=(T *A, const IntrusiveRefCntPtr<U> &B) { |
| 254 | return A != B.get(); |
| 255 | } |
| 256 | |
| 257 | template <class T> |
| 258 | bool operator==(std::nullptr_t, const IntrusiveRefCntPtr<T> &B) { |
| 259 | return !B; |
| 260 | } |
| 261 | |
| 262 | template <class T> |
| 263 | bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { |
| 264 | return B == A; |
| 265 | } |
| 266 | |
| 267 | template <class T> |
| 268 | bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) { |
| 269 | return !(A == B); |
| 270 | } |
| 271 | |
| 272 | template <class T> |
| 273 | bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) { |
| 274 | return !(A == B); |
| 275 | } |
| 276 | |
| 277 | // Make IntrusiveRefCntPtr work with dyn_cast, isa, and the other idioms from |
| 278 | // Casting.h. |
| 279 | template <typename From> struct simplify_type; |
| 280 | |
| 281 | template <class T> struct simplify_type<IntrusiveRefCntPtr<T>> { |
| 282 | using SimpleType = T *; |
| 283 | |
| 284 | static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T> &Val) { |
| 285 | return Val.get(); |
| 286 | } |
| 287 | }; |
| 288 | |
| 289 | template <class T> struct simplify_type<const IntrusiveRefCntPtr<T>> { |
| 290 | using SimpleType = /*const*/ T *; |
| 291 | |
| 292 | static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T> &Val) { |
| 293 | return Val.get(); |
| 294 | } |
| 295 | }; |
| 296 | |
| 297 | /// Factory function for creating intrusive ref counted pointers. |
| 298 | template <typename T, typename... Args> |
| 299 | IntrusiveRefCntPtr<T> makeIntrusiveRefCnt(Args &&...A) { |
| 300 | return IntrusiveRefCntPtr<T>(new T(std::forward<Args>(A)...)); |
| 301 | } |
| 302 | |
| 303 | } // end namespace llvm |
| 304 | |
| 305 | #endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H |
| 1 | // <tuple> -*- C++ -*- |
| 2 | |
| 3 | // Copyright (C) 2007-2020 Free Software Foundation, Inc. |
| 4 | // |
| 5 | // This file is part of the GNU ISO C++ Library. This library is free |
| 6 | // software; you can redistribute it and/or modify it under the |
| 7 | // terms of the GNU General Public License as published by the |
| 8 | // Free Software Foundation; either version 3, or (at your option) |
| 9 | // any later version. |
| 10 | |
| 11 | // This library is distributed in the hope that it will be useful, |
| 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | // GNU General Public License for more details. |
| 15 | |
| 16 | // Under Section 7 of GPL version 3, you are granted additional |
| 17 | // permissions described in the GCC Runtime Library Exception, version |
| 18 | // 3.1, as published by the Free Software Foundation. |
| 19 | |
| 20 | // You should have received a copy of the GNU General Public License and |
| 21 | // a copy of the GCC Runtime Library Exception along with this program; |
| 22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| 23 | // <http://www.gnu.org/licenses/>. |
| 24 | |
| 25 | /** @file include/tuple |
| 26 | * This is a Standard C++ Library header. |
| 27 | */ |
| 28 | |
| 29 | #ifndef _GLIBCXX_TUPLE1 |
| 30 | #define _GLIBCXX_TUPLE1 1 |
| 31 | |
| 32 | #pragma GCC system_header |
| 33 | |
| 34 | #if __cplusplus201402L < 201103L |
| 35 | # include <bits/c++0x_warning.h> |
| 36 | #else |
| 37 | |
| 38 | #include <utility> |
| 39 | #include <array> |
| 40 | #include <bits/uses_allocator.h> |
| 41 | #include <bits/invoke.h> |
| 42 | #if __cplusplus201402L > 201703L |
| 43 | # include <compare> |
| 44 | # define __cpp_lib_constexpr_tuple 201811L |
| 45 | #endif |
| 46 | |
| 47 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
| 48 | { |
| 49 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
| 50 | |
| 51 | /** |
| 52 | * @addtogroup utilities |
| 53 | * @{ |
| 54 | */ |
| 55 | |
| 56 | template<typename... _Elements> |
| 57 | class tuple; |
| 58 | |
| 59 | template<typename _Tp> |
| 60 | struct __is_empty_non_tuple : is_empty<_Tp> { }; |
| 61 | |
| 62 | // Using EBO for elements that are tuples causes ambiguous base errors. |
| 63 | template<typename _El0, typename... _El> |
| 64 | struct __is_empty_non_tuple<tuple<_El0, _El...>> : false_type { }; |
| 65 | |
| 66 | // Use the Empty Base-class Optimization for empty, non-final types. |
| 67 | template<typename _Tp> |
| 68 | using __empty_not_final |
| 69 | = typename conditional<__is_final(_Tp), false_type, |
| 70 | __is_empty_non_tuple<_Tp>>::type; |
| 71 | |
| 72 | template<std::size_t _Idx, typename _Head, |
| 73 | bool = __empty_not_final<_Head>::value> |
| 74 | struct _Head_base; |
| 75 | |
| 76 | template<std::size_t _Idx, typename _Head> |
| 77 | struct _Head_base<_Idx, _Head, true> |
| 78 | : public _Head |
| 79 | { |
| 80 | constexpr _Head_base() |
| 81 | : _Head() { } |
| 82 | |
| 83 | constexpr _Head_base(const _Head& __h) |
| 84 | : _Head(__h) { } |
| 85 | |
| 86 | constexpr _Head_base(const _Head_base&) = default; |
| 87 | constexpr _Head_base(_Head_base&&) = default; |
| 88 | |
| 89 | template<typename _UHead> |
| 90 | constexpr _Head_base(_UHead&& __h) |
| 91 | : _Head(std::forward<_UHead>(__h)) { } |
| 92 | |
| 93 | _Head_base(allocator_arg_t, __uses_alloc0) |
| 94 | : _Head() { } |
| 95 | |
| 96 | template<typename _Alloc> |
| 97 | _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a) |
| 98 | : _Head(allocator_arg, *__a._M_a) { } |
| 99 | |
| 100 | template<typename _Alloc> |
| 101 | _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a) |
| 102 | : _Head(*__a._M_a) { } |
| 103 | |
| 104 | template<typename _UHead> |
| 105 | _Head_base(__uses_alloc0, _UHead&& __uhead) |
| 106 | : _Head(std::forward<_UHead>(__uhead)) { } |
| 107 | |
| 108 | template<typename _Alloc, typename _UHead> |
| 109 | _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead) |
| 110 | : _Head(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) { } |
| 111 | |
| 112 | template<typename _Alloc, typename _UHead> |
| 113 | _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead) |
| 114 | : _Head(std::forward<_UHead>(__uhead), *__a._M_a) { } |
| 115 | |
| 116 | static constexpr _Head& |
| 117 | _M_head(_Head_base& __b) noexcept { return __b; } |
| 118 | |
| 119 | static constexpr const _Head& |
| 120 | _M_head(const _Head_base& __b) noexcept { return __b; } |
| 121 | }; |
| 122 | |
| 123 | template<std::size_t _Idx, typename _Head> |
| 124 | struct _Head_base<_Idx, _Head, false> |
| 125 | { |
| 126 | constexpr _Head_base() |
| 127 | : _M_head_impl() { } |
| 128 | |
| 129 | constexpr _Head_base(const _Head& __h) |
| 130 | : _M_head_impl(__h) { } |
| 131 | |
| 132 | constexpr _Head_base(const _Head_base&) = default; |
| 133 | constexpr _Head_base(_Head_base&&) = default; |
| 134 | |
| 135 | template<typename _UHead> |
| 136 | constexpr _Head_base(_UHead&& __h) |
| 137 | : _M_head_impl(std::forward<_UHead>(__h)) { } |
| 138 | |
| 139 | _GLIBCXX20_CONSTEXPR |
| 140 | _Head_base(allocator_arg_t, __uses_alloc0) |
| 141 | : _M_head_impl() { } |
| 142 | |
| 143 | template<typename _Alloc> |
| 144 | _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a) |
| 145 | : _M_head_impl(allocator_arg, *__a._M_a) { } |
| 146 | |
| 147 | template<typename _Alloc> |
| 148 | _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a) |
| 149 | : _M_head_impl(*__a._M_a) { } |
| 150 | |
| 151 | template<typename _UHead> |
| 152 | _GLIBCXX20_CONSTEXPR |
| 153 | _Head_base(__uses_alloc0, _UHead&& __uhead) |
| 154 | : _M_head_impl(std::forward<_UHead>(__uhead)) { } |
| 155 | |
| 156 | template<typename _Alloc, typename _UHead> |
| 157 | _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead) |
| 158 | : _M_head_impl(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) |
| 159 | { } |
| 160 | |
| 161 | template<typename _Alloc, typename _UHead> |
| 162 | _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead) |
| 163 | : _M_head_impl(std::forward<_UHead>(__uhead), *__a._M_a) { } |
| 164 | |
| 165 | static constexpr _Head& |
| 166 | _M_head(_Head_base& __b) noexcept { return __b._M_head_impl; } |
| 167 | |
| 168 | static constexpr const _Head& |
| 169 | _M_head(const _Head_base& __b) noexcept { return __b._M_head_impl; } |
| 170 | |
| 171 | _Head _M_head_impl; |
| 172 | }; |
| 173 | |
| 174 | /** |
| 175 | * Contains the actual implementation of the @c tuple template, stored |
| 176 | * as a recursive inheritance hierarchy from the first element (most |
| 177 | * derived class) to the last (least derived class). The @c Idx |
| 178 | * parameter gives the 0-based index of the element stored at this |
| 179 | * point in the hierarchy; we use it to implement a constant-time |
| 180 | * get() operation. |
| 181 | */ |
| 182 | template<std::size_t _Idx, typename... _Elements> |
| 183 | struct _Tuple_impl; |
| 184 | |
| 185 | /** |
| 186 | * Recursive tuple implementation. Here we store the @c Head element |
| 187 | * and derive from a @c Tuple_impl containing the remaining elements |
| 188 | * (which contains the @c Tail). |
| 189 | */ |
| 190 | template<std::size_t _Idx, typename _Head, typename... _Tail> |
| 191 | struct _Tuple_impl<_Idx, _Head, _Tail...> |
| 192 | : public _Tuple_impl<_Idx + 1, _Tail...>, |
| 193 | private _Head_base<_Idx, _Head> |
| 194 | { |
| 195 | template<std::size_t, typename...> friend class _Tuple_impl; |
| 196 | |
| 197 | typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited; |
| 198 | typedef _Head_base<_Idx, _Head> _Base; |
| 199 | |
| 200 | static constexpr _Head& |
| 201 | _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
| 202 | |
| 203 | static constexpr const _Head& |
| 204 | _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
| 205 | |
| 206 | static constexpr _Inherited& |
| 207 | _M_tail(_Tuple_impl& __t) noexcept { return __t; } |
| 208 | |
| 209 | static constexpr const _Inherited& |
| 210 | _M_tail(const _Tuple_impl& __t) noexcept { return __t; } |
| 211 | |
| 212 | constexpr _Tuple_impl() |
| 213 | : _Inherited(), _Base() { } |
| 214 | |
| 215 | explicit |
| 216 | constexpr _Tuple_impl(const _Head& __head, const _Tail&... __tail) |
| 217 | : _Inherited(__tail...), _Base(__head) { } |
| 218 | |
| 219 | template<typename _UHead, typename... _UTail, typename = typename |
| 220 | enable_if<sizeof...(_Tail) == sizeof...(_UTail)>::type> |
| 221 | explicit |
| 222 | constexpr _Tuple_impl(_UHead&& __head, _UTail&&... __tail) |
| 223 | : _Inherited(std::forward<_UTail>(__tail)...), |
| 224 | _Base(std::forward<_UHead>(__head)) { } |
| 225 | |
| 226 | constexpr _Tuple_impl(const _Tuple_impl&) = default; |
| 227 | |
| 228 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
| 229 | // 2729. Missing SFINAE on std::pair::operator= |
| 230 | _Tuple_impl& operator=(const _Tuple_impl&) = delete; |
| 231 | |
| 232 | constexpr |
| 233 | _Tuple_impl(_Tuple_impl&& __in) |
| 234 | noexcept(__and_<is_nothrow_move_constructible<_Head>, |
| 235 | is_nothrow_move_constructible<_Inherited>>::value) |
| 236 | : _Inherited(std::move(_M_tail(__in))), |
| 237 | _Base(std::forward<_Head>(_M_head(__in))) { } |
| 238 | |
| 239 | template<typename... _UElements> |
| 240 | constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UElements...>& __in) |
| 241 | : _Inherited(_Tuple_impl<_Idx, _UElements...>::_M_tail(__in)), |
| 242 | _Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { } |
| 243 | |
| 244 | template<typename _UHead, typename... _UTails> |
| 245 | constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) |
| 246 | : _Inherited(std::move |
| 247 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), |
| 248 | _Base(std::forward<_UHead> |
| 249 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } |
| 250 | |
| 251 | template<typename _Alloc> |
| 252 | _GLIBCXX20_CONSTEXPR |
| 253 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) |
| 254 | : _Inherited(__tag, __a), |
| 255 | _Base(__tag, __use_alloc<_Head>(__a)) { } |
| 256 | |
| 257 | template<typename _Alloc> |
| 258 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 259 | const _Head& __head, const _Tail&... __tail) |
| 260 | : _Inherited(__tag, __a, __tail...), |
| 261 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } |
| 262 | |
| 263 | template<typename _Alloc, typename _UHead, typename... _UTail, |
| 264 | typename = typename enable_if<sizeof...(_Tail) |
| 265 | == sizeof...(_UTail)>::type> |
| 266 | _GLIBCXX20_CONSTEXPR |
| 267 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 268 | _UHead&& __head, _UTail&&... __tail) |
| 269 | : _Inherited(__tag, __a, std::forward<_UTail>(__tail)...), |
| 270 | _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
| 271 | std::forward<_UHead>(__head)) { } |
| 272 | |
| 273 | template<typename _Alloc> |
| 274 | _GLIBCXX20_CONSTEXPR |
| 275 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 276 | const _Tuple_impl& __in) |
| 277 | : _Inherited(__tag, __a, _M_tail(__in)), |
| 278 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } |
| 279 | |
| 280 | template<typename _Alloc> |
| 281 | _GLIBCXX20_CONSTEXPR |
| 282 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 283 | _Tuple_impl&& __in) |
| 284 | : _Inherited(__tag, __a, std::move(_M_tail(__in))), |
| 285 | _Base(__use_alloc<_Head, _Alloc, _Head>(__a), |
| 286 | std::forward<_Head>(_M_head(__in))) { } |
| 287 | |
| 288 | template<typename _Alloc, typename _UHead, typename... _UTails> |
| 289 | _GLIBCXX20_CONSTEXPR |
| 290 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 291 | const _Tuple_impl<_Idx, _UHead, _UTails...>& __in) |
| 292 | : _Inherited(__tag, __a, |
| 293 | _Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)), |
| 294 | _Base(__use_alloc<_Head, _Alloc, const _UHead&>(__a), |
| 295 | _Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)) { } |
| 296 | |
| 297 | template<typename _Alloc, typename _UHead, typename... _UTails> |
| 298 | _GLIBCXX20_CONSTEXPR |
| 299 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 300 | _Tuple_impl<_Idx, _UHead, _UTails...>&& __in) |
| 301 | : _Inherited(__tag, __a, std::move |
| 302 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), |
| 303 | _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
| 304 | std::forward<_UHead> |
| 305 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } |
| 306 | |
| 307 | template<typename... _UElements> |
| 308 | _GLIBCXX20_CONSTEXPR |
| 309 | void |
| 310 | _M_assign(const _Tuple_impl<_Idx, _UElements...>& __in) |
| 311 | { |
| 312 | _M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in); |
| 313 | _M_tail(*this)._M_assign( |
| 314 | _Tuple_impl<_Idx, _UElements...>::_M_tail(__in)); |
| 315 | } |
| 316 | |
| 317 | template<typename _UHead, typename... _UTails> |
| 318 | _GLIBCXX20_CONSTEXPR |
| 319 | void |
| 320 | _M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) |
| 321 | { |
| 322 | _M_head(*this) = std::forward<_UHead> |
| 323 | (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)); |
| 324 | _M_tail(*this)._M_assign( |
| 325 | std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))); |
| 326 | } |
| 327 | |
| 328 | protected: |
| 329 | _GLIBCXX20_CONSTEXPR |
| 330 | void |
| 331 | _M_swap(_Tuple_impl& __in) |
| 332 | { |
| 333 | using std::swap; |
| 334 | swap(_M_head(*this), _M_head(__in)); |
| 335 | _Inherited::_M_swap(_M_tail(__in)); |
| 336 | } |
| 337 | }; |
| 338 | |
| 339 | // Basis case of inheritance recursion. |
| 340 | template<std::size_t _Idx, typename _Head> |
| 341 | struct _Tuple_impl<_Idx, _Head> |
| 342 | : private _Head_base<_Idx, _Head> |
| 343 | { |
| 344 | template<std::size_t, typename...> friend class _Tuple_impl; |
| 345 | |
| 346 | typedef _Head_base<_Idx, _Head> _Base; |
| 347 | |
| 348 | static constexpr _Head& |
| 349 | _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
| 350 | |
| 351 | static constexpr const _Head& |
| 352 | _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } |
| 353 | |
| 354 | constexpr _Tuple_impl() |
| 355 | : _Base() { } |
| 356 | |
| 357 | explicit |
| 358 | constexpr _Tuple_impl(const _Head& __head) |
| 359 | : _Base(__head) { } |
| 360 | |
| 361 | template<typename _UHead> |
| 362 | explicit |
| 363 | constexpr _Tuple_impl(_UHead&& __head) |
| 364 | : _Base(std::forward<_UHead>(__head)) { } |
| 365 | |
| 366 | constexpr _Tuple_impl(const _Tuple_impl&) = default; |
| 367 | |
| 368 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
| 369 | // 2729. Missing SFINAE on std::pair::operator= |
| 370 | _Tuple_impl& operator=(const _Tuple_impl&) = delete; |
| 371 | |
| 372 | constexpr |
| 373 | _Tuple_impl(_Tuple_impl&& __in) |
| 374 | noexcept(is_nothrow_move_constructible<_Head>::value) |
| 375 | : _Base(std::forward<_Head>(_M_head(__in))) { } |
| 376 | |
| 377 | template<typename _UHead> |
| 378 | constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in) |
| 379 | : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } |
| 380 | |
| 381 | template<typename _UHead> |
| 382 | constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in) |
| 383 | : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) |
| 384 | { } |
| 385 | |
| 386 | template<typename _Alloc> |
| 387 | _GLIBCXX20_CONSTEXPR |
| 388 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) |
| 389 | : _Base(__tag, __use_alloc<_Head>(__a)) { } |
| 390 | |
| 391 | template<typename _Alloc> |
| 392 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 393 | const _Head& __head) |
| 394 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } |
| 395 | |
| 396 | template<typename _Alloc, typename _UHead> |
| 397 | _GLIBCXX20_CONSTEXPR |
| 398 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 399 | _UHead&& __head) |
| 400 | : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
| 401 | std::forward<_UHead>(__head)) { } |
| 402 | |
| 403 | template<typename _Alloc> |
| 404 | _GLIBCXX20_CONSTEXPR |
| 405 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 406 | const _Tuple_impl& __in) |
| 407 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } |
| 408 | |
| 409 | template<typename _Alloc> |
| 410 | _GLIBCXX20_CONSTEXPR |
| 411 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 412 | _Tuple_impl&& __in) |
| 413 | : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), |
| 414 | std::forward<_Head>(_M_head(__in))) { } |
| 415 | |
| 416 | template<typename _Alloc, typename _UHead> |
| 417 | _GLIBCXX20_CONSTEXPR |
| 418 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 419 | const _Tuple_impl<_Idx, _UHead>& __in) |
| 420 | : _Base(__use_alloc<_Head, _Alloc, const _UHead&>(__a), |
| 421 | _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } |
| 422 | |
| 423 | template<typename _Alloc, typename _UHead> |
| 424 | _GLIBCXX20_CONSTEXPR |
| 425 | _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, |
| 426 | _Tuple_impl<_Idx, _UHead>&& __in) |
| 427 | : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), |
| 428 | std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) |
| 429 | { } |
| 430 | |
| 431 | template<typename _UHead> |
| 432 | _GLIBCXX20_CONSTEXPR |
| 433 | void |
| 434 | _M_assign(const _Tuple_impl<_Idx, _UHead>& __in) |
| 435 | { |
| 436 | _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); |
| 437 | } |
| 438 | |
| 439 | template<typename _UHead> |
| 440 | _GLIBCXX20_CONSTEXPR |
| 441 | void |
| 442 | _M_assign(_Tuple_impl<_Idx, _UHead>&& __in) |
| 443 | { |
| 444 | _M_head(*this) |
| 445 | = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); |
| 446 | } |
| 447 | |
| 448 | protected: |
| 449 | _GLIBCXX20_CONSTEXPR |
| 450 | void |
| 451 | _M_swap(_Tuple_impl& __in) |
| 452 | { |
| 453 | using std::swap; |
| 454 | swap(_M_head(*this), _M_head(__in)); |
| 455 | } |
| 456 | }; |
| 457 | |
| 458 | // Concept utility functions, reused in conditionally-explicit |
| 459 | // constructors. |
| 460 | template<bool, typename... _Types> |
| 461 | struct _TupleConstraints |
| 462 | { |
| 463 | // Constraint for a non-explicit constructor. |
| 464 | // True iff each Ti in _Types... can be constructed from Ui in _UTypes... |
| 465 | // and every Ui is implicitly convertible to Ti. |
| 466 | template<typename... _UTypes> |
| 467 | static constexpr bool __is_implicitly_constructible() |
| 468 | { |
| 469 | return __and_<is_constructible<_Types, _UTypes>..., |
| 470 | is_convertible<_UTypes, _Types>... |
| 471 | >::value; |
| 472 | } |
| 473 | |
| 474 | // Constraint for a non-explicit constructor. |
| 475 | // True iff each Ti in _Types... can be constructed from Ui in _UTypes... |
| 476 | // but not every Ui is implicitly convertible to Ti. |
| 477 | template<typename... _UTypes> |
| 478 | static constexpr bool __is_explicitly_constructible() |
| 479 | { |
| 480 | return __and_<is_constructible<_Types, _UTypes>..., |
| 481 | __not_<__and_<is_convertible<_UTypes, _Types>...>> |
| 482 | >::value; |
| 483 | } |
| 484 | |
| 485 | static constexpr bool __is_implicitly_default_constructible() |
| 486 | { |
| 487 | return __and_<std::__is_implicitly_default_constructible<_Types>... |
| 488 | >::value; |
| 489 | } |
| 490 | |
| 491 | static constexpr bool __is_explicitly_default_constructible() |
| 492 | { |
| 493 | return __and_<is_default_constructible<_Types>..., |
| 494 | __not_<__and_< |
| 495 | std::__is_implicitly_default_constructible<_Types>...> |
| 496 | >>::value; |
| 497 | } |
| 498 | }; |
| 499 | |
| 500 | // Partial specialization used when a required precondition isn't met, |
| 501 | // e.g. when sizeof...(_Types) != sizeof...(_UTypes). |
| 502 | template<typename... _Types> |
| 503 | struct _TupleConstraints<false, _Types...> |
| 504 | { |
| 505 | template<typename... _UTypes> |
| 506 | static constexpr bool __is_implicitly_constructible() |
| 507 | { return false; } |
| 508 | |
| 509 | template<typename... _UTypes> |
| 510 | static constexpr bool __is_explicitly_constructible() |
| 511 | { return false; } |
| 512 | }; |
| 513 | |
| 514 | /// Primary class template, tuple |
| 515 | template<typename... _Elements> |
| 516 | class tuple : public _Tuple_impl<0, _Elements...> |
| 517 | { |
| 518 | typedef _Tuple_impl<0, _Elements...> _Inherited; |
| 519 | |
| 520 | template<bool _Cond> |
| 521 | using _TCC = _TupleConstraints<_Cond, _Elements...>; |
| 522 | |
| 523 | // Constraint for non-explicit default constructor |
| 524 | template<bool _Dummy> |
| 525 | using _ImplicitDefaultCtor = __enable_if_t< |
| 526 | _TCC<_Dummy>::__is_implicitly_default_constructible(), |
| 527 | bool>; |
| 528 | |
| 529 | // Constraint for explicit default constructor |
| 530 | template<bool _Dummy> |
| 531 | using _ExplicitDefaultCtor = __enable_if_t< |
| 532 | _TCC<_Dummy>::__is_explicitly_default_constructible(), |
| 533 | bool>; |
| 534 | |
| 535 | // Constraint for non-explicit constructors |
| 536 | template<bool _Cond, typename... _Args> |
| 537 | using _ImplicitCtor = __enable_if_t< |
| 538 | _TCC<_Cond>::template __is_implicitly_constructible<_Args...>(), |
| 539 | bool>; |
| 540 | |
| 541 | // Constraint for non-explicit constructors |
| 542 | template<bool _Cond, typename... _Args> |
| 543 | using _ExplicitCtor = __enable_if_t< |
| 544 | _TCC<_Cond>::template __is_explicitly_constructible<_Args...>(), |
| 545 | bool>; |
| 546 | |
| 547 | template<typename... _UElements> |
| 548 | static constexpr |
| 549 | __enable_if_t<sizeof...(_UElements) == sizeof...(_Elements), bool> |
| 550 | __assignable() |
| 551 | { return __and_<is_assignable<_Elements&, _UElements>...>::value; } |
| 552 | |
| 553 | // Condition for noexcept-specifier of an assignment operator. |
| 554 | template<typename... _UElements> |
| 555 | static constexpr bool __nothrow_assignable() |
| 556 | { |
| 557 | return |
| 558 | __and_<is_nothrow_assignable<_Elements&, _UElements>...>::value; |
| 559 | } |
| 560 | |
| 561 | // Condition for noexcept-specifier of a constructor. |
| 562 | template<typename... _UElements> |
| 563 | static constexpr bool __nothrow_constructible() |
| 564 | { |
| 565 | return |
| 566 | __and_<is_nothrow_constructible<_Elements, _UElements>...>::value; |
| 567 | } |
| 568 | |
| 569 | // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) == 1. |
| 570 | template<typename _Up> |
| 571 | static constexpr bool __valid_args() |
| 572 | { |
| 573 | return sizeof...(_Elements) == 1 |
| 574 | && !is_same<tuple, __remove_cvref_t<_Up>>::value; |
| 575 | } |
| 576 | |
| 577 | // Constraint for tuple(_UTypes&&...) where sizeof...(_UTypes) > 1. |
| 578 | template<typename, typename, typename... _Tail> |
| 579 | static constexpr bool __valid_args() |
| 580 | { return (sizeof...(_Tail) + 2) == sizeof...(_Elements); } |
| 581 | |
| 582 | /* Constraint for constructors with a tuple<UTypes...> parameter ensures |
| 583 | * that the constructor is only viable when it would not interfere with |
| 584 | * tuple(UTypes&&...) or tuple(const tuple&) or tuple(tuple&&). |
| 585 | * Such constructors are only viable if: |
| 586 | * either sizeof...(Types) != 1, |
| 587 | * or (when Types... expands to T and UTypes... expands to U) |
| 588 | * is_convertible_v<TUPLE, T>, is_constructible_v<T, TUPLE>, |
| 589 | * and is_same_v<T, U> are all false. |
| 590 | */ |
| 591 | template<typename _Tuple, typename = tuple, |
| 592 | typename = __remove_cvref_t<_Tuple>> |
| 593 | struct _UseOtherCtor |
| 594 | : false_type |
| 595 | { }; |
| 596 | // If TUPLE is convertible to the single element in *this, |
| 597 | // then TUPLE should match tuple(UTypes&&...) instead. |
| 598 | template<typename _Tuple, typename _Tp, typename _Up> |
| 599 | struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Up>> |
| 600 | : __or_<is_convertible<_Tuple, _Tp>, is_constructible<_Tp, _Tuple>> |
| 601 | { }; |
| 602 | // If TUPLE and *this each have a single element of the same type, |
| 603 | // then TUPLE should match a copy/move constructor instead. |
| 604 | template<typename _Tuple, typename _Tp> |
| 605 | struct _UseOtherCtor<_Tuple, tuple<_Tp>, tuple<_Tp>> |
| 606 | : true_type |
| 607 | { }; |
| 608 | |
| 609 | // Return true iff sizeof...(Types) == 1 && tuple_size_v<TUPLE> == 1 |
| 610 | // and the single element in Types can be initialized from TUPLE, |
| 611 | // or is the same type as tuple_element_t<0, TUPLE>. |
| 612 | template<typename _Tuple> |
| 613 | static constexpr bool __use_other_ctor() |
| 614 | { return _UseOtherCtor<_Tuple>::value; } |
| 615 | |
| 616 | public: |
| 617 | template<typename _Dummy = void, |
| 618 | _ImplicitDefaultCtor<is_void<_Dummy>::value> = true> |
| 619 | constexpr |
| 620 | tuple() |
| 621 | noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value) |
| 622 | : _Inherited() { } |
| 623 | |
| 624 | template<typename _Dummy = void, |
| 625 | _ExplicitDefaultCtor<is_void<_Dummy>::value> = false> |
| 626 | explicit constexpr |
| 627 | tuple() |
| 628 | noexcept(__and_<is_nothrow_default_constructible<_Elements>...>::value) |
| 629 | : _Inherited() { } |
| 630 | |
| 631 | template<bool _NotEmpty = (sizeof...(_Elements) >= 1), |
| 632 | _ImplicitCtor<_NotEmpty, const _Elements&...> = true> |
| 633 | constexpr |
| 634 | tuple(const _Elements&... __elements) |
| 635 | noexcept(__nothrow_constructible<const _Elements&...>()) |
| 636 | : _Inherited(__elements...) { } |
| 637 | |
| 638 | template<bool _NotEmpty = (sizeof...(_Elements) >= 1), |
| 639 | _ExplicitCtor<_NotEmpty, const _Elements&...> = false> |
| 640 | explicit constexpr |
| 641 | tuple(const _Elements&... __elements) |
| 642 | noexcept(__nothrow_constructible<const _Elements&...>()) |
| 643 | : _Inherited(__elements...) { } |
| 644 | |
| 645 | template<typename... _UElements, |
| 646 | bool _Valid = __valid_args<_UElements...>(), |
| 647 | _ImplicitCtor<_Valid, _UElements...> = true> |
| 648 | constexpr |
| 649 | tuple(_UElements&&... __elements) |
| 650 | noexcept(__nothrow_constructible<_UElements...>()) |
| 651 | : _Inherited(std::forward<_UElements>(__elements)...) { } |
| 652 | |
| 653 | template<typename... _UElements, |
| 654 | bool _Valid = __valid_args<_UElements...>(), |
| 655 | _ExplicitCtor<_Valid, _UElements...> = false> |
| 656 | explicit constexpr |
| 657 | tuple(_UElements&&... __elements) |
| 658 | noexcept(__nothrow_constructible<_UElements...>()) |
| 659 | : _Inherited(std::forward<_UElements>(__elements)...) { } |
| 660 | |
| 661 | constexpr tuple(const tuple&) = default; |
| 662 | |
| 663 | constexpr tuple(tuple&&) = default; |
| 664 | |
| 665 | template<typename... _UElements, |
| 666 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 667 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
| 668 | _ImplicitCtor<_Valid, const _UElements&...> = true> |
| 669 | constexpr |
| 670 | tuple(const tuple<_UElements...>& __in) |
| 671 | noexcept(__nothrow_constructible<const _UElements&...>()) |
| 672 | : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
| 673 | { } |
| 674 | |
| 675 | template<typename... _UElements, |
| 676 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 677 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
| 678 | _ExplicitCtor<_Valid, const _UElements&...> = false> |
| 679 | explicit constexpr |
| 680 | tuple(const tuple<_UElements...>& __in) |
| 681 | noexcept(__nothrow_constructible<const _UElements&...>()) |
| 682 | : _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
| 683 | { } |
| 684 | |
| 685 | template<typename... _UElements, |
| 686 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 687 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
| 688 | _ImplicitCtor<_Valid, _UElements...> = true> |
| 689 | constexpr |
| 690 | tuple(tuple<_UElements...>&& __in) |
| 691 | noexcept(__nothrow_constructible<_UElements...>()) |
| 692 | : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } |
| 693 | |
| 694 | template<typename... _UElements, |
| 695 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 696 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
| 697 | _ExplicitCtor<_Valid, _UElements...> = false> |
| 698 | explicit constexpr |
| 699 | tuple(tuple<_UElements...>&& __in) |
| 700 | noexcept(__nothrow_constructible<_UElements...>()) |
| 701 | : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } |
| 702 | |
| 703 | // Allocator-extended constructors. |
| 704 | |
| 705 | template<typename _Alloc, |
| 706 | _ImplicitDefaultCtor<is_object<_Alloc>::value> = true> |
| 707 | _GLIBCXX20_CONSTEXPR |
| 708 | tuple(allocator_arg_t __tag, const _Alloc& __a) |
| 709 | : _Inherited(__tag, __a) { } |
| 710 | |
| 711 | template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1), |
| 712 | _ImplicitCtor<_NotEmpty, const _Elements&...> = true> |
| 713 | _GLIBCXX20_CONSTEXPR |
| 714 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 715 | const _Elements&... __elements) |
| 716 | : _Inherited(__tag, __a, __elements...) { } |
| 717 | |
| 718 | template<typename _Alloc, bool _NotEmpty = (sizeof...(_Elements) >= 1), |
| 719 | _ExplicitCtor<_NotEmpty, const _Elements&...> = false> |
| 720 | _GLIBCXX20_CONSTEXPR |
| 721 | explicit |
| 722 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 723 | const _Elements&... __elements) |
| 724 | : _Inherited(__tag, __a, __elements...) { } |
| 725 | |
| 726 | template<typename _Alloc, typename... _UElements, |
| 727 | bool _Valid = __valid_args<_UElements...>(), |
| 728 | _ImplicitCtor<_Valid, _UElements...> = true> |
| 729 | _GLIBCXX20_CONSTEXPR |
| 730 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 731 | _UElements&&... __elements) |
| 732 | : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) |
| 733 | { } |
| 734 | |
| 735 | template<typename _Alloc, typename... _UElements, |
| 736 | bool _Valid = __valid_args<_UElements...>(), |
| 737 | _ExplicitCtor<_Valid, _UElements...> = false> |
| 738 | _GLIBCXX20_CONSTEXPR |
| 739 | explicit |
| 740 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 741 | _UElements&&... __elements) |
| 742 | : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) |
| 743 | { } |
| 744 | |
| 745 | template<typename _Alloc> |
| 746 | _GLIBCXX20_CONSTEXPR |
| 747 | tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) |
| 748 | : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { } |
| 749 | |
| 750 | template<typename _Alloc> |
| 751 | _GLIBCXX20_CONSTEXPR |
| 752 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) |
| 753 | : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } |
| 754 | |
| 755 | template<typename _Alloc, typename... _UElements, |
| 756 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 757 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
| 758 | _ImplicitCtor<_Valid, const _UElements&...> = true> |
| 759 | _GLIBCXX20_CONSTEXPR |
| 760 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 761 | const tuple<_UElements...>& __in) |
| 762 | : _Inherited(__tag, __a, |
| 763 | static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
| 764 | { } |
| 765 | |
| 766 | template<typename _Alloc, typename... _UElements, |
| 767 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 768 | && !__use_other_ctor<const tuple<_UElements...>&>(), |
| 769 | _ExplicitCtor<_Valid, const _UElements&...> = false> |
| 770 | _GLIBCXX20_CONSTEXPR |
| 771 | explicit |
| 772 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 773 | const tuple<_UElements...>& __in) |
| 774 | : _Inherited(__tag, __a, |
| 775 | static_cast<const _Tuple_impl<0, _UElements...>&>(__in)) |
| 776 | { } |
| 777 | |
| 778 | template<typename _Alloc, typename... _UElements, |
| 779 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 780 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
| 781 | _ImplicitCtor<_Valid, _UElements...> = true> |
| 782 | _GLIBCXX20_CONSTEXPR |
| 783 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 784 | tuple<_UElements...>&& __in) |
| 785 | : _Inherited(__tag, __a, |
| 786 | static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) |
| 787 | { } |
| 788 | |
| 789 | template<typename _Alloc, typename... _UElements, |
| 790 | bool _Valid = (sizeof...(_Elements) == sizeof...(_UElements)) |
| 791 | && !__use_other_ctor<tuple<_UElements...>&&>(), |
| 792 | _ExplicitCtor<_Valid, _UElements...> = false> |
| 793 | _GLIBCXX20_CONSTEXPR |
| 794 | explicit |
| 795 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 796 | tuple<_UElements...>&& __in) |
| 797 | : _Inherited(__tag, __a, |
| 798 | static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) |
| 799 | { } |
| 800 | |
| 801 | // tuple assignment |
| 802 | |
| 803 | _GLIBCXX20_CONSTEXPR |
| 804 | tuple& |
| 805 | operator=(typename conditional<__assignable<const _Elements&...>(), |
| 806 | const tuple&, |
| 807 | const __nonesuch&>::type __in) |
| 808 | noexcept(__nothrow_assignable<const _Elements&...>()) |
| 809 | { |
| 810 | this->_M_assign(__in); |
| 811 | return *this; |
| 812 | } |
| 813 | |
| 814 | _GLIBCXX20_CONSTEXPR |
| 815 | tuple& |
| 816 | operator=(typename conditional<__assignable<_Elements...>(), |
| 817 | tuple&&, |
| 818 | __nonesuch&&>::type __in) |
| 819 | noexcept(__nothrow_assignable<_Elements...>()) |
| 820 | { |
| 821 | this->_M_assign(std::move(__in)); |
| 822 | return *this; |
| 823 | } |
| 824 | |
| 825 | template<typename... _UElements> |
| 826 | _GLIBCXX20_CONSTEXPR |
| 827 | __enable_if_t<__assignable<const _UElements&...>(), tuple&> |
| 828 | operator=(const tuple<_UElements...>& __in) |
| 829 | noexcept(__nothrow_assignable<const _UElements&...>()) |
| 830 | { |
| 831 | this->_M_assign(__in); |
| 832 | return *this; |
| 833 | } |
| 834 | |
| 835 | template<typename... _UElements> |
| 836 | _GLIBCXX20_CONSTEXPR |
| 837 | __enable_if_t<__assignable<_UElements...>(), tuple&> |
| 838 | operator=(tuple<_UElements...>&& __in) |
| 839 | noexcept(__nothrow_assignable<_UElements...>()) |
| 840 | { |
| 841 | this->_M_assign(std::move(__in)); |
| 842 | return *this; |
| 843 | } |
| 844 | |
| 845 | // tuple swap |
| 846 | _GLIBCXX20_CONSTEXPR |
| 847 | void |
| 848 | swap(tuple& __in) |
| 849 | noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value) |
| 850 | { _Inherited::_M_swap(__in); } |
| 851 | }; |
| 852 | |
| 853 | #if __cpp_deduction_guides >= 201606 |
| 854 | template<typename... _UTypes> |
| 855 | tuple(_UTypes...) -> tuple<_UTypes...>; |
| 856 | template<typename _T1, typename _T2> |
| 857 | tuple(pair<_T1, _T2>) -> tuple<_T1, _T2>; |
| 858 | template<typename _Alloc, typename... _UTypes> |
| 859 | tuple(allocator_arg_t, _Alloc, _UTypes...) -> tuple<_UTypes...>; |
| 860 | template<typename _Alloc, typename _T1, typename _T2> |
| 861 | tuple(allocator_arg_t, _Alloc, pair<_T1, _T2>) -> tuple<_T1, _T2>; |
| 862 | template<typename _Alloc, typename... _UTypes> |
| 863 | tuple(allocator_arg_t, _Alloc, tuple<_UTypes...>) -> tuple<_UTypes...>; |
| 864 | #endif |
| 865 | |
| 866 | // Explicit specialization, zero-element tuple. |
| 867 | template<> |
| 868 | class tuple<> |
| 869 | { |
| 870 | public: |
| 871 | void swap(tuple&) noexcept { /* no-op */ } |
| 872 | // We need the default since we're going to define no-op |
| 873 | // allocator constructors. |
| 874 | tuple() = default; |
| 875 | // No-op allocator constructors. |
| 876 | template<typename _Alloc> |
| 877 | _GLIBCXX20_CONSTEXPR |
| 878 | tuple(allocator_arg_t, const _Alloc&) noexcept { } |
| 879 | template<typename _Alloc> |
| 880 | _GLIBCXX20_CONSTEXPR |
| 881 | tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept { } |
| 882 | }; |
| 883 | |
| 884 | /// Partial specialization, 2-element tuple. |
| 885 | /// Includes construction and assignment from a pair. |
| 886 | template<typename _T1, typename _T2> |
| 887 | class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2> |
| 888 | { |
| 889 | typedef _Tuple_impl<0, _T1, _T2> _Inherited; |
| 890 | |
| 891 | // Constraint for non-explicit default constructor |
| 892 | template<bool _Dummy, typename _U1, typename _U2> |
| 893 | using _ImplicitDefaultCtor = __enable_if_t< |
| 894 | _TupleConstraints<_Dummy, _U1, _U2>:: |
| 895 | __is_implicitly_default_constructible(), |
| 896 | bool>; |
| 897 | |
| 898 | // Constraint for explicit default constructor |
| 899 | template<bool _Dummy, typename _U1, typename _U2> |
| 900 | using _ExplicitDefaultCtor = __enable_if_t< |
| 901 | _TupleConstraints<_Dummy, _U1, _U2>:: |
| 902 | __is_explicitly_default_constructible(), |
| 903 | bool>; |
| 904 | |
| 905 | template<bool _Dummy> |
| 906 | using _TCC = _TupleConstraints<_Dummy, _T1, _T2>; |
| 907 | |
| 908 | // Constraint for non-explicit constructors |
| 909 | template<bool _Cond, typename _U1, typename _U2> |
| 910 | using _ImplicitCtor = __enable_if_t< |
| 911 | _TCC<_Cond>::template __is_implicitly_constructible<_U1, _U2>(), |
| 912 | bool>; |
| 913 | |
| 914 | // Constraint for non-explicit constructors |
| 915 | template<bool _Cond, typename _U1, typename _U2> |
| 916 | using _ExplicitCtor = __enable_if_t< |
| 917 | _TCC<_Cond>::template __is_explicitly_constructible<_U1, _U2>(), |
| 918 | bool>; |
| 919 | |
| 920 | template<typename _U1, typename _U2> |
| 921 | static constexpr bool __assignable() |
| 922 | { |
| 923 | return __and_<is_assignable<_T1&, _U1>, |
| 924 | is_assignable<_T2&, _U2>>::value; |
| 925 | } |
| 926 | |
| 927 | template<typename _U1, typename _U2> |
| 928 | static constexpr bool __nothrow_assignable() |
| 929 | { |
| 930 | return __and_<is_nothrow_assignable<_T1&, _U1>, |
| 931 | is_nothrow_assignable<_T2&, _U2>>::value; |
| 932 | } |
| 933 | |
| 934 | template<typename _U1, typename _U2> |
| 935 | static constexpr bool __nothrow_constructible() |
| 936 | { |
| 937 | return __and_<is_nothrow_constructible<_T1, _U1>, |
| 938 | is_nothrow_constructible<_T2, _U2>>::value; |
| 939 | } |
| 940 | |
| 941 | static constexpr bool __nothrow_default_constructible() |
| 942 | { |
| 943 | return __and_<is_nothrow_default_constructible<_T1>, |
| 944 | is_nothrow_default_constructible<_T2>>::value; |
| 945 | } |
| 946 | |
| 947 | template<typename _U1> |
| 948 | static constexpr bool __is_alloc_arg() |
| 949 | { return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; } |
| 950 | |
| 951 | public: |
| 952 | template<bool _Dummy = true, |
| 953 | _ImplicitDefaultCtor<_Dummy, _T1, _T2> = true> |
| 954 | constexpr |
| 955 | tuple() |
| 956 | noexcept(__nothrow_default_constructible()) |
| 957 | : _Inherited() { } |
| 958 | |
| 959 | template<bool _Dummy = true, |
| 960 | _ExplicitDefaultCtor<_Dummy, _T1, _T2> = false> |
| 961 | explicit constexpr |
| 962 | tuple() |
| 963 | noexcept(__nothrow_default_constructible()) |
| 964 | : _Inherited() { } |
| 965 | |
| 966 | template<bool _Dummy = true, |
| 967 | _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true> |
| 968 | constexpr |
| 969 | tuple(const _T1& __a1, const _T2& __a2) |
| 970 | noexcept(__nothrow_constructible<const _T1&, const _T2&>()) |
| 971 | : _Inherited(__a1, __a2) { } |
| 972 | |
| 973 | template<bool _Dummy = true, |
| 974 | _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false> |
| 975 | explicit constexpr |
| 976 | tuple(const _T1& __a1, const _T2& __a2) |
| 977 | noexcept(__nothrow_constructible<const _T1&, const _T2&>()) |
| 978 | : _Inherited(__a1, __a2) { } |
| 979 | |
| 980 | template<typename _U1, typename _U2, |
| 981 | _ImplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = true> |
| 982 | constexpr |
| 983 | tuple(_U1&& __a1, _U2&& __a2) |
| 984 | noexcept(__nothrow_constructible<_U1, _U2>()) |
| 985 | : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } |
| 986 | |
| 987 | template<typename _U1, typename _U2, |
| 988 | _ExplicitCtor<!__is_alloc_arg<_U1>(), _U1, _U2> = false> |
| 989 | explicit constexpr |
| 990 | tuple(_U1&& __a1, _U2&& __a2) |
| 991 | noexcept(__nothrow_constructible<_U1, _U2>()) |
| 992 | : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } |
| 993 | |
| 994 | constexpr tuple(const tuple&) = default; |
| 995 | |
| 996 | constexpr tuple(tuple&&) = default; |
| 997 | |
| 998 | template<typename _U1, typename _U2, |
| 999 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
| 1000 | constexpr |
| 1001 | tuple(const tuple<_U1, _U2>& __in) |
| 1002 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
| 1003 | : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } |
| 1004 | |
| 1005 | template<typename _U1, typename _U2, |
| 1006 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
| 1007 | explicit constexpr |
| 1008 | tuple(const tuple<_U1, _U2>& __in) |
| 1009 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
| 1010 | : _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) { } |
| 1011 | |
| 1012 | template<typename _U1, typename _U2, |
| 1013 | _ImplicitCtor<true, _U1, _U2> = true> |
| 1014 | constexpr |
| 1015 | tuple(tuple<_U1, _U2>&& __in) |
| 1016 | noexcept(__nothrow_constructible<_U1, _U2>()) |
| 1017 | : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } |
| 1018 | |
| 1019 | template<typename _U1, typename _U2, |
| 1020 | _ExplicitCtor<true, _U1, _U2> = false> |
| 1021 | explicit constexpr |
| 1022 | tuple(tuple<_U1, _U2>&& __in) |
| 1023 | noexcept(__nothrow_constructible<_U1, _U2>()) |
| 1024 | : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } |
| 1025 | |
| 1026 | template<typename _U1, typename _U2, |
| 1027 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
| 1028 | constexpr |
| 1029 | tuple(const pair<_U1, _U2>& __in) |
| 1030 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
| 1031 | : _Inherited(__in.first, __in.second) { } |
| 1032 | |
| 1033 | template<typename _U1, typename _U2, |
| 1034 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
| 1035 | explicit constexpr |
| 1036 | tuple(const pair<_U1, _U2>& __in) |
| 1037 | noexcept(__nothrow_constructible<const _U1&, const _U2&>()) |
| 1038 | : _Inherited(__in.first, __in.second) { } |
| 1039 | |
| 1040 | template<typename _U1, typename _U2, |
| 1041 | _ImplicitCtor<true, _U1, _U2> = true> |
| 1042 | constexpr |
| 1043 | tuple(pair<_U1, _U2>&& __in) |
| 1044 | noexcept(__nothrow_constructible<_U1, _U2>()) |
| 1045 | : _Inherited(std::forward<_U1>(__in.first), |
| 1046 | std::forward<_U2>(__in.second)) { } |
| 1047 | |
| 1048 | template<typename _U1, typename _U2, |
| 1049 | _ExplicitCtor<true, _U1, _U2> = false> |
| 1050 | explicit constexpr |
| 1051 | tuple(pair<_U1, _U2>&& __in) |
| 1052 | noexcept(__nothrow_constructible<_U1, _U2>()) |
| 1053 | : _Inherited(std::forward<_U1>(__in.first), |
| 1054 | std::forward<_U2>(__in.second)) { } |
| 1055 | |
| 1056 | // Allocator-extended constructors. |
| 1057 | |
| 1058 | template<typename _Alloc, |
| 1059 | _ImplicitDefaultCtor<is_object<_Alloc>::value, _T1, _T2> = true> |
| 1060 | _GLIBCXX20_CONSTEXPR |
| 1061 | tuple(allocator_arg_t __tag, const _Alloc& __a) |
| 1062 | : _Inherited(__tag, __a) { } |
| 1063 | |
| 1064 | template<typename _Alloc, bool _Dummy = true, |
| 1065 | _ImplicitCtor<_Dummy, const _T1&, const _T2&> = true> |
| 1066 | _GLIBCXX20_CONSTEXPR |
| 1067 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1068 | const _T1& __a1, const _T2& __a2) |
| 1069 | : _Inherited(__tag, __a, __a1, __a2) { } |
| 1070 | |
| 1071 | template<typename _Alloc, bool _Dummy = true, |
| 1072 | _ExplicitCtor<_Dummy, const _T1&, const _T2&> = false> |
| 1073 | explicit |
| 1074 | _GLIBCXX20_CONSTEXPR |
| 1075 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1076 | const _T1& __a1, const _T2& __a2) |
| 1077 | : _Inherited(__tag, __a, __a1, __a2) { } |
| 1078 | |
| 1079 | template<typename _Alloc, typename _U1, typename _U2, |
| 1080 | _ImplicitCtor<true, _U1, _U2> = true> |
| 1081 | _GLIBCXX20_CONSTEXPR |
| 1082 | tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2) |
| 1083 | : _Inherited(__tag, __a, std::forward<_U1>(__a1), |
| 1084 | std::forward<_U2>(__a2)) { } |
| 1085 | |
| 1086 | template<typename _Alloc, typename _U1, typename _U2, |
| 1087 | _ExplicitCtor<true, _U1, _U2> = false> |
| 1088 | explicit |
| 1089 | _GLIBCXX20_CONSTEXPR |
| 1090 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1091 | _U1&& __a1, _U2&& __a2) |
| 1092 | : _Inherited(__tag, __a, std::forward<_U1>(__a1), |
| 1093 | std::forward<_U2>(__a2)) { } |
| 1094 | |
| 1095 | template<typename _Alloc> |
| 1096 | _GLIBCXX20_CONSTEXPR |
| 1097 | tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) |
| 1098 | : _Inherited(__tag, __a, static_cast<const _Inherited&>(__in)) { } |
| 1099 | |
| 1100 | template<typename _Alloc> |
| 1101 | _GLIBCXX20_CONSTEXPR |
| 1102 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) |
| 1103 | : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } |
| 1104 | |
| 1105 | template<typename _Alloc, typename _U1, typename _U2, |
| 1106 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
| 1107 | _GLIBCXX20_CONSTEXPR |
| 1108 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1109 | const tuple<_U1, _U2>& __in) |
| 1110 | : _Inherited(__tag, __a, |
| 1111 | static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) |
| 1112 | { } |
| 1113 | |
| 1114 | template<typename _Alloc, typename _U1, typename _U2, |
| 1115 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
| 1116 | explicit |
| 1117 | _GLIBCXX20_CONSTEXPR |
| 1118 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1119 | const tuple<_U1, _U2>& __in) |
| 1120 | : _Inherited(__tag, __a, |
| 1121 | static_cast<const _Tuple_impl<0, _U1, _U2>&>(__in)) |
| 1122 | { } |
| 1123 | |
| 1124 | template<typename _Alloc, typename _U1, typename _U2, |
| 1125 | _ImplicitCtor<true, _U1, _U2> = true> |
| 1126 | _GLIBCXX20_CONSTEXPR |
| 1127 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) |
| 1128 | : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) |
| 1129 | { } |
| 1130 | |
| 1131 | template<typename _Alloc, typename _U1, typename _U2, |
| 1132 | _ExplicitCtor<true, _U1, _U2> = false> |
| 1133 | explicit |
| 1134 | _GLIBCXX20_CONSTEXPR |
| 1135 | tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) |
| 1136 | : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) |
| 1137 | { } |
| 1138 | |
| 1139 | template<typename _Alloc, typename _U1, typename _U2, |
| 1140 | _ImplicitCtor<true, const _U1&, const _U2&> = true> |
| 1141 | _GLIBCXX20_CONSTEXPR |
| 1142 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1143 | const pair<_U1, _U2>& __in) |
| 1144 | : _Inherited(__tag, __a, __in.first, __in.second) { } |
| 1145 | |
| 1146 | template<typename _Alloc, typename _U1, typename _U2, |
| 1147 | _ExplicitCtor<true, const _U1&, const _U2&> = false> |
| 1148 | explicit |
| 1149 | _GLIBCXX20_CONSTEXPR |
| 1150 | tuple(allocator_arg_t __tag, const _Alloc& __a, |
| 1151 | const pair<_U1, _U2>& __in) |
| 1152 | : _Inherited(__tag, __a, __in.first, __in.second) { } |
| 1153 | |
| 1154 | template<typename _Alloc, typename _U1, typename _U2, |
| 1155 | _ImplicitCtor<true, _U1, _U2> = true> |
| 1156 | _GLIBCXX20_CONSTEXPR |
| 1157 | tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) |
| 1158 | : _Inherited(__tag, __a, std::forward<_U1>(__in.first), |
| 1159 | std::forward<_U2>(__in.second)) { } |
| 1160 | |
| 1161 | template<typename _Alloc, typename _U1, typename _U2, |
| 1162 | _ExplicitCtor<true, _U1, _U2> = false> |
| 1163 | explicit |
| 1164 | _GLIBCXX20_CONSTEXPR |
| 1165 | tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) |
| 1166 | : _Inherited(__tag, __a, std::forward<_U1>(__in.first), |
| 1167 | std::forward<_U2>(__in.second)) { } |
| 1168 | |
| 1169 | // Tuple assignment. |
| 1170 | |
| 1171 | _GLIBCXX20_CONSTEXPR |
| 1172 | tuple& |
| 1173 | operator=(typename conditional<__assignable<const _T1&, const _T2&>(), |
| 1174 | const tuple&, |
| 1175 | const __nonesuch&>::type __in) |
| 1176 | noexcept(__nothrow_assignable<const _T1&, const _T2&>()) |
| 1177 | { |
| 1178 | this->_M_assign(__in); |
| 1179 | return *this; |
| 1180 | } |
| 1181 | |
| 1182 | _GLIBCXX20_CONSTEXPR |
| 1183 | tuple& |
| 1184 | operator=(typename conditional<__assignable<_T1, _T2>(), |
| 1185 | tuple&&, |
| 1186 | __nonesuch&&>::type __in) |
| 1187 | noexcept(__nothrow_assignable<_T1, _T2>()) |
| 1188 | { |
| 1189 | this->_M_assign(std::move(__in)); |
| 1190 | return *this; |
| 1191 | } |
| 1192 | |
| 1193 | template<typename _U1, typename _U2> |
| 1194 | _GLIBCXX20_CONSTEXPR |
| 1195 | __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&> |
| 1196 | operator=(const tuple<_U1, _U2>& __in) |
| 1197 | noexcept(__nothrow_assignable<const _U1&, const _U2&>()) |
| 1198 | { |
| 1199 | this->_M_assign(__in); |
| 1200 | return *this; |
| 1201 | } |
| 1202 | |
| 1203 | template<typename _U1, typename _U2> |
| 1204 | _GLIBCXX20_CONSTEXPR |
| 1205 | __enable_if_t<__assignable<_U1, _U2>(), tuple&> |
| 1206 | operator=(tuple<_U1, _U2>&& __in) |
| 1207 | noexcept(__nothrow_assignable<_U1, _U2>()) |
| 1208 | { |
| 1209 | this->_M_assign(std::move(__in)); |
| 1210 | return *this; |
| 1211 | } |
| 1212 | |
| 1213 | template<typename _U1, typename _U2> |
| 1214 | _GLIBCXX20_CONSTEXPR |
| 1215 | __enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&> |
| 1216 | operator=(const pair<_U1, _U2>& __in) |
| 1217 | noexcept(__nothrow_assignable<const _U1&, const _U2&>()) |
| 1218 | { |
| 1219 | this->_M_head(*this) = __in.first; |
| 1220 | this->_M_tail(*this)._M_head(*this) = __in.second; |
| 1221 | return *this; |
| 1222 | } |
| 1223 | |
| 1224 | template<typename _U1, typename _U2> |
| 1225 | _GLIBCXX20_CONSTEXPR |
| 1226 | __enable_if_t<__assignable<_U1, _U2>(), tuple&> |
| 1227 | operator=(pair<_U1, _U2>&& __in) |
| 1228 | noexcept(__nothrow_assignable<_U1, _U2>()) |
| 1229 | { |
| 1230 | this->_M_head(*this) = std::forward<_U1>(__in.first); |
| 1231 | this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second); |
| 1232 | return *this; |
| 1233 | } |
| 1234 | |
| 1235 | _GLIBCXX20_CONSTEXPR |
| 1236 | void |
| 1237 | swap(tuple& __in) |
| 1238 | noexcept(__and_<__is_nothrow_swappable<_T1>, |
| 1239 | __is_nothrow_swappable<_T2>>::value) |
| 1240 | { _Inherited::_M_swap(__in); } |
| 1241 | }; |
| 1242 | |
| 1243 | |
| 1244 | /// class tuple_size |
| 1245 | template<typename... _Elements> |
| 1246 | struct tuple_size<tuple<_Elements...>> |
| 1247 | : public integral_constant<std::size_t, sizeof...(_Elements)> { }; |
| 1248 | |
| 1249 | #if __cplusplus201402L > 201402L |
| 1250 | template <typename _Tp> |
| 1251 | inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value; |
| 1252 | #endif |
| 1253 | |
| 1254 | /** |
| 1255 | * Recursive case for tuple_element: strip off the first element in |
| 1256 | * the tuple and retrieve the (i-1)th element of the remaining tuple. |
| 1257 | */ |
| 1258 | template<std::size_t __i, typename _Head, typename... _Tail> |
| 1259 | struct tuple_element<__i, tuple<_Head, _Tail...> > |
| 1260 | : tuple_element<__i - 1, tuple<_Tail...> > { }; |
| 1261 | |
| 1262 | /** |
| 1263 | * Basis case for tuple_element: The first element is the one we're seeking. |
| 1264 | */ |
| 1265 | template<typename _Head, typename... _Tail> |
| 1266 | struct tuple_element<0, tuple<_Head, _Tail...> > |
| 1267 | { |
| 1268 | typedef _Head type; |
| 1269 | }; |
| 1270 | |
| 1271 | /** |
| 1272 | * Error case for tuple_element: invalid index. |
| 1273 | */ |
| 1274 | template<size_t __i> |
| 1275 | struct tuple_element<__i, tuple<>> |
| 1276 | { |
| 1277 | static_assert(__i < tuple_size<tuple<>>::value, |
| 1278 | "tuple index is in range"); |
| 1279 | }; |
| 1280 | |
| 1281 | template<std::size_t __i, typename _Head, typename... _Tail> |
| 1282 | constexpr _Head& |
| 1283 | __get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
| 1284 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
| 1285 | |
| 1286 | template<std::size_t __i, typename _Head, typename... _Tail> |
| 1287 | constexpr const _Head& |
| 1288 | __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
| 1289 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
| 1290 | |
| 1291 | /// Return a reference to the ith element of a tuple. |
| 1292 | template<std::size_t __i, typename... _Elements> |
| 1293 | constexpr __tuple_element_t<__i, tuple<_Elements...>>& |
| 1294 | get(tuple<_Elements...>& __t) noexcept |
| 1295 | { return std::__get_helper<__i>(__t); } |
| 1296 | |
| 1297 | /// Return a const reference to the ith element of a const tuple. |
| 1298 | template<std::size_t __i, typename... _Elements> |
| 1299 | constexpr const __tuple_element_t<__i, tuple<_Elements...>>& |
| 1300 | get(const tuple<_Elements...>& __t) noexcept |
| 1301 | { return std::__get_helper<__i>(__t); } |
| 1302 | |
| 1303 | /// Return an rvalue reference to the ith element of a tuple rvalue. |
| 1304 | template<std::size_t __i, typename... _Elements> |
| 1305 | constexpr __tuple_element_t<__i, tuple<_Elements...>>&& |
| 1306 | get(tuple<_Elements...>&& __t) noexcept |
| 1307 | { |
| 1308 | typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type; |
| 1309 | return std::forward<__element_type&&>(std::get<__i>(__t)); |
| 1310 | } |
| 1311 | |
| 1312 | /// Return a const rvalue reference to the ith element of a const tuple rvalue. |
| 1313 | template<std::size_t __i, typename... _Elements> |
| 1314 | constexpr const __tuple_element_t<__i, tuple<_Elements...>>&& |
| 1315 | get(const tuple<_Elements...>&& __t) noexcept |
| 1316 | { |
| 1317 | typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type; |
| 1318 | return std::forward<const __element_type&&>(std::get<__i>(__t)); |
| 1319 | } |
| 1320 | |
| 1321 | #if __cplusplus201402L >= 201402L |
| 1322 | |
| 1323 | #define __cpp_lib_tuples_by_type201304 201304 |
| 1324 | |
| 1325 | template<typename _Head, size_t __i, typename... _Tail> |
| 1326 | constexpr _Head& |
| 1327 | __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
| 1328 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
| 1329 | |
| 1330 | template<typename _Head, size_t __i, typename... _Tail> |
| 1331 | constexpr const _Head& |
| 1332 | __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept |
| 1333 | { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } |
| 1334 | |
| 1335 | /// Return a reference to the unique element of type _Tp of a tuple. |
| 1336 | template <typename _Tp, typename... _Types> |
| 1337 | constexpr _Tp& |
| 1338 | get(tuple<_Types...>& __t) noexcept |
| 1339 | { return std::__get_helper2<_Tp>(__t); } |
| 1340 | |
| 1341 | /// Return a reference to the unique element of type _Tp of a tuple rvalue. |
| 1342 | template <typename _Tp, typename... _Types> |
| 1343 | constexpr _Tp&& |
| 1344 | get(tuple<_Types...>&& __t) noexcept |
| 1345 | { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } |
| 1346 | |
| 1347 | /// Return a const reference to the unique element of type _Tp of a tuple. |
| 1348 | template <typename _Tp, typename... _Types> |
| 1349 | constexpr const _Tp& |
| 1350 | get(const tuple<_Types...>& __t) noexcept |
| 1351 | { return std::__get_helper2<_Tp>(__t); } |
| 1352 | |
| 1353 | /// Return a const reference to the unique element of type _Tp of |
| 1354 | /// a const tuple rvalue. |
| 1355 | template <typename _Tp, typename... _Types> |
| 1356 | constexpr const _Tp&& |
| 1357 | get(const tuple<_Types...>&& __t) noexcept |
| 1358 | { return std::forward<const _Tp&&>(std::__get_helper2<_Tp>(__t)); } |
| 1359 | #endif |
| 1360 | |
| 1361 | // This class performs the comparison operations on tuples |
| 1362 | template<typename _Tp, typename _Up, size_t __i, size_t __size> |
| 1363 | struct __tuple_compare |
| 1364 | { |
| 1365 | static constexpr bool |
| 1366 | __eq(const _Tp& __t, const _Up& __u) |
| 1367 | { |
| 1368 | return bool(std::get<__i>(__t) == std::get<__i>(__u)) |
| 1369 | && __tuple_compare<_Tp, _Up, __i + 1, __size>::__eq(__t, __u); |
| 1370 | } |
| 1371 | |
| 1372 | static constexpr bool |
| 1373 | __less(const _Tp& __t, const _Up& __u) |
| 1374 | { |
| 1375 | return bool(std::get<__i>(__t) < std::get<__i>(__u)) |
| 1376 | || (!bool(std::get<__i>(__u) < std::get<__i>(__t)) |
| 1377 | && __tuple_compare<_Tp, _Up, __i + 1, __size>::__less(__t, __u)); |
| 1378 | } |
| 1379 | }; |
| 1380 | |
| 1381 | template<typename _Tp, typename _Up, size_t __size> |
| 1382 | struct __tuple_compare<_Tp, _Up, __size, __size> |
| 1383 | { |
| 1384 | static constexpr bool |
| 1385 | __eq(const _Tp&, const _Up&) { return true; } |
| 1386 | |
| 1387 | static constexpr bool |
| 1388 | __less(const _Tp&, const _Up&) { return false; } |
| 1389 | }; |
| 1390 | |
| 1391 | template<typename... _TElements, typename... _UElements> |
| 1392 | constexpr bool |
| 1393 | operator==(const tuple<_TElements...>& __t, |
| 1394 | const tuple<_UElements...>& __u) |
| 1395 | { |
| 1396 | static_assert(sizeof...(_TElements) == sizeof...(_UElements), |
| 1397 | "tuple objects can only be compared if they have equal sizes."); |
| 1398 | using __compare = __tuple_compare<tuple<_TElements...>, |
| 1399 | tuple<_UElements...>, |
| 1400 | 0, sizeof...(_TElements)>; |
| 1401 | return __compare::__eq(__t, __u); |
| 1402 | } |
| 1403 | |
| 1404 | #if __cpp_lib_three_way_comparison |
| 1405 | template<typename _Cat, typename _Tp, typename _Up> |
| 1406 | constexpr _Cat |
| 1407 | __tuple_cmp(const _Tp&, const _Up&, index_sequence<>) |
| 1408 | { return _Cat::equivalent; } |
| 1409 | |
| 1410 | template<typename _Cat, typename _Tp, typename _Up, |
| 1411 | size_t _Idx0, size_t... _Idxs> |
| 1412 | constexpr _Cat |
| 1413 | __tuple_cmp(const _Tp& __t, const _Up& __u, |
| 1414 | index_sequence<_Idx0, _Idxs...>) |
| 1415 | { |
| 1416 | auto __c |
| 1417 | = __detail::__synth3way(std::get<_Idx0>(__t), std::get<_Idx0>(__u)); |
| 1418 | if (__c != 0) |
| 1419 | return __c; |
| 1420 | return std::__tuple_cmp<_Cat>(__t, __u, index_sequence<_Idxs...>()); |
| 1421 | } |
| 1422 | |
| 1423 | template<typename... _Tps, typename... _Ups> |
| 1424 | constexpr |
| 1425 | common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...> |
| 1426 | operator<=>(const tuple<_Tps...>& __t, const tuple<_Ups...>& __u) |
| 1427 | { |
| 1428 | using _Cat |
| 1429 | = common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>; |
| 1430 | return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>()); |
| 1431 | } |
| 1432 | #else |
| 1433 | template<typename... _TElements, typename... _UElements> |
| 1434 | constexpr bool |
| 1435 | operator<(const tuple<_TElements...>& __t, |
| 1436 | const tuple<_UElements...>& __u) |
| 1437 | { |
| 1438 | static_assert(sizeof...(_TElements) == sizeof...(_UElements), |
| 1439 | "tuple objects can only be compared if they have equal sizes."); |
| 1440 | using __compare = __tuple_compare<tuple<_TElements...>, |
| 1441 | tuple<_UElements...>, |
| 1442 | 0, sizeof...(_TElements)>; |
| 1443 | return __compare::__less(__t, __u); |
| 1444 | } |
| 1445 | |
| 1446 | template<typename... _TElements, typename... _UElements> |
| 1447 | constexpr bool |
| 1448 | operator!=(const tuple<_TElements...>& __t, |
| 1449 | const tuple<_UElements...>& __u) |
| 1450 | { return !(__t == __u); } |
| 1451 | |
| 1452 | template<typename... _TElements, typename... _UElements> |
| 1453 | constexpr bool |
| 1454 | operator>(const tuple<_TElements...>& __t, |
| 1455 | const tuple<_UElements...>& __u) |
| 1456 | { return __u < __t; } |
| 1457 | |
| 1458 | template<typename... _TElements, typename... _UElements> |
| 1459 | constexpr bool |
| 1460 | operator<=(const tuple<_TElements...>& __t, |
| 1461 | const tuple<_UElements...>& __u) |
| 1462 | { return !(__u < __t); } |
| 1463 | |
| 1464 | template<typename... _TElements, typename... _UElements> |
| 1465 | constexpr bool |
| 1466 | operator>=(const tuple<_TElements...>& __t, |
| 1467 | const tuple<_UElements...>& __u) |
| 1468 | { return !(__t < __u); } |
| 1469 | #endif // three_way_comparison |
| 1470 | |
| 1471 | // NB: DR 705. |
| 1472 | template<typename... _Elements> |
| 1473 | constexpr tuple<typename __decay_and_strip<_Elements>::__type...> |
| 1474 | make_tuple(_Elements&&... __args) |
| 1475 | { |
| 1476 | typedef tuple<typename __decay_and_strip<_Elements>::__type...> |
| 1477 | __result_type; |
| 1478 | return __result_type(std::forward<_Elements>(__args)...); |
| 1479 | } |
| 1480 | |
| 1481 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
| 1482 | // 2275. Why is forward_as_tuple not constexpr? |
| 1483 | /// std::forward_as_tuple |
| 1484 | template<typename... _Elements> |
| 1485 | constexpr tuple<_Elements&&...> |
| 1486 | forward_as_tuple(_Elements&&... __args) noexcept |
| 1487 | { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); } |
| 1488 | |
| 1489 | template<size_t, typename, typename, size_t> |
| 1490 | struct __make_tuple_impl; |
| 1491 | |
| 1492 | template<size_t _Idx, typename _Tuple, typename... _Tp, size_t _Nm> |
| 1493 | struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm> |
| 1494 | : __make_tuple_impl<_Idx + 1, |
| 1495 | tuple<_Tp..., __tuple_element_t<_Idx, _Tuple>>, |
| 1496 | _Tuple, _Nm> |
| 1497 | { }; |
| 1498 | |
| 1499 | template<std::size_t _Nm, typename _Tuple, typename... _Tp> |
| 1500 | struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm> |
| 1501 | { |
| 1502 | typedef tuple<_Tp...> __type; |
| 1503 | }; |
| 1504 | |
| 1505 | template<typename _Tuple> |
| 1506 | struct __do_make_tuple |
| 1507 | : __make_tuple_impl<0, tuple<>, _Tuple, std::tuple_size<_Tuple>::value> |
| 1508 | { }; |
| 1509 | |
| 1510 | // Returns the std::tuple equivalent of a tuple-like type. |
| 1511 | template<typename _Tuple> |
| 1512 | struct __make_tuple |
| 1513 | : public __do_make_tuple<__remove_cvref_t<_Tuple>> |
| 1514 | { }; |
| 1515 | |
| 1516 | // Combines several std::tuple's into a single one. |
| 1517 | template<typename...> |
| 1518 | struct __combine_tuples; |
| 1519 | |
| 1520 | template<> |
| 1521 | struct __combine_tuples<> |
| 1522 | { |
| 1523 | typedef tuple<> __type; |
| 1524 | }; |
| 1525 | |
| 1526 | template<typename... _Ts> |
| 1527 | struct __combine_tuples<tuple<_Ts...>> |
| 1528 | { |
| 1529 | typedef tuple<_Ts...> __type; |
| 1530 | }; |
| 1531 | |
| 1532 | template<typename... _T1s, typename... _T2s, typename... _Rem> |
| 1533 | struct __combine_tuples<tuple<_T1s...>, tuple<_T2s...>, _Rem...> |
| 1534 | { |
| 1535 | typedef typename __combine_tuples<tuple<_T1s..., _T2s...>, |
| 1536 | _Rem...>::__type __type; |
| 1537 | }; |
| 1538 | |
| 1539 | // Computes the result type of tuple_cat given a set of tuple-like types. |
| 1540 | template<typename... _Tpls> |
| 1541 | struct __tuple_cat_result |
| 1542 | { |
| 1543 | typedef typename __combine_tuples |
| 1544 | <typename __make_tuple<_Tpls>::__type...>::__type __type; |
| 1545 | }; |
| 1546 | |
| 1547 | // Helper to determine the index set for the first tuple-like |
| 1548 | // type of a given set. |
| 1549 | template<typename...> |
| 1550 | struct __make_1st_indices; |
| 1551 | |
| 1552 | template<> |
| 1553 | struct __make_1st_indices<> |
| 1554 | { |
| 1555 | typedef std::_Index_tuple<> __type; |
| 1556 | }; |
| 1557 | |
| 1558 | template<typename _Tp, typename... _Tpls> |
| 1559 | struct __make_1st_indices<_Tp, _Tpls...> |
| 1560 | { |
| 1561 | typedef typename std::_Build_index_tuple<std::tuple_size< |
| 1562 | typename std::remove_reference<_Tp>::type>::value>::__type __type; |
| 1563 | }; |
| 1564 | |
| 1565 | // Performs the actual concatenation by step-wise expanding tuple-like |
| 1566 | // objects into the elements, which are finally forwarded into the |
| 1567 | // result tuple. |
| 1568 | template<typename _Ret, typename _Indices, typename... _Tpls> |
| 1569 | struct __tuple_concater; |
| 1570 | |
| 1571 | template<typename _Ret, std::size_t... _Is, typename _Tp, typename... _Tpls> |
| 1572 | struct __tuple_concater<_Ret, std::_Index_tuple<_Is...>, _Tp, _Tpls...> |
| 1573 | { |
| 1574 | template<typename... _Us> |
| 1575 | static constexpr _Ret |
| 1576 | _S_do(_Tp&& __tp, _Tpls&&... __tps, _Us&&... __us) |
| 1577 | { |
| 1578 | typedef typename __make_1st_indices<_Tpls...>::__type __idx; |
| 1579 | typedef __tuple_concater<_Ret, __idx, _Tpls...> __next; |
| 1580 | return __next::_S_do(std::forward<_Tpls>(__tps)..., |
| 1581 | std::forward<_Us>(__us)..., |
| 1582 | std::get<_Is>(std::forward<_Tp>(__tp))...); |
| 1583 | } |
| 1584 | }; |
| 1585 | |
| 1586 | template<typename _Ret> |
| 1587 | struct __tuple_concater<_Ret, std::_Index_tuple<>> |
| 1588 | { |
| 1589 | template<typename... _Us> |
| 1590 | static constexpr _Ret |
| 1591 | _S_do(_Us&&... __us) |
| 1592 | { |
| 1593 | return _Ret(std::forward<_Us>(__us)...); |
| 1594 | } |
| 1595 | }; |
| 1596 | |
| 1597 | /// tuple_cat |
| 1598 | template<typename... _Tpls, typename = typename |
| 1599 | enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type> |
| 1600 | constexpr auto |
| 1601 | tuple_cat(_Tpls&&... __tpls) |
| 1602 | -> typename __tuple_cat_result<_Tpls...>::__type |
| 1603 | { |
| 1604 | typedef typename __tuple_cat_result<_Tpls...>::__type __ret; |
| 1605 | typedef typename __make_1st_indices<_Tpls...>::__type __idx; |
| 1606 | typedef __tuple_concater<__ret, __idx, _Tpls...> __concater; |
| 1607 | return __concater::_S_do(std::forward<_Tpls>(__tpls)...); |
| 1608 | } |
| 1609 | |
| 1610 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
| 1611 | // 2301. Why is tie not constexpr? |
| 1612 | /// tie |
| 1613 | template<typename... _Elements> |
| 1614 | constexpr tuple<_Elements&...> |
| 1615 | tie(_Elements&... __args) noexcept |
| 1616 | { return tuple<_Elements&...>(__args...); } |
| 1617 | |
| 1618 | /// swap |
| 1619 | template<typename... _Elements> |
| 1620 | _GLIBCXX20_CONSTEXPR |
| 1621 | inline |
| 1622 | #if __cplusplus201402L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
| 1623 | // Constrained free swap overload, see p0185r1 |
| 1624 | typename enable_if<__and_<__is_swappable<_Elements>...>::value |
| 1625 | >::type |
| 1626 | #else |
| 1627 | void |
| 1628 | #endif |
| 1629 | swap(tuple<_Elements...>& __x, tuple<_Elements...>& __y) |
| 1630 | noexcept(noexcept(__x.swap(__y))) |
| 1631 | { __x.swap(__y); } |
| 1632 | |
| 1633 | #if __cplusplus201402L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
| 1634 | template<typename... _Elements> |
| 1635 | _GLIBCXX20_CONSTEXPR |
| 1636 | typename enable_if<!__and_<__is_swappable<_Elements>...>::value>::type |
| 1637 | swap(tuple<_Elements...>&, tuple<_Elements...>&) = delete; |
| 1638 | #endif |
| 1639 | |
| 1640 | // A class (and instance) which can be used in 'tie' when an element |
| 1641 | // of a tuple is not required. |
| 1642 | // _GLIBCXX14_CONSTEXPR |
| 1643 | // 2933. PR for LWG 2773 could be clearer |
| 1644 | struct _Swallow_assign |
| 1645 | { |
| 1646 | template<class _Tp> |
| 1647 | _GLIBCXX14_CONSTEXPRconstexpr const _Swallow_assign& |
| 1648 | operator=(const _Tp&) const |
| 1649 | { return *this; } |
| 1650 | }; |
| 1651 | |
| 1652 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
| 1653 | // 2773. Making std::ignore constexpr |
| 1654 | _GLIBCXX17_INLINE constexpr _Swallow_assign ignore{}; |
| 1655 | |
| 1656 | /// Partial specialization for tuples |
| 1657 | template<typename... _Types, typename _Alloc> |
| 1658 | struct uses_allocator<tuple<_Types...>, _Alloc> : true_type { }; |
| 1659 | |
| 1660 | // See stl_pair.h... |
| 1661 | /** "piecewise construction" using a tuple of arguments for each member. |
| 1662 | * |
| 1663 | * @param __first Arguments for the first member of the pair. |
| 1664 | * @param __second Arguments for the second member of the pair. |
| 1665 | * |
| 1666 | * The elements of each tuple will be used as the constructor arguments |
| 1667 | * for the data members of the pair. |
| 1668 | */ |
| 1669 | template<class _T1, class _T2> |
| 1670 | template<typename... _Args1, typename... _Args2> |
| 1671 | _GLIBCXX20_CONSTEXPR |
| 1672 | inline |
| 1673 | pair<_T1, _T2>:: |
| 1674 | pair(piecewise_construct_t, |
| 1675 | tuple<_Args1...> __first, tuple<_Args2...> __second) |
| 1676 | : pair(__first, __second, |
| 1677 | typename _Build_index_tuple<sizeof...(_Args1)>::__type(), |
| 1678 | typename _Build_index_tuple<sizeof...(_Args2)>::__type()) |
| 1679 | { } |
| 1680 | |
| 1681 | template<class _T1, class _T2> |
| 1682 | template<typename... _Args1, std::size_t... _Indexes1, |
| 1683 | typename... _Args2, std::size_t... _Indexes2> |
| 1684 | _GLIBCXX20_CONSTEXPR inline |
| 1685 | pair<_T1, _T2>:: |
| 1686 | pair(tuple<_Args1...>& __tuple1, tuple<_Args2...>& __tuple2, |
| 1687 | _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>) |
| 1688 | : first(std::forward<_Args1>(std::get<_Indexes1>(__tuple1))...), |
| 1689 | second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...) |
| 1690 | { } |
| 1691 | |
| 1692 | #if __cplusplus201402L >= 201703L |
| 1693 | |
| 1694 | // Unpack a std::tuple into a type trait and use its value. |
| 1695 | // For cv std::tuple<_Up> the result is _Trait<_Tp, cv _Up...>::value. |
| 1696 | // For cv std::tuple<_Up>& the result is _Trait<_Tp, cv _Up&...>::value. |
| 1697 | // Otherwise the result is false (because we don't know if std::get throws). |
| 1698 | template<template<typename...> class _Trait, typename _Tp, typename _Tuple> |
| 1699 | inline constexpr bool __unpack_std_tuple = false; |
| 1700 | |
| 1701 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
| 1702 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>> |
| 1703 | = _Trait<_Tp, _Up...>::value; |
| 1704 | |
| 1705 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
| 1706 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, tuple<_Up...>&> |
| 1707 | = _Trait<_Tp, _Up&...>::value; |
| 1708 | |
| 1709 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
| 1710 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>> |
| 1711 | = _Trait<_Tp, const _Up...>::value; |
| 1712 | |
| 1713 | template<template<typename...> class _Trait, typename _Tp, typename... _Up> |
| 1714 | inline constexpr bool __unpack_std_tuple<_Trait, _Tp, const tuple<_Up...>&> |
| 1715 | = _Trait<_Tp, const _Up&...>::value; |
| 1716 | |
| 1717 | # define __cpp_lib_apply 201603 |
| 1718 | |
| 1719 | template <typename _Fn, typename _Tuple, size_t... _Idx> |
| 1720 | constexpr decltype(auto) |
| 1721 | __apply_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Idx...>) |
| 1722 | { |
| 1723 | return std::__invoke(std::forward<_Fn>(__f), |
| 1724 | std::get<_Idx>(std::forward<_Tuple>(__t))...); |
| 1725 | } |
| 1726 | |
| 1727 | template <typename _Fn, typename _Tuple> |
| 1728 | constexpr decltype(auto) |
| 1729 | apply(_Fn&& __f, _Tuple&& __t) |
| 1730 | noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>) |
| 1731 | { |
| 1732 | using _Indices |
| 1733 | = make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>; |
| 1734 | return std::__apply_impl(std::forward<_Fn>(__f), |
| 1735 | std::forward<_Tuple>(__t), |
| 1736 | _Indices{}); |
| 1737 | } |
| 1738 | |
| 1739 | #define __cpp_lib_make_from_tuple 201606 |
| 1740 | |
| 1741 | template <typename _Tp, typename _Tuple, size_t... _Idx> |
| 1742 | constexpr _Tp |
| 1743 | __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) |
| 1744 | { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } |
| 1745 | |
| 1746 | template <typename _Tp, typename _Tuple> |
| 1747 | constexpr _Tp |
| 1748 | make_from_tuple(_Tuple&& __t) |
| 1749 | noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>) |
| 1750 | { |
| 1751 | return __make_from_tuple_impl<_Tp>( |
| 1752 | std::forward<_Tuple>(__t), |
| 1753 | make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{}); |
| 1754 | } |
| 1755 | #endif // C++17 |
| 1756 | |
| 1757 | /// @} |
| 1758 | |
| 1759 | _GLIBCXX_END_NAMESPACE_VERSION |
| 1760 | } // namespace std |
| 1761 | |
| 1762 | #endif // C++11 |
| 1763 | |
| 1764 | #endif // _GLIBCXX_TUPLE |
| 1 | //===- SVals.h - Abstract Values for Static Analysis ------------*- 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 SVal, Loc, and NonLoc, classes that represent |
| 10 | // abstract r-values for use with path-sensitive value tracking. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H |
| 15 | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H |
| 16 | |
| 17 | #include "clang/AST/Expr.h" |
| 18 | #include "clang/AST/Type.h" |
| 19 | #include "clang/Basic/LLVM.h" |
| 20 | #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" |
| 21 | #include "llvm/ADT/FoldingSet.h" |
| 22 | #include "llvm/ADT/ImmutableList.h" |
| 23 | #include "llvm/ADT/None.h" |
| 24 | #include "llvm/ADT/Optional.h" |
| 25 | #include "llvm/ADT/PointerUnion.h" |
| 26 | #include "llvm/Support/Casting.h" |
| 27 | #include <cassert> |
| 28 | #include <cstdint> |
| 29 | #include <utility> |
| 30 | |
| 31 | //==------------------------------------------------------------------------==// |
| 32 | // Base SVal types. |
| 33 | //==------------------------------------------------------------------------==// |
| 34 | |
| 35 | namespace clang { |
| 36 | |
| 37 | class CXXBaseSpecifier; |
| 38 | class DeclaratorDecl; |
| 39 | class FunctionDecl; |
| 40 | class LabelDecl; |
| 41 | |
| 42 | namespace ento { |
| 43 | |
| 44 | class BasicValueFactory; |
| 45 | class CompoundValData; |
| 46 | class LazyCompoundValData; |
| 47 | class MemRegion; |
| 48 | class PointerToMemberData; |
| 49 | class SValBuilder; |
| 50 | class TypedValueRegion; |
| 51 | |
| 52 | namespace nonloc { |
| 53 | |
| 54 | /// Sub-kinds for NonLoc values. |
| 55 | enum Kind { |
| 56 | #define NONLOC_SVAL(Id, Parent) Id ## Kind, |
| 57 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" |
| 58 | }; |
| 59 | |
| 60 | } // namespace nonloc |
| 61 | |
| 62 | namespace loc { |
| 63 | |
| 64 | /// Sub-kinds for Loc values. |
| 65 | enum Kind { |
| 66 | #define LOC_SVAL(Id, Parent) Id ## Kind, |
| 67 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" |
| 68 | }; |
| 69 | |
| 70 | } // namespace loc |
| 71 | |
| 72 | /// SVal - This represents a symbolic expression, which can be either |
| 73 | /// an L-value or an R-value. |
| 74 | /// |
| 75 | class SVal { |
| 76 | public: |
| 77 | enum BaseKind { |
| 78 | // The enumerators must be representable using 2 bits. |
| 79 | #define BASIC_SVAL(Id, Parent) Id ## Kind, |
| 80 | #define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind, |
| 81 | #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" |
| 82 | }; |
| 83 | enum { BaseBits = 2, BaseMask = 0b11 }; |
| 84 | |
| 85 | protected: |
| 86 | const void *Data = nullptr; |
| 87 | |
| 88 | /// The lowest 2 bits are a BaseKind (0 -- 3). |
| 89 | /// The higher bits are an unsigned "kind" value. |
| 90 | unsigned Kind = 0; |
| 91 | |
| 92 | explicit SVal(const void *d, bool isLoc, unsigned ValKind) |
| 93 | : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} |
| 94 | |
| 95 | explicit SVal(BaseKind k, const void *D = nullptr) : Data(D), Kind(k) {} |
| 96 | |
| 97 | public: |
| 98 | explicit SVal() = default; |
| 99 | |
| 100 | /// Convert to the specified SVal type, asserting that this SVal is of |
| 101 | /// the desired type. |
| 102 | template<typename T> |
| 103 | T castAs() const { |
| 104 | assert(T::isKind(*this))(static_cast <bool> (T::isKind(*this)) ? void (0) : __assert_fail ("T::isKind(*this)", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 104, __extension__ __PRETTY_FUNCTION__)); |
| 105 | return *static_cast<const T *>(this); |
| 106 | } |
| 107 | |
| 108 | /// Convert to the specified SVal type, returning None if this SVal is |
| 109 | /// not of the desired type. |
| 110 | template<typename T> |
| 111 | Optional<T> getAs() const { |
| 112 | if (!T::isKind(*this)) |
| 113 | return None; |
| 114 | return *static_cast<const T *>(this); |
| 115 | } |
| 116 | |
| 117 | unsigned getRawKind() const { return Kind; } |
| 118 | BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } |
| 119 | unsigned getSubKind() const { return Kind >> BaseBits; } |
| 120 | |
| 121 | // This method is required for using SVal in a FoldingSetNode. It |
| 122 | // extracts a unique signature for this SVal object. |
| 123 | void Profile(llvm::FoldingSetNodeID &ID) const { |
| 124 | ID.AddInteger((unsigned) getRawKind()); |
| 125 | ID.AddPointer(Data); |
| 126 | } |
| 127 | |
| 128 | bool operator==(const SVal &R) const { |
| 129 | return getRawKind() == R.getRawKind() && Data == R.Data; |
| 130 | } |
| 131 | |
| 132 | bool operator!=(const SVal &R) const { |
| 133 | return !(*this == R); |
| 134 | } |
| 135 | |
| 136 | bool isUnknown() const { |
| 137 | return getRawKind() == UnknownValKind; |
| 138 | } |
| 139 | |
| 140 | bool isUndef() const { |
| 141 | return getRawKind() == UndefinedValKind; |
| 142 | } |
| 143 | |
| 144 | bool isUnknownOrUndef() const { |
| 145 | return getRawKind() <= UnknownValKind; |
| 146 | } |
| 147 | |
| 148 | bool isValid() const { |
| 149 | return getRawKind() > UnknownValKind; |
| 150 | } |
| 151 | |
| 152 | bool isConstant() const; |
| 153 | |
| 154 | bool isConstant(int I) const; |
| 155 | |
| 156 | bool isZeroConstant() const; |
| 157 | |
| 158 | /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; |
| 159 | bool hasConjuredSymbol() const; |
| 160 | |
| 161 | /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a |
| 162 | /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. |
| 163 | /// Otherwise return 0. |
| 164 | const FunctionDecl *getAsFunctionDecl() const; |
| 165 | |
| 166 | /// If this SVal is a location and wraps a symbol, return that |
| 167 | /// SymbolRef. Otherwise return 0. |
| 168 | /// |
| 169 | /// Casts are ignored during lookup. |
| 170 | /// \param IncludeBaseRegions The boolean that controls whether the search |
| 171 | /// should continue to the base regions if the region is not symbolic. |
| 172 | SymbolRef getAsLocSymbol(bool IncludeBaseRegions = false) const; |
| 173 | |
| 174 | /// Get the symbol in the SVal or its base region. |
| 175 | SymbolRef getLocSymbolInBase() const; |
| 176 | |
| 177 | /// If this SVal wraps a symbol return that SymbolRef. |
| 178 | /// Otherwise, return 0. |
| 179 | /// |
| 180 | /// Casts are ignored during lookup. |
| 181 | /// \param IncludeBaseRegions The boolean that controls whether the search |
| 182 | /// should continue to the base regions if the region is not symbolic. |
| 183 | SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; |
| 184 | |
| 185 | const MemRegion *getAsRegion() const; |
| 186 | |
| 187 | /// printJson - Pretty-prints in JSON format. |
| 188 | void printJson(raw_ostream &Out, bool AddQuotes) const; |
| 189 | |
| 190 | void dumpToStream(raw_ostream &OS) const; |
| 191 | void dump() const; |
| 192 | |
| 193 | SymExpr::symbol_iterator symbol_begin() const { |
| 194 | const SymExpr *SE = getAsSymbol(/*IncludeBaseRegions=*/true); |
| 195 | if (SE) |
| 196 | return SE->symbol_begin(); |
| 197 | else |
| 198 | return SymExpr::symbol_iterator(); |
| 199 | } |
| 200 | |
| 201 | SymExpr::symbol_iterator symbol_end() const { |
| 202 | return SymExpr::symbol_end(); |
| 203 | } |
| 204 | |
| 205 | /// Try to get a reasonable type for the given value. |
| 206 | /// |
| 207 | /// \returns The best approximation of the value type or Null. |
| 208 | /// In theory, all symbolic values should be typed, but this function |
| 209 | /// is still a WIP and might have a few blind spots. |
| 210 | /// |
| 211 | /// \note This function should not be used when the user has access to the |
| 212 | /// bound expression AST node as well, since AST always has exact types. |
| 213 | /// |
| 214 | /// \note Loc values are interpreted as pointer rvalues for the purposes of |
| 215 | /// this method. |
| 216 | QualType getType(const ASTContext &) const; |
| 217 | }; |
| 218 | |
| 219 | inline raw_ostream &operator<<(raw_ostream &os, clang::ento::SVal V) { |
| 220 | V.dumpToStream(os); |
| 221 | return os; |
| 222 | } |
| 223 | |
| 224 | class UndefinedVal : public SVal { |
| 225 | public: |
| 226 | UndefinedVal() : SVal(UndefinedValKind) {} |
| 227 | |
| 228 | private: |
| 229 | friend class SVal; |
| 230 | |
| 231 | static bool isKind(const SVal& V) { |
| 232 | return V.getBaseKind() == UndefinedValKind; |
| 233 | } |
| 234 | }; |
| 235 | |
| 236 | class DefinedOrUnknownSVal : public SVal { |
| 237 | public: |
| 238 | // We want calling these methods to be a compiler error since they are |
| 239 | // tautologically false. |
| 240 | bool isUndef() const = delete; |
| 241 | bool isValid() const = delete; |
| 242 | |
| 243 | protected: |
| 244 | DefinedOrUnknownSVal() = default; |
| 245 | explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) |
| 246 | : SVal(d, isLoc, ValKind) {} |
| 247 | explicit DefinedOrUnknownSVal(BaseKind k, void *D = nullptr) : SVal(k, D) {} |
| 248 | |
| 249 | private: |
| 250 | friend class SVal; |
| 251 | |
| 252 | static bool isKind(const SVal& V) { |
| 253 | return !V.isUndef(); |
| 254 | } |
| 255 | }; |
| 256 | |
| 257 | class UnknownVal : public DefinedOrUnknownSVal { |
| 258 | public: |
| 259 | explicit UnknownVal() : DefinedOrUnknownSVal(UnknownValKind) {} |
| 260 | |
| 261 | private: |
| 262 | friend class SVal; |
| 263 | |
| 264 | static bool isKind(const SVal &V) { |
| 265 | return V.getBaseKind() == UnknownValKind; |
| 266 | } |
| 267 | }; |
| 268 | |
| 269 | class DefinedSVal : public DefinedOrUnknownSVal { |
| 270 | public: |
| 271 | // We want calling these methods to be a compiler error since they are |
| 272 | // tautologically true/false. |
| 273 | bool isUnknown() const = delete; |
| 274 | bool isUnknownOrUndef() const = delete; |
| 275 | bool isValid() const = delete; |
| 276 | |
| 277 | protected: |
| 278 | DefinedSVal() = default; |
| 279 | explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind) |
| 280 | : DefinedOrUnknownSVal(d, isLoc, ValKind) {} |
| 281 | |
| 282 | private: |
| 283 | friend class SVal; |
| 284 | |
| 285 | static bool isKind(const SVal& V) { |
| 286 | return !V.isUnknownOrUndef(); |
| 287 | } |
| 288 | }; |
| 289 | |
| 290 | /// Represents an SVal that is guaranteed to not be UnknownVal. |
| 291 | class KnownSVal : public SVal { |
| 292 | friend class SVal; |
| 293 | |
| 294 | KnownSVal() = default; |
| 295 | |
| 296 | static bool isKind(const SVal &V) { |
| 297 | return !V.isUnknown(); |
| 298 | } |
| 299 | |
| 300 | public: |
| 301 | KnownSVal(const DefinedSVal &V) : SVal(V) {} |
| 302 | KnownSVal(const UndefinedVal &V) : SVal(V) {} |
| 303 | }; |
| 304 | |
| 305 | class NonLoc : public DefinedSVal { |
| 306 | protected: |
| 307 | NonLoc() = default; |
| 308 | explicit NonLoc(unsigned SubKind, const void *d) |
| 309 | : DefinedSVal(d, false, SubKind) {} |
| 310 | |
| 311 | public: |
| 312 | void dumpToStream(raw_ostream &Out) const; |
| 313 | |
| 314 | static bool isCompoundType(QualType T) { |
| 315 | return T->isArrayType() || T->isRecordType() || |
| 316 | T->isAnyComplexType() || T->isVectorType(); |
| 317 | } |
| 318 | |
| 319 | private: |
| 320 | friend class SVal; |
| 321 | |
| 322 | static bool isKind(const SVal& V) { |
| 323 | return V.getBaseKind() == NonLocKind; |
| 324 | } |
| 325 | }; |
| 326 | |
| 327 | class Loc : public DefinedSVal { |
| 328 | protected: |
| 329 | Loc() = default; |
| 330 | explicit Loc(unsigned SubKind, const void *D) |
| 331 | : DefinedSVal(const_cast<void *>(D), true, SubKind) {} |
| 332 | |
| 333 | public: |
| 334 | void dumpToStream(raw_ostream &Out) const; |
| 335 | |
| 336 | static bool isLocType(QualType T) { |
| 337 | return T->isAnyPointerType() || T->isBlockPointerType() || |
| 338 | T->isReferenceType() || T->isNullPtrType(); |
| 339 | } |
| 340 | |
| 341 | private: |
| 342 | friend class SVal; |
| 343 | |
| 344 | static bool isKind(const SVal& V) { |
| 345 | return V.getBaseKind() == LocKind; |
| 346 | } |
| 347 | }; |
| 348 | |
| 349 | //==------------------------------------------------------------------------==// |
| 350 | // Subclasses of NonLoc. |
| 351 | //==------------------------------------------------------------------------==// |
| 352 | |
| 353 | namespace nonloc { |
| 354 | |
| 355 | /// Represents symbolic expression that isn't a location. |
| 356 | class SymbolVal : public NonLoc { |
| 357 | public: |
| 358 | SymbolVal() = delete; |
| 359 | SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) { |
| 360 | assert(sym)(static_cast <bool> (sym) ? void (0) : __assert_fail ("sym" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 360, __extension__ __PRETTY_FUNCTION__)); |
| 361 | assert(!Loc::isLocType(sym->getType()))(static_cast <bool> (!Loc::isLocType(sym->getType()) ) ? void (0) : __assert_fail ("!Loc::isLocType(sym->getType())" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 361, __extension__ __PRETTY_FUNCTION__)); |
| 362 | } |
| 363 | |
| 364 | SymbolRef getSymbol() const { |
| 365 | return (const SymExpr *) Data; |
| 366 | } |
| 367 | |
| 368 | bool isExpression() const { |
| 369 | return !isa<SymbolData>(getSymbol()); |
| 370 | } |
| 371 | |
| 372 | private: |
| 373 | friend class SVal; |
| 374 | |
| 375 | static bool isKind(const SVal& V) { |
| 376 | return V.getBaseKind() == NonLocKind && |
| 377 | V.getSubKind() == SymbolValKind; |
| 378 | } |
| 379 | |
| 380 | static bool isKind(const NonLoc& V) { |
| 381 | return V.getSubKind() == SymbolValKind; |
| 382 | } |
| 383 | }; |
| 384 | |
| 385 | /// Value representing integer constant. |
| 386 | class ConcreteInt : public NonLoc { |
| 387 | public: |
| 388 | explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} |
| 389 | |
| 390 | const llvm::APSInt& getValue() const { |
| 391 | return *static_cast<const llvm::APSInt *>(Data); |
| 392 | } |
| 393 | |
| 394 | // Transfer functions for binary/unary operations on ConcreteInts. |
| 395 | SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, |
| 396 | const ConcreteInt& R) const; |
| 397 | |
| 398 | ConcreteInt evalComplement(SValBuilder &svalBuilder) const; |
| 399 | |
| 400 | ConcreteInt evalMinus(SValBuilder &svalBuilder) const; |
| 401 | |
| 402 | private: |
| 403 | friend class SVal; |
| 404 | |
| 405 | ConcreteInt() = default; |
| 406 | |
| 407 | static bool isKind(const SVal& V) { |
| 408 | return V.getBaseKind() == NonLocKind && |
| 409 | V.getSubKind() == ConcreteIntKind; |
| 410 | } |
| 411 | |
| 412 | static bool isKind(const NonLoc& V) { |
| 413 | return V.getSubKind() == ConcreteIntKind; |
| 414 | } |
| 415 | }; |
| 416 | |
| 417 | class LocAsInteger : public NonLoc { |
| 418 | friend class ento::SValBuilder; |
| 419 | |
| 420 | explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data) |
| 421 | : NonLoc(LocAsIntegerKind, &data) { |
| 422 | // We do not need to represent loc::ConcreteInt as LocAsInteger, |
| 423 | // as it'd collapse into a nonloc::ConcreteInt instead. |
| 424 | assert(data.first.getBaseKind() == LocKind &&(static_cast <bool> (data.first.getBaseKind() == LocKind && (data.first.getSubKind() == loc::MemRegionValKind || data.first.getSubKind() == loc::GotoLabelKind)) ? void (0 ) : __assert_fail ("data.first.getBaseKind() == LocKind && (data.first.getSubKind() == loc::MemRegionValKind || data.first.getSubKind() == loc::GotoLabelKind)" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 426, __extension__ __PRETTY_FUNCTION__)) |
| 425 | (data.first.getSubKind() == loc::MemRegionValKind ||(static_cast <bool> (data.first.getBaseKind() == LocKind && (data.first.getSubKind() == loc::MemRegionValKind || data.first.getSubKind() == loc::GotoLabelKind)) ? void (0 ) : __assert_fail ("data.first.getBaseKind() == LocKind && (data.first.getSubKind() == loc::MemRegionValKind || data.first.getSubKind() == loc::GotoLabelKind)" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 426, __extension__ __PRETTY_FUNCTION__)) |
| 426 | data.first.getSubKind() == loc::GotoLabelKind))(static_cast <bool> (data.first.getBaseKind() == LocKind && (data.first.getSubKind() == loc::MemRegionValKind || data.first.getSubKind() == loc::GotoLabelKind)) ? void (0 ) : __assert_fail ("data.first.getBaseKind() == LocKind && (data.first.getSubKind() == loc::MemRegionValKind || data.first.getSubKind() == loc::GotoLabelKind)" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 426, __extension__ __PRETTY_FUNCTION__)); |
| 427 | } |
| 428 | |
| 429 | public: |
| 430 | Loc getLoc() const { |
| 431 | const std::pair<SVal, uintptr_t> *D = |
| 432 | static_cast<const std::pair<SVal, uintptr_t> *>(Data); |
| 433 | return D->first.castAs<Loc>(); |
| 434 | } |
| 435 | |
| 436 | Loc getPersistentLoc() const { |
| 437 | const std::pair<SVal, uintptr_t> *D = |
| 438 | static_cast<const std::pair<SVal, uintptr_t> *>(Data); |
| 439 | const SVal& V = D->first; |
| 440 | return V.castAs<Loc>(); |
| 441 | } |
| 442 | |
| 443 | unsigned getNumBits() const { |
| 444 | const std::pair<SVal, uintptr_t> *D = |
| 445 | static_cast<const std::pair<SVal, uintptr_t> *>(Data); |
| 446 | return D->second; |
| 447 | } |
| 448 | |
| 449 | private: |
| 450 | friend class SVal; |
| 451 | |
| 452 | LocAsInteger() = default; |
| 453 | |
| 454 | static bool isKind(const SVal& V) { |
| 455 | return V.getBaseKind() == NonLocKind && |
| 456 | V.getSubKind() == LocAsIntegerKind; |
| 457 | } |
| 458 | |
| 459 | static bool isKind(const NonLoc& V) { |
| 460 | return V.getSubKind() == LocAsIntegerKind; |
| 461 | } |
| 462 | }; |
| 463 | |
| 464 | class CompoundVal : public NonLoc { |
| 465 | friend class ento::SValBuilder; |
| 466 | |
| 467 | explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} |
| 468 | |
| 469 | public: |
| 470 | const CompoundValData* getValue() const { |
| 471 | return static_cast<const CompoundValData *>(Data); |
| 472 | } |
| 473 | |
| 474 | using iterator = llvm::ImmutableList<SVal>::iterator; |
| 475 | |
| 476 | iterator begin() const; |
| 477 | iterator end() const; |
| 478 | |
| 479 | private: |
| 480 | friend class SVal; |
| 481 | |
| 482 | CompoundVal() = default; |
| 483 | |
| 484 | static bool isKind(const SVal& V) { |
| 485 | return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind; |
| 486 | } |
| 487 | |
| 488 | static bool isKind(const NonLoc& V) { |
| 489 | return V.getSubKind() == CompoundValKind; |
| 490 | } |
| 491 | }; |
| 492 | |
| 493 | class LazyCompoundVal : public NonLoc { |
| 494 | friend class ento::SValBuilder; |
| 495 | |
| 496 | explicit LazyCompoundVal(const LazyCompoundValData *D) |
| 497 | : NonLoc(LazyCompoundValKind, D) {} |
| 498 | |
| 499 | public: |
| 500 | const LazyCompoundValData *getCVData() const { |
| 501 | return static_cast<const LazyCompoundValData *>(Data); |
| 502 | } |
| 503 | |
| 504 | const void *getStore() const; |
| 505 | const TypedValueRegion *getRegion() const; |
| 506 | |
| 507 | private: |
| 508 | friend class SVal; |
| 509 | |
| 510 | LazyCompoundVal() = default; |
| 511 | |
| 512 | static bool isKind(const SVal& V) { |
| 513 | return V.getBaseKind() == NonLocKind && |
| 514 | V.getSubKind() == LazyCompoundValKind; |
| 515 | } |
| 516 | |
| 517 | static bool isKind(const NonLoc& V) { |
| 518 | return V.getSubKind() == LazyCompoundValKind; |
| 519 | } |
| 520 | }; |
| 521 | |
| 522 | /// Value representing pointer-to-member. |
| 523 | /// |
| 524 | /// This value is qualified as NonLoc because neither loading nor storing |
| 525 | /// operations are applied to it. Instead, the analyzer uses the L-value coming |
| 526 | /// from pointer-to-member applied to an object. |
| 527 | /// This SVal is represented by a NamedDecl which can be a member function |
| 528 | /// pointer or a member data pointer and an optional list of CXXBaseSpecifiers. |
| 529 | /// This list is required to accumulate the pointer-to-member cast history to |
| 530 | /// figure out the correct subobject field. In particular, implicit casts grow |
| 531 | /// this list and explicit casts like static_cast shrink this list. |
| 532 | class PointerToMember : public NonLoc { |
| 533 | friend class ento::SValBuilder; |
| 534 | |
| 535 | public: |
| 536 | using PTMDataType = |
| 537 | llvm::PointerUnion<const NamedDecl *, const PointerToMemberData *>; |
| 538 | |
| 539 | const PTMDataType getPTMData() const { |
| 540 | return PTMDataType::getFromOpaqueValue(const_cast<void *>(Data)); |
| 541 | } |
| 542 | |
| 543 | bool isNullMemberPointer() const; |
| 544 | |
| 545 | const NamedDecl *getDecl() const; |
| 546 | |
| 547 | template<typename AdjustedDecl> |
| 548 | const AdjustedDecl *getDeclAs() const { |
| 549 | return dyn_cast_or_null<AdjustedDecl>(getDecl()); |
| 550 | } |
| 551 | |
| 552 | using iterator = llvm::ImmutableList<const CXXBaseSpecifier *>::iterator; |
| 553 | |
| 554 | iterator begin() const; |
| 555 | iterator end() const; |
| 556 | |
| 557 | private: |
| 558 | friend class SVal; |
| 559 | |
| 560 | PointerToMember() = default; |
| 561 | explicit PointerToMember(const PTMDataType D) |
| 562 | : NonLoc(PointerToMemberKind, D.getOpaqueValue()) {} |
| 563 | |
| 564 | static bool isKind(const SVal& V) { |
| 565 | return V.getBaseKind() == NonLocKind && |
| 566 | V.getSubKind() == PointerToMemberKind; |
| 567 | } |
| 568 | |
| 569 | static bool isKind(const NonLoc& V) { |
| 570 | return V.getSubKind() == PointerToMemberKind; |
| 571 | } |
| 572 | }; |
| 573 | |
| 574 | } // namespace nonloc |
| 575 | |
| 576 | //==------------------------------------------------------------------------==// |
| 577 | // Subclasses of Loc. |
| 578 | //==------------------------------------------------------------------------==// |
| 579 | |
| 580 | namespace loc { |
| 581 | |
| 582 | class GotoLabel : public Loc { |
| 583 | public: |
| 584 | explicit GotoLabel(const LabelDecl *Label) : Loc(GotoLabelKind, Label) { |
| 585 | assert(Label)(static_cast <bool> (Label) ? void (0) : __assert_fail ( "Label", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 585, __extension__ __PRETTY_FUNCTION__)); |
| 586 | } |
| 587 | |
| 588 | const LabelDecl *getLabel() const { |
| 589 | return static_cast<const LabelDecl *>(Data); |
| 590 | } |
| 591 | |
| 592 | private: |
| 593 | friend class SVal; |
| 594 | |
| 595 | GotoLabel() = default; |
| 596 | |
| 597 | static bool isKind(const SVal& V) { |
| 598 | return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind; |
| 599 | } |
| 600 | |
| 601 | static bool isKind(const Loc& V) { |
| 602 | return V.getSubKind() == GotoLabelKind; |
| 603 | } |
| 604 | }; |
| 605 | |
| 606 | class MemRegionVal : public Loc { |
| 607 | public: |
| 608 | explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionValKind, r) { |
| 609 | assert(r)(static_cast <bool> (r) ? void (0) : __assert_fail ("r" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h" , 609, __extension__ __PRETTY_FUNCTION__)); |
| 610 | } |
| 611 | |
| 612 | /// Get the underlining region. |
| 613 | const MemRegion *getRegion() const { |
| 614 | return static_cast<const MemRegion *>(Data); |
| 615 | } |
| 616 | |
| 617 | /// Get the underlining region and strip casts. |
| 618 | const MemRegion* stripCasts(bool StripBaseCasts = true) const; |
| 619 | |
| 620 | template <typename REGION> |
| 621 | const REGION* getRegionAs() const { |
| 622 | return dyn_cast<REGION>(getRegion()); |
| 623 | } |
| 624 | |
| 625 | bool operator==(const MemRegionVal &R) const { |
| 626 | return getRegion() == R.getRegion(); |
| 627 | } |
| 628 | |
| 629 | bool operator!=(const MemRegionVal &R) const { |
| 630 | return getRegion() != R.getRegion(); |
| 631 | } |
| 632 | |
| 633 | private: |
| 634 | friend class SVal; |
| 635 | |
| 636 | MemRegionVal() = default; |
| 637 | |
| 638 | static bool isKind(const SVal& V) { |
| 639 | return V.getBaseKind() == LocKind && |
| 640 | V.getSubKind() == MemRegionValKind; |
| 641 | } |
| 642 | |
| 643 | static bool isKind(const Loc& V) { |
| 644 | return V.getSubKind() == MemRegionValKind; |
| 645 | } |
| 646 | }; |
| 647 | |
| 648 | class ConcreteInt : public Loc { |
| 649 | public: |
| 650 | explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} |
| 651 | |
| 652 | const llvm::APSInt &getValue() const { |
| 653 | return *static_cast<const llvm::APSInt *>(Data); |
| 654 | } |
| 655 | |
| 656 | // Transfer functions for binary/unary operations on ConcreteInts. |
| 657 | SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, |
| 658 | const ConcreteInt& R) const; |
| 659 | |
| 660 | private: |
| 661 | friend class SVal; |
| 662 | |
| 663 | ConcreteInt() = default; |
| 664 | |
| 665 | static bool isKind(const SVal& V) { |
| 666 | return V.getBaseKind() == LocKind && |
| 667 | V.getSubKind() == ConcreteIntKind; |
| 668 | } |
| 669 | |
| 670 | static bool isKind(const Loc& V) { |
| 671 | return V.getSubKind() == ConcreteIntKind; |
| 672 | } |
| 673 | }; |
| 674 | |
| 675 | } // namespace loc |
| 676 | |
| 677 | } // namespace ento |
| 678 | |
| 679 | } // namespace clang |
| 680 | |
| 681 | #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SVALS_H |
| 1 | //== ProgramState.h - Path-sensitive "State" for tracking values -*- 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 the state of the program along the analysisa path. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H |
| 14 | #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_PROGRAMSTATE_H |
| 15 | |
| 16 | #include "clang/Basic/LLVM.h" |
| 17 | #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" |
| 18 | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" |
| 19 | #include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" |
| 20 | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" |
| 21 | #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" |
| 22 | #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" |
| 23 | #include "llvm/ADT/FoldingSet.h" |
| 24 | #include "llvm/ADT/ImmutableMap.h" |
| 25 | #include "llvm/Support/Allocator.h" |
| 26 | #include <utility> |
| 27 | |
| 28 | namespace llvm { |
| 29 | class APSInt; |
| 30 | } |
| 31 | |
| 32 | namespace clang { |
| 33 | class ASTContext; |
| 34 | |
| 35 | namespace ento { |
| 36 | |
| 37 | class AnalysisManager; |
| 38 | class CallEvent; |
| 39 | class CallEventManager; |
| 40 | |
| 41 | typedef std::unique_ptr<ConstraintManager>(*ConstraintManagerCreator)( |
| 42 | ProgramStateManager &, ExprEngine *); |
| 43 | typedef std::unique_ptr<StoreManager>(*StoreManagerCreator)( |
| 44 | ProgramStateManager &); |
| 45 | |
| 46 | //===----------------------------------------------------------------------===// |
| 47 | // ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. |
| 48 | //===----------------------------------------------------------------------===// |
| 49 | |
| 50 | template <typename T> struct ProgramStatePartialTrait; |
| 51 | |
| 52 | template <typename T> struct ProgramStateTrait { |
| 53 | typedef typename T::data_type data_type; |
| 54 | static inline void *MakeVoidPtr(data_type D) { return (void*) D; } |
| 55 | static inline data_type MakeData(void *const* P) { |
| 56 | return P ? (data_type) *P : (data_type) 0; |
| 57 | } |
| 58 | }; |
| 59 | |
| 60 | /// \class ProgramState |
| 61 | /// ProgramState - This class encapsulates: |
| 62 | /// |
| 63 | /// 1. A mapping from expressions to values (Environment) |
| 64 | /// 2. A mapping from locations to values (Store) |
| 65 | /// 3. Constraints on symbolic values (GenericDataMap) |
| 66 | /// |
| 67 | /// Together these represent the "abstract state" of a program. |
| 68 | /// |
| 69 | /// ProgramState is intended to be used as a functional object; that is, |
| 70 | /// once it is created and made "persistent" in a FoldingSet, its |
| 71 | /// values will never change. |
| 72 | class ProgramState : public llvm::FoldingSetNode { |
| 73 | public: |
| 74 | typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; |
| 75 | typedef llvm::ImmutableMap<void*, void*> GenericDataMap; |
| 76 | |
| 77 | private: |
| 78 | void operator=(const ProgramState& R) = delete; |
| 79 | |
| 80 | friend class ProgramStateManager; |
| 81 | friend class ExplodedGraph; |
| 82 | friend class ExplodedNode; |
| 83 | |
| 84 | ProgramStateManager *stateMgr; |
| 85 | Environment Env; // Maps a Stmt to its current SVal. |
| 86 | Store store; // Maps a location to its current value. |
| 87 | GenericDataMap GDM; // Custom data stored by a client of this class. |
| 88 | unsigned refCount; |
| 89 | |
| 90 | /// makeWithStore - Return a ProgramState with the same values as the current |
| 91 | /// state with the exception of using the specified Store. |
| 92 | ProgramStateRef makeWithStore(const StoreRef &store) const; |
| 93 | |
| 94 | void setStore(const StoreRef &storeRef); |
| 95 | |
| 96 | public: |
| 97 | /// This ctor is used when creating the first ProgramState object. |
| 98 | ProgramState(ProgramStateManager *mgr, const Environment& env, |
| 99 | StoreRef st, GenericDataMap gdm); |
| 100 | |
| 101 | /// Copy ctor - We must explicitly define this or else the "Next" ptr |
| 102 | /// in FoldingSetNode will also get copied. |
| 103 | ProgramState(const ProgramState &RHS); |
| 104 | |
| 105 | ~ProgramState(); |
| 106 | |
| 107 | int64_t getID() const; |
| 108 | |
| 109 | /// Return the ProgramStateManager associated with this state. |
| 110 | ProgramStateManager &getStateManager() const { |
| 111 | return *stateMgr; |
| 112 | } |
| 113 | |
| 114 | AnalysisManager &getAnalysisManager() const; |
| 115 | |
| 116 | /// Return the ConstraintManager. |
| 117 | ConstraintManager &getConstraintManager() const; |
| 118 | |
| 119 | /// getEnvironment - Return the environment associated with this state. |
| 120 | /// The environment is the mapping from expressions to values. |
| 121 | const Environment& getEnvironment() const { return Env; } |
| 122 | |
| 123 | /// Return the store associated with this state. The store |
| 124 | /// is a mapping from locations to values. |
| 125 | Store getStore() const { return store; } |
| 126 | |
| 127 | |
| 128 | /// getGDM - Return the generic data map associated with this state. |
| 129 | GenericDataMap getGDM() const { return GDM; } |
| 130 | |
| 131 | void setGDM(GenericDataMap gdm) { GDM = gdm; } |
| 132 | |
| 133 | /// Profile - Profile the contents of a ProgramState object for use in a |
| 134 | /// FoldingSet. Two ProgramState objects are considered equal if they |
| 135 | /// have the same Environment, Store, and GenericDataMap. |
| 136 | static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) { |
| 137 | V->Env.Profile(ID); |
| 138 | ID.AddPointer(V->store); |
| 139 | V->GDM.Profile(ID); |
| 140 | } |
| 141 | |
| 142 | /// Profile - Used to profile the contents of this object for inclusion |
| 143 | /// in a FoldingSet. |
| 144 | void Profile(llvm::FoldingSetNodeID& ID) const { |
| 145 | Profile(ID, this); |
| 146 | } |
| 147 | |
| 148 | BasicValueFactory &getBasicVals() const; |
| 149 | SymbolManager &getSymbolManager() const; |
| 150 | |
| 151 | //==---------------------------------------------------------------------==// |
| 152 | // Constraints on values. |
| 153 | //==---------------------------------------------------------------------==// |
| 154 | // |
| 155 | // Each ProgramState records constraints on symbolic values. These constraints |
| 156 | // are managed using the ConstraintManager associated with a ProgramStateManager. |
| 157 | // As constraints gradually accrue on symbolic values, added constraints |
| 158 | // may conflict and indicate that a state is infeasible (as no real values |
| 159 | // could satisfy all the constraints). This is the principal mechanism |
| 160 | // for modeling path-sensitivity in ExprEngine/ProgramState. |
| 161 | // |
| 162 | // Various "assume" methods form the interface for adding constraints to |
| 163 | // symbolic values. A call to 'assume' indicates an assumption being placed |
| 164 | // on one or symbolic values. 'assume' methods take the following inputs: |
| 165 | // |
| 166 | // (1) A ProgramState object representing the current state. |
| 167 | // |
| 168 | // (2) The assumed constraint (which is specific to a given "assume" method). |
| 169 | // |
| 170 | // (3) A binary value "Assumption" that indicates whether the constraint is |
| 171 | // assumed to be true or false. |
| 172 | // |
| 173 | // The output of "assume*" is a new ProgramState object with the added constraints. |
| 174 | // If no new state is feasible, NULL is returned. |
| 175 | // |
| 176 | |
| 177 | /// Assumes that the value of \p cond is zero (if \p assumption is "false") |
| 178 | /// or non-zero (if \p assumption is "true"). |
| 179 | /// |
| 180 | /// This returns a new state with the added constraint on \p cond. |
| 181 | /// If no new state is feasible, NULL is returned. |
| 182 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef assume(DefinedOrUnknownSVal cond, |
| 183 | bool assumption) const; |
| 184 | |
| 185 | /// Assumes both "true" and "false" for \p cond, and returns both |
| 186 | /// corresponding states (respectively). |
| 187 | /// |
| 188 | /// This is more efficient than calling assume() twice. Note that one (but not |
| 189 | /// both) of the returned states may be NULL. |
| 190 | LLVM_NODISCARD[[clang::warn_unused_result]] std::pair<ProgramStateRef, ProgramStateRef> |
| 191 | assume(DefinedOrUnknownSVal cond) const; |
| 192 | |
| 193 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 194 | assumeInBound(DefinedOrUnknownSVal idx, DefinedOrUnknownSVal upperBound, |
| 195 | bool assumption, QualType IndexType = QualType()) const; |
| 196 | |
| 197 | /// Assumes that the value of \p Val is bounded with [\p From; \p To] |
| 198 | /// (if \p assumption is "true") or it is fully out of this range |
| 199 | /// (if \p assumption is "false"). |
| 200 | /// |
| 201 | /// This returns a new state with the added constraint on \p cond. |
| 202 | /// If no new state is feasible, NULL is returned. |
| 203 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef assumeInclusiveRange(DefinedOrUnknownSVal Val, |
| 204 | const llvm::APSInt &From, |
| 205 | const llvm::APSInt &To, |
| 206 | bool assumption) const; |
| 207 | |
| 208 | /// Assumes given range both "true" and "false" for \p Val, and returns both |
| 209 | /// corresponding states (respectively). |
| 210 | /// |
| 211 | /// This is more efficient than calling assume() twice. Note that one (but not |
| 212 | /// both) of the returned states may be NULL. |
| 213 | LLVM_NODISCARD[[clang::warn_unused_result]] std::pair<ProgramStateRef, ProgramStateRef> |
| 214 | assumeInclusiveRange(DefinedOrUnknownSVal Val, const llvm::APSInt &From, |
| 215 | const llvm::APSInt &To) const; |
| 216 | |
| 217 | /// Check if the given SVal is not constrained to zero and is not |
| 218 | /// a zero constant. |
| 219 | ConditionTruthVal isNonNull(SVal V) const; |
| 220 | |
| 221 | /// Check if the given SVal is constrained to zero or is a zero |
| 222 | /// constant. |
| 223 | ConditionTruthVal isNull(SVal V) const; |
| 224 | |
| 225 | /// \return Whether values \p Lhs and \p Rhs are equal. |
| 226 | ConditionTruthVal areEqual(SVal Lhs, SVal Rhs) const; |
| 227 | |
| 228 | /// Utility method for getting regions. |
| 229 | const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; |
| 230 | |
| 231 | //==---------------------------------------------------------------------==// |
| 232 | // Binding and retrieving values to/from the environment and symbolic store. |
| 233 | //==---------------------------------------------------------------------==// |
| 234 | |
| 235 | /// Create a new state by binding the value 'V' to the statement 'S' in the |
| 236 | /// state's environment. |
| 237 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef BindExpr(const Stmt *S, |
| 238 | const LocationContext *LCtx, SVal V, |
| 239 | bool Invalidate = true) const; |
| 240 | |
| 241 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef bindLoc(Loc location, SVal V, |
| 242 | const LocationContext *LCtx, |
| 243 | bool notifyChanges = true) const; |
| 244 | |
| 245 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef bindLoc(SVal location, SVal V, |
| 246 | const LocationContext *LCtx) const; |
| 247 | |
| 248 | /// Initializes the region of memory represented by \p loc with an initial |
| 249 | /// value. Once initialized, all values loaded from any sub-regions of that |
| 250 | /// region will be equal to \p V, unless overwritten later by the program. |
| 251 | /// This method should not be used on regions that are already initialized. |
| 252 | /// If you need to indicate that memory contents have suddenly become unknown |
| 253 | /// within a certain region of memory, consider invalidateRegions(). |
| 254 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 255 | bindDefaultInitial(SVal loc, SVal V, const LocationContext *LCtx) const; |
| 256 | |
| 257 | /// Performs C++ zero-initialization procedure on the region of memory |
| 258 | /// represented by \p loc. |
| 259 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 260 | bindDefaultZero(SVal loc, const LocationContext *LCtx) const; |
| 261 | |
| 262 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef killBinding(Loc LV) const; |
| 263 | |
| 264 | /// Returns the state with bindings for the given regions |
| 265 | /// cleared from the store. |
| 266 | /// |
| 267 | /// Optionally invalidates global regions as well. |
| 268 | /// |
| 269 | /// \param Regions the set of regions to be invalidated. |
| 270 | /// \param E the expression that caused the invalidation. |
| 271 | /// \param BlockCount The number of times the current basic block has been |
| 272 | // visited. |
| 273 | /// \param CausesPointerEscape the flag is set to true when |
| 274 | /// the invalidation entails escape of a symbol (representing a |
| 275 | /// pointer). For example, due to it being passed as an argument in a |
| 276 | /// call. |
| 277 | /// \param IS the set of invalidated symbols. |
| 278 | /// \param Call if non-null, the invalidated regions represent parameters to |
| 279 | /// the call and should be considered directly invalidated. |
| 280 | /// \param ITraits information about special handling for a particular |
| 281 | /// region/symbol. |
| 282 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 283 | invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E, |
| 284 | unsigned BlockCount, const LocationContext *LCtx, |
| 285 | bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, |
| 286 | const CallEvent *Call = nullptr, |
| 287 | RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; |
| 288 | |
| 289 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 290 | invalidateRegions(ArrayRef<SVal> Regions, const Expr *E, |
| 291 | unsigned BlockCount, const LocationContext *LCtx, |
| 292 | bool CausesPointerEscape, InvalidatedSymbols *IS = nullptr, |
| 293 | const CallEvent *Call = nullptr, |
| 294 | RegionAndSymbolInvalidationTraits *ITraits = nullptr) const; |
| 295 | |
| 296 | /// enterStackFrame - Returns the state for entry to the given stack frame, |
| 297 | /// preserving the current state. |
| 298 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef enterStackFrame( |
| 299 | const CallEvent &Call, const StackFrameContext *CalleeCtx) const; |
| 300 | |
| 301 | /// Return the value of 'self' if available in the given context. |
| 302 | SVal getSelfSVal(const LocationContext *LC) const; |
| 303 | |
| 304 | /// Get the lvalue for a base class object reference. |
| 305 | Loc getLValue(const CXXBaseSpecifier &BaseSpec, const SubRegion *Super) const; |
| 306 | |
| 307 | /// Get the lvalue for a base class object reference. |
| 308 | Loc getLValue(const CXXRecordDecl *BaseClass, const SubRegion *Super, |
| 309 | bool IsVirtual) const; |
| 310 | |
| 311 | /// Get the lvalue for a parameter. |
| 312 | Loc getLValue(const Expr *Call, unsigned Index, |
| 313 | const LocationContext *LC) const; |
| 314 | |
| 315 | /// Get the lvalue for a variable reference. |
| 316 | Loc getLValue(const VarDecl *D, const LocationContext *LC) const; |
| 317 | |
| 318 | Loc getLValue(const CompoundLiteralExpr *literal, |
| 319 | const LocationContext *LC) const; |
| 320 | |
| 321 | /// Get the lvalue for an ivar reference. |
| 322 | SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; |
| 323 | |
| 324 | /// Get the lvalue for a field reference. |
| 325 | SVal getLValue(const FieldDecl *decl, SVal Base) const; |
| 326 | |
| 327 | /// Get the lvalue for an indirect field reference. |
| 328 | SVal getLValue(const IndirectFieldDecl *decl, SVal Base) const; |
| 329 | |
| 330 | /// Get the lvalue for an array index. |
| 331 | SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; |
| 332 | |
| 333 | /// Returns the SVal bound to the statement 'S' in the state's environment. |
| 334 | SVal getSVal(const Stmt *S, const LocationContext *LCtx) const; |
| 335 | |
| 336 | SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const; |
| 337 | |
| 338 | /// Return the value bound to the specified location. |
| 339 | /// Returns UnknownVal() if none found. |
| 340 | SVal getSVal(Loc LV, QualType T = QualType()) const; |
| 341 | |
| 342 | /// Returns the "raw" SVal bound to LV before any value simplfication. |
| 343 | SVal getRawSVal(Loc LV, QualType T= QualType()) const; |
| 344 | |
| 345 | /// Return the value bound to the specified location. |
| 346 | /// Returns UnknownVal() if none found. |
| 347 | SVal getSVal(const MemRegion* R, QualType T = QualType()) const; |
| 348 | |
| 349 | /// Return the value bound to the specified location, assuming |
| 350 | /// that the value is a scalar integer or an enumeration or a pointer. |
| 351 | /// Returns UnknownVal() if none found or the region is not known to hold |
| 352 | /// a value of such type. |
| 353 | SVal getSValAsScalarOrLoc(const MemRegion *R) const; |
| 354 | |
| 355 | using region_iterator = const MemRegion **; |
| 356 | |
| 357 | /// Visits the symbols reachable from the given SVal using the provided |
| 358 | /// SymbolVisitor. |
| 359 | /// |
| 360 | /// This is a convenience API. Consider using ScanReachableSymbols class |
| 361 | /// directly when making multiple scans on the same state with the same |
| 362 | /// visitor to avoid repeated initialization cost. |
| 363 | /// \sa ScanReachableSymbols |
| 364 | bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; |
| 365 | |
| 366 | /// Visits the symbols reachable from the regions in the given |
| 367 | /// MemRegions range using the provided SymbolVisitor. |
| 368 | bool scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable, |
| 369 | SymbolVisitor &visitor) const; |
| 370 | |
| 371 | template <typename CB> CB scanReachableSymbols(SVal val) const; |
| 372 | template <typename CB> CB |
| 373 | scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable) const; |
| 374 | |
| 375 | //==---------------------------------------------------------------------==// |
| 376 | // Accessing the Generic Data Map (GDM). |
| 377 | //==---------------------------------------------------------------------==// |
| 378 | |
| 379 | void *const* FindGDM(void *K) const; |
| 380 | |
| 381 | template <typename T> |
| 382 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 383 | add(typename ProgramStateTrait<T>::key_type K) const; |
| 384 | |
| 385 | template <typename T> |
| 386 | typename ProgramStateTrait<T>::data_type |
| 387 | get() const { |
| 388 | return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex())); |
| 389 | } |
| 390 | |
| 391 | template<typename T> |
| 392 | typename ProgramStateTrait<T>::lookup_type |
| 393 | get(typename ProgramStateTrait<T>::key_type key) const { |
| 394 | void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); |
| 395 | return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key); |
| 396 | } |
| 397 | |
| 398 | template <typename T> |
| 399 | typename ProgramStateTrait<T>::context_type get_context() const; |
| 400 | |
| 401 | template <typename T> |
| 402 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 403 | remove(typename ProgramStateTrait<T>::key_type K) const; |
| 404 | |
| 405 | template <typename T> |
| 406 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 407 | remove(typename ProgramStateTrait<T>::key_type K, |
| 408 | typename ProgramStateTrait<T>::context_type C) const; |
| 409 | |
| 410 | template <typename T> LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef remove() const; |
| 411 | |
| 412 | template <typename T> |
| 413 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 414 | set(typename ProgramStateTrait<T>::data_type D) const; |
| 415 | |
| 416 | template <typename T> |
| 417 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 418 | set(typename ProgramStateTrait<T>::key_type K, |
| 419 | typename ProgramStateTrait<T>::value_type E) const; |
| 420 | |
| 421 | template <typename T> |
| 422 | LLVM_NODISCARD[[clang::warn_unused_result]] ProgramStateRef |
| 423 | set(typename ProgramStateTrait<T>::key_type K, |
| 424 | typename ProgramStateTrait<T>::value_type E, |
| 425 | typename ProgramStateTrait<T>::context_type C) const; |
| 426 | |
| 427 | template<typename T> |
| 428 | bool contains(typename ProgramStateTrait<T>::key_type key) const { |
| 429 | void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); |
| 430 | return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key); |
| 431 | } |
| 432 | |
| 433 | // Pretty-printing. |
| 434 | void printJson(raw_ostream &Out, const LocationContext *LCtx = nullptr, |
| 435 | const char *NL = "\n", unsigned int Space = 0, |
| 436 | bool IsDot = false) const; |
| 437 | |
| 438 | void printDOT(raw_ostream &Out, const LocationContext *LCtx = nullptr, |
| 439 | unsigned int Space = 0) const; |
| 440 | |
| 441 | void dump() const; |
| 442 | |
| 443 | private: |
| 444 | friend void ProgramStateRetain(const ProgramState *state); |
| 445 | friend void ProgramStateRelease(const ProgramState *state); |
| 446 | |
| 447 | /// \sa invalidateValues() |
| 448 | /// \sa invalidateRegions() |
| 449 | ProgramStateRef |
| 450 | invalidateRegionsImpl(ArrayRef<SVal> Values, |
| 451 | const Expr *E, unsigned BlockCount, |
| 452 | const LocationContext *LCtx, |
| 453 | bool ResultsInSymbolEscape, |
| 454 | InvalidatedSymbols *IS, |
| 455 | RegionAndSymbolInvalidationTraits *HTraits, |
| 456 | const CallEvent *Call) const; |
| 457 | }; |
| 458 | |
| 459 | //===----------------------------------------------------------------------===// |
| 460 | // ProgramStateManager - Factory object for ProgramStates. |
| 461 | //===----------------------------------------------------------------------===// |
| 462 | |
| 463 | class ProgramStateManager { |
| 464 | friend class ProgramState; |
| 465 | friend void ProgramStateRelease(const ProgramState *state); |
| 466 | private: |
| 467 | /// Eng - The ExprEngine that owns this state manager. |
| 468 | ExprEngine *Eng; /* Can be null. */ |
| 469 | |
| 470 | EnvironmentManager EnvMgr; |
| 471 | std::unique_ptr<StoreManager> StoreMgr; |
| 472 | std::unique_ptr<ConstraintManager> ConstraintMgr; |
| 473 | |
| 474 | ProgramState::GenericDataMap::Factory GDMFactory; |
| 475 | |
| 476 | typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; |
| 477 | GDMContextsTy GDMContexts; |
| 478 | |
| 479 | /// StateSet - FoldingSet containing all the states created for analyzing |
| 480 | /// a particular function. This is used to unique states. |
| 481 | llvm::FoldingSet<ProgramState> StateSet; |
| 482 | |
| 483 | /// Object that manages the data for all created SVals. |
| 484 | std::unique_ptr<SValBuilder> svalBuilder; |
| 485 | |
| 486 | /// Manages memory for created CallEvents. |
| 487 | std::unique_ptr<CallEventManager> CallEventMgr; |
| 488 | |
| 489 | /// A BumpPtrAllocator to allocate states. |
| 490 | llvm::BumpPtrAllocator &Alloc; |
| 491 | |
| 492 | /// A vector of ProgramStates that we can reuse. |
| 493 | std::vector<ProgramState *> freeStates; |
| 494 | |
| 495 | public: |
| 496 | ProgramStateManager(ASTContext &Ctx, |
| 497 | StoreManagerCreator CreateStoreManager, |
| 498 | ConstraintManagerCreator CreateConstraintManager, |
| 499 | llvm::BumpPtrAllocator& alloc, |
| 500 | ExprEngine *expreng); |
| 501 | |
| 502 | ~ProgramStateManager(); |
| 503 | |
| 504 | ProgramStateRef getInitialState(const LocationContext *InitLoc); |
| 505 | |
| 506 | ASTContext &getContext() { return svalBuilder->getContext(); } |
| 507 | const ASTContext &getContext() const { return svalBuilder->getContext(); } |
| 508 | |
| 509 | BasicValueFactory &getBasicVals() { |
| 510 | return svalBuilder->getBasicValueFactory(); |
| 511 | } |
| 512 | |
| 513 | SValBuilder &getSValBuilder() { |
| 514 | return *svalBuilder; |
| 515 | } |
| 516 | |
| 517 | const SValBuilder &getSValBuilder() const { |
| 518 | return *svalBuilder; |
| 519 | } |
| 520 | |
| 521 | SymbolManager &getSymbolManager() { |
| 522 | return svalBuilder->getSymbolManager(); |
| 523 | } |
| 524 | const SymbolManager &getSymbolManager() const { |
| 525 | return svalBuilder->getSymbolManager(); |
| 526 | } |
| 527 | |
| 528 | llvm::BumpPtrAllocator& getAllocator() { return Alloc; } |
| 529 | |
| 530 | MemRegionManager& getRegionManager() { |
| 531 | return svalBuilder->getRegionManager(); |
| 532 | } |
| 533 | const MemRegionManager &getRegionManager() const { |
| 534 | return svalBuilder->getRegionManager(); |
| 535 | } |
| 536 | |
| 537 | CallEventManager &getCallEventManager() { return *CallEventMgr; } |
| 538 | |
| 539 | StoreManager &getStoreManager() { return *StoreMgr; } |
| 540 | ConstraintManager &getConstraintManager() { return *ConstraintMgr; } |
| 541 | ExprEngine &getOwningEngine() { return *Eng; } |
| 542 | |
| 543 | ProgramStateRef |
| 544 | removeDeadBindingsFromEnvironmentAndStore(ProgramStateRef St, |
| 545 | const StackFrameContext *LCtx, |
| 546 | SymbolReaper &SymReaper); |
| 547 | |
| 548 | public: |
| 549 | |
| 550 | SVal ArrayToPointer(Loc Array, QualType ElementTy) { |
| 551 | return StoreMgr->ArrayToPointer(Array, ElementTy); |
| 552 | } |
| 553 | |
| 554 | // Methods that manipulate the GDM. |
| 555 | ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data); |
| 556 | ProgramStateRef removeGDM(ProgramStateRef state, void *Key); |
| 557 | |
| 558 | // Methods that query & manipulate the Store. |
| 559 | |
| 560 | void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler& F) { |
| 561 | StoreMgr->iterBindings(state->getStore(), F); |
| 562 | } |
| 563 | |
| 564 | ProgramStateRef getPersistentState(ProgramState &Impl); |
| 565 | ProgramStateRef getPersistentStateWithGDM(ProgramStateRef FromState, |
| 566 | ProgramStateRef GDMState); |
| 567 | |
| 568 | bool haveEqualConstraints(ProgramStateRef S1, ProgramStateRef S2) const { |
| 569 | return ConstraintMgr->haveEqualConstraints(S1, S2); |
| 570 | } |
| 571 | |
| 572 | bool haveEqualEnvironments(ProgramStateRef S1, ProgramStateRef S2) const { |
| 573 | return S1->Env == S2->Env; |
| 574 | } |
| 575 | |
| 576 | bool haveEqualStores(ProgramStateRef S1, ProgramStateRef S2) const { |
| 577 | return S1->store == S2->store; |
| 578 | } |
| 579 | |
| 580 | //==---------------------------------------------------------------------==// |
| 581 | // Generic Data Map methods. |
| 582 | //==---------------------------------------------------------------------==// |
| 583 | // |
| 584 | // ProgramStateManager and ProgramState support a "generic data map" that allows |
| 585 | // different clients of ProgramState objects to embed arbitrary data within a |
| 586 | // ProgramState object. The generic data map is essentially an immutable map |
| 587 | // from a "tag" (that acts as the "key" for a client) and opaque values. |
| 588 | // Tags/keys and values are simply void* values. The typical way that clients |
| 589 | // generate unique tags are by taking the address of a static variable. |
| 590 | // Clients are responsible for ensuring that data values referred to by a |
| 591 | // the data pointer are immutable (and thus are essentially purely functional |
| 592 | // data). |
| 593 | // |
| 594 | // The templated methods below use the ProgramStateTrait<T> class |
| 595 | // to resolve keys into the GDM and to return data values to clients. |
| 596 | // |
| 597 | |
| 598 | // Trait based GDM dispatch. |
| 599 | template <typename T> |
| 600 | ProgramStateRef set(ProgramStateRef st, typename ProgramStateTrait<T>::data_type D) { |
| 601 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
| 602 | ProgramStateTrait<T>::MakeVoidPtr(D)); |
| 603 | } |
| 604 | |
| 605 | template<typename T> |
| 606 | ProgramStateRef set(ProgramStateRef st, |
| 607 | typename ProgramStateTrait<T>::key_type K, |
| 608 | typename ProgramStateTrait<T>::value_type V, |
| 609 | typename ProgramStateTrait<T>::context_type C) { |
| 610 | |
| 611 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
| 612 | ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C))); |
| 613 | } |
| 614 | |
| 615 | template <typename T> |
| 616 | ProgramStateRef add(ProgramStateRef st, |
| 617 | typename ProgramStateTrait<T>::key_type K, |
| 618 | typename ProgramStateTrait<T>::context_type C) { |
| 619 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
| 620 | ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C))); |
| 621 | } |
| 622 | |
| 623 | template <typename T> |
| 624 | ProgramStateRef remove(ProgramStateRef st, |
| 625 | typename ProgramStateTrait<T>::key_type K, |
| 626 | typename ProgramStateTrait<T>::context_type C) { |
| 627 | |
| 628 | return addGDM(st, ProgramStateTrait<T>::GDMIndex(), |
| 629 | ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C))); |
| 630 | } |
| 631 | |
| 632 | template <typename T> |
| 633 | ProgramStateRef remove(ProgramStateRef st) { |
| 634 | return removeGDM(st, ProgramStateTrait<T>::GDMIndex()); |
| 635 | } |
| 636 | |
| 637 | void *FindGDMContext(void *index, |
| 638 | void *(*CreateContext)(llvm::BumpPtrAllocator&), |
| 639 | void (*DeleteContext)(void*)); |
| 640 | |
| 641 | template <typename T> |
| 642 | typename ProgramStateTrait<T>::context_type get_context() { |
| 643 | void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(), |
| 644 | ProgramStateTrait<T>::CreateContext, |
| 645 | ProgramStateTrait<T>::DeleteContext); |
| 646 | |
| 647 | return ProgramStateTrait<T>::MakeContext(p); |
| 648 | } |
| 649 | }; |
| 650 | |
| 651 | |
| 652 | //===----------------------------------------------------------------------===// |
| 653 | // Out-of-line method definitions for ProgramState. |
| 654 | //===----------------------------------------------------------------------===// |
| 655 | |
| 656 | inline ConstraintManager &ProgramState::getConstraintManager() const { |
| 657 | return stateMgr->getConstraintManager(); |
| 658 | } |
| 659 | |
| 660 | inline const VarRegion* ProgramState::getRegion(const VarDecl *D, |
| 661 | const LocationContext *LC) const |
| 662 | { |
| 663 | return getStateManager().getRegionManager().getVarRegion(D, LC); |
| 664 | } |
| 665 | |
| 666 | inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond, |
| 667 | bool Assumption) const { |
| 668 | if (Cond.isUnknown()) |
| 669 | return this; |
| 670 | |
| 671 | return getStateManager().ConstraintMgr |
| 672 | ->assume(this, Cond.castAs<DefinedSVal>(), Assumption); |
| 673 | } |
| 674 | |
| 675 | inline std::pair<ProgramStateRef , ProgramStateRef > |
| 676 | ProgramState::assume(DefinedOrUnknownSVal Cond) const { |
| 677 | if (Cond.isUnknown()) |
| 678 | return std::make_pair(this, this); |
| 679 | |
| 680 | return getStateManager().ConstraintMgr |
| 681 | ->assumeDual(this, Cond.castAs<DefinedSVal>()); |
| 682 | } |
| 683 | |
| 684 | inline ProgramStateRef ProgramState::assumeInclusiveRange( |
| 685 | DefinedOrUnknownSVal Val, const llvm::APSInt &From, const llvm::APSInt &To, |
| 686 | bool Assumption) const { |
| 687 | if (Val.isUnknown()) |
| 688 | return this; |
| 689 | |
| 690 | assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!")(static_cast <bool> (Val.getAs<NonLoc>() && "Only NonLocs are supported!") ? void (0) : __assert_fail ("Val.getAs<NonLoc>() && \"Only NonLocs are supported!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" , 690, __extension__ __PRETTY_FUNCTION__)); |
| 691 | |
| 692 | return getStateManager().ConstraintMgr->assumeInclusiveRange( |
| 693 | this, Val.castAs<NonLoc>(), From, To, Assumption); |
| 694 | } |
| 695 | |
| 696 | inline std::pair<ProgramStateRef, ProgramStateRef> |
| 697 | ProgramState::assumeInclusiveRange(DefinedOrUnknownSVal Val, |
| 698 | const llvm::APSInt &From, |
| 699 | const llvm::APSInt &To) const { |
| 700 | if (Val.isUnknown()) |
| 701 | return std::make_pair(this, this); |
| 702 | |
| 703 | assert(Val.getAs<NonLoc>() && "Only NonLocs are supported!")(static_cast <bool> (Val.getAs<NonLoc>() && "Only NonLocs are supported!") ? void (0) : __assert_fail ("Val.getAs<NonLoc>() && \"Only NonLocs are supported!\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" , 703, __extension__ __PRETTY_FUNCTION__)); |
| 704 | |
| 705 | return getStateManager().ConstraintMgr->assumeInclusiveRangeDual( |
| 706 | this, Val.castAs<NonLoc>(), From, To); |
| 707 | } |
| 708 | |
| 709 | inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V, const LocationContext *LCtx) const { |
| 710 | if (Optional<Loc> L = LV.getAs<Loc>()) |
| 711 | return bindLoc(*L, V, LCtx); |
| 712 | return this; |
| 713 | } |
| 714 | |
| 715 | inline Loc ProgramState::getLValue(const CXXBaseSpecifier &BaseSpec, |
| 716 | const SubRegion *Super) const { |
| 717 | const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl(); |
| 718 | return loc::MemRegionVal( |
| 719 | getStateManager().getRegionManager().getCXXBaseObjectRegion( |
| 720 | Base, Super, BaseSpec.isVirtual())); |
| 721 | } |
| 722 | |
| 723 | inline Loc ProgramState::getLValue(const CXXRecordDecl *BaseClass, |
| 724 | const SubRegion *Super, |
| 725 | bool IsVirtual) const { |
| 726 | return loc::MemRegionVal( |
| 727 | getStateManager().getRegionManager().getCXXBaseObjectRegion( |
| 728 | BaseClass, Super, IsVirtual)); |
| 729 | } |
| 730 | |
| 731 | inline Loc ProgramState::getLValue(const VarDecl *VD, |
| 732 | const LocationContext *LC) const { |
| 733 | return getStateManager().StoreMgr->getLValueVar(VD, LC); |
| 734 | } |
| 735 | |
| 736 | inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal, |
| 737 | const LocationContext *LC) const { |
| 738 | return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); |
| 739 | } |
| 740 | |
| 741 | inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const { |
| 742 | return getStateManager().StoreMgr->getLValueIvar(D, Base); |
| 743 | } |
| 744 | |
| 745 | inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const { |
| 746 | return getStateManager().StoreMgr->getLValueField(D, Base); |
| 747 | } |
| 748 | |
| 749 | inline SVal ProgramState::getLValue(const IndirectFieldDecl *D, |
| 750 | SVal Base) const { |
| 751 | StoreManager &SM = *getStateManager().StoreMgr; |
| 752 | for (const auto *I : D->chain()) { |
| 753 | Base = SM.getLValueField(cast<FieldDecl>(I), Base); |
| 754 | } |
| 755 | |
| 756 | return Base; |
| 757 | } |
| 758 | |
| 759 | inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ |
| 760 | if (Optional<NonLoc> N = Idx.getAs<NonLoc>()) |
| 761 | return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); |
| 762 | return UnknownVal(); |
| 763 | } |
| 764 | |
| 765 | inline SVal ProgramState::getSVal(const Stmt *Ex, |
| 766 | const LocationContext *LCtx) const{ |
| 767 | return Env.getSVal(EnvironmentEntry(Ex, LCtx), |
| 768 | *getStateManager().svalBuilder); |
| 769 | } |
| 770 | |
| 771 | inline SVal |
| 772 | ProgramState::getSValAsScalarOrLoc(const Stmt *S, |
| 773 | const LocationContext *LCtx) const { |
| 774 | if (const Expr *Ex = dyn_cast<Expr>(S)) { |
| 775 | QualType T = Ex->getType(); |
| 776 | if (Ex->isGLValue() || Loc::isLocType(T) || |
| 777 | T->isIntegralOrEnumerationType()) |
| 778 | return getSVal(S, LCtx); |
| 779 | } |
| 780 | |
| 781 | return UnknownVal(); |
| 782 | } |
| 783 | |
| 784 | inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const { |
| 785 | return getStateManager().StoreMgr->getBinding(getStore(), LV, T); |
| 786 | } |
| 787 | |
| 788 | inline SVal ProgramState::getSVal(const MemRegion* R, QualType T) const { |
| 789 | return getStateManager().StoreMgr->getBinding(getStore(), |
| 790 | loc::MemRegionVal(R), |
| 791 | T); |
| 792 | } |
| 793 | |
| 794 | inline BasicValueFactory &ProgramState::getBasicVals() const { |
| 795 | return getStateManager().getBasicVals(); |
| 796 | } |
| 797 | |
| 798 | inline SymbolManager &ProgramState::getSymbolManager() const { |
| 799 | return getStateManager().getSymbolManager(); |
| 800 | } |
| 801 | |
| 802 | template<typename T> |
| 803 | ProgramStateRef ProgramState::add(typename ProgramStateTrait<T>::key_type K) const { |
| 804 | return getStateManager().add<T>(this, K, get_context<T>()); |
| 805 | } |
| 806 | |
| 807 | template <typename T> |
| 808 | typename ProgramStateTrait<T>::context_type ProgramState::get_context() const { |
| 809 | return getStateManager().get_context<T>(); |
| 810 | } |
| 811 | |
| 812 | template<typename T> |
| 813 | ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const { |
| 814 | return getStateManager().remove<T>(this, K, get_context<T>()); |
| 815 | } |
| 816 | |
| 817 | template<typename T> |
| 818 | ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K, |
| 819 | typename ProgramStateTrait<T>::context_type C) const { |
| 820 | return getStateManager().remove<T>(this, K, C); |
| 821 | } |
| 822 | |
| 823 | template <typename T> |
| 824 | ProgramStateRef ProgramState::remove() const { |
| 825 | return getStateManager().remove<T>(this); |
| 826 | } |
| 827 | |
| 828 | template<typename T> |
| 829 | ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::data_type D) const { |
| 830 | return getStateManager().set<T>(this, D); |
| 831 | } |
| 832 | |
| 833 | template<typename T> |
| 834 | ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, |
| 835 | typename ProgramStateTrait<T>::value_type E) const { |
| 836 | return getStateManager().set<T>(this, K, E, get_context<T>()); |
| 837 | } |
| 838 | |
| 839 | template<typename T> |
| 840 | ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, |
| 841 | typename ProgramStateTrait<T>::value_type E, |
| 842 | typename ProgramStateTrait<T>::context_type C) const { |
| 843 | return getStateManager().set<T>(this, K, E, C); |
| 844 | } |
| 845 | |
| 846 | template <typename CB> |
| 847 | CB ProgramState::scanReachableSymbols(SVal val) const { |
| 848 | CB cb(this); |
| 849 | scanReachableSymbols(val, cb); |
| 850 | return cb; |
| 851 | } |
| 852 | |
| 853 | template <typename CB> |
| 854 | CB ProgramState::scanReachableSymbols( |
| 855 | llvm::iterator_range<region_iterator> Reachable) const { |
| 856 | CB cb(this); |
| 857 | scanReachableSymbols(Reachable, cb); |
| 858 | return cb; |
| 859 | } |
| 860 | |
| 861 | /// \class ScanReachableSymbols |
| 862 | /// A utility class that visits the reachable symbols using a custom |
| 863 | /// SymbolVisitor. Terminates recursive traversal when the visitor function |
| 864 | /// returns false. |
| 865 | class ScanReachableSymbols { |
| 866 | typedef llvm::DenseSet<const void*> VisitedItems; |
| 867 | |
| 868 | VisitedItems visited; |
| 869 | ProgramStateRef state; |
| 870 | SymbolVisitor &visitor; |
| 871 | public: |
| 872 | ScanReachableSymbols(ProgramStateRef st, SymbolVisitor &v) |
| 873 | : state(std::move(st)), visitor(v) {} |
| 874 | |
| 875 | bool scan(nonloc::LazyCompoundVal val); |
| 876 | bool scan(nonloc::CompoundVal val); |
| 877 | bool scan(SVal val); |
| 878 | bool scan(const MemRegion *R); |
| 879 | bool scan(const SymExpr *sym); |
| 880 | }; |
| 881 | |
| 882 | } // end ento namespace |
| 883 | |
| 884 | } // end clang namespace |
| 885 | |
| 886 | #endif |
| 1 | //===- Optional.h - Simple variant for passing optional values --*- 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 provides Optional, a template class modeled in the spirit of |
| 10 | // OCaml's 'opt' variant. The idea is to strongly type whether or not |
| 11 | // a value can be optional. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #ifndef LLVM_ADT_OPTIONAL_H |
| 16 | #define LLVM_ADT_OPTIONAL_H |
| 17 | |
| 18 | #include "llvm/ADT/Hashing.h" |
| 19 | #include "llvm/ADT/None.h" |
| 20 | #include "llvm/ADT/STLForwardCompat.h" |
| 21 | #include "llvm/Support/Compiler.h" |
| 22 | #include "llvm/Support/type_traits.h" |
| 23 | #include <cassert> |
| 24 | #include <memory> |
| 25 | #include <new> |
| 26 | #include <utility> |
| 27 | |
| 28 | namespace llvm { |
| 29 | |
| 30 | class raw_ostream; |
| 31 | |
| 32 | namespace optional_detail { |
| 33 | |
| 34 | /// Storage for any type. |
| 35 | // |
| 36 | // The specialization condition intentionally uses |
| 37 | // llvm::is_trivially_copy_constructible instead of |
| 38 | // std::is_trivially_copy_constructible. GCC versions prior to 7.4 may |
| 39 | // instantiate the copy constructor of `T` when |
| 40 | // std::is_trivially_copy_constructible is instantiated. This causes |
| 41 | // compilation to fail if we query the trivially copy constructible property of |
| 42 | // a class which is not copy constructible. |
| 43 | // |
| 44 | // The current implementation of OptionalStorage insists that in order to use |
| 45 | // the trivial specialization, the value_type must be trivially copy |
| 46 | // constructible and trivially copy assignable due to =default implementations |
| 47 | // of the copy/move constructor/assignment. It does not follow that this is |
| 48 | // necessarily the case std::is_trivially_copyable is true (hence the expanded |
| 49 | // specialization condition). |
| 50 | // |
| 51 | // The move constructible / assignable conditions emulate the remaining behavior |
| 52 | // of std::is_trivially_copyable. |
| 53 | template <typename T, bool = (llvm::is_trivially_copy_constructible<T>::value && |
| 54 | std::is_trivially_copy_assignable<T>::value && |
| 55 | (std::is_trivially_move_constructible<T>::value || |
| 56 | !std::is_move_constructible<T>::value) && |
| 57 | (std::is_trivially_move_assignable<T>::value || |
| 58 | !std::is_move_assignable<T>::value))> |
| 59 | class OptionalStorage { |
| 60 | union { |
| 61 | char empty; |
| 62 | T value; |
| 63 | }; |
| 64 | bool hasVal; |
| 65 | |
| 66 | public: |
| 67 | ~OptionalStorage() { reset(); } |
| 68 | |
| 69 | constexpr OptionalStorage() noexcept : empty(), hasVal(false) {} |
| 70 | |
| 71 | constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() { |
| 72 | if (other.hasValue()) { |
| 73 | emplace(other.value); |
| 74 | } |
| 75 | } |
| 76 | constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() { |
| 77 | if (other.hasValue()) { |
| 78 | emplace(std::move(other.value)); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | template <class... Args> |
| 83 | constexpr explicit OptionalStorage(in_place_t, Args &&... args) |
| 84 | : value(std::forward<Args>(args)...), hasVal(true) {} |
| 85 | |
| 86 | void reset() noexcept { |
| 87 | if (hasVal) { |
| 88 | value.~T(); |
| 89 | hasVal = false; |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | constexpr bool hasValue() const noexcept { return hasVal; } |
| 94 | |
| 95 | T &getValue() LLVM_LVALUE_FUNCTION& noexcept { |
| 96 | assert(hasVal)(static_cast <bool> (hasVal) ? void (0) : __assert_fail ("hasVal", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/Optional.h" , 96, __extension__ __PRETTY_FUNCTION__)); |
| 97 | return value; |
| 98 | } |
| 99 | constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept { |
| 100 | assert(hasVal)(static_cast <bool> (hasVal) ? void (0) : __assert_fail ("hasVal", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/Optional.h" , 100, __extension__ __PRETTY_FUNCTION__)); |
| 101 | return value; |
| 102 | } |
| 103 | #if LLVM_HAS_RVALUE_REFERENCE_THIS1 |
| 104 | T &&getValue() && noexcept { |
| 105 | assert(hasVal)(static_cast <bool> (hasVal) ? void (0) : __assert_fail ("hasVal", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/Optional.h" , 105, __extension__ __PRETTY_FUNCTION__)); |
| 106 | return std::move(value); |
| 107 | } |
| 108 | #endif |
| 109 | |
| 110 | template <class... Args> void emplace(Args &&... args) { |
| 111 | reset(); |
| 112 | ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); |
| 113 | hasVal = true; |
| 114 | } |
| 115 | |
| 116 | OptionalStorage &operator=(T const &y) { |
| 117 | if (hasValue()) { |
| 118 | value = y; |
| 119 | } else { |
| 120 | ::new ((void *)std::addressof(value)) T(y); |
| 121 | hasVal = true; |
| 122 | } |
| 123 | return *this; |
| 124 | } |
| 125 | OptionalStorage &operator=(T &&y) { |
| 126 | if (hasValue()) { |
| 127 | value = std::move(y); |
| 128 | } else { |
| 129 | ::new ((void *)std::addressof(value)) T(std::move(y)); |
| 130 | hasVal = true; |
| 131 | } |
| 132 | return *this; |
| 133 | } |
| 134 | |
| 135 | OptionalStorage &operator=(OptionalStorage const &other) { |
| 136 | if (other.hasValue()) { |
| 137 | if (hasValue()) { |
| 138 | value = other.value; |
| 139 | } else { |
| 140 | ::new ((void *)std::addressof(value)) T(other.value); |
| 141 | hasVal = true; |
| 142 | } |
| 143 | } else { |
| 144 | reset(); |
| 145 | } |
| 146 | return *this; |
| 147 | } |
| 148 | |
| 149 | OptionalStorage &operator=(OptionalStorage &&other) { |
| 150 | if (other.hasValue()) { |
| 151 | if (hasValue()) { |
| 152 | value = std::move(other.value); |
| 153 | } else { |
| 154 | ::new ((void *)std::addressof(value)) T(std::move(other.value)); |
| 155 | hasVal = true; |
| 156 | } |
| 157 | } else { |
| 158 | reset(); |
| 159 | } |
| 160 | return *this; |
| 161 | } |
| 162 | }; |
| 163 | |
| 164 | template <typename T> class OptionalStorage<T, true> { |
| 165 | union { |
| 166 | char empty; |
| 167 | T value; |
| 168 | }; |
| 169 | bool hasVal = false; |
| 170 | |
| 171 | public: |
| 172 | ~OptionalStorage() = default; |
| 173 | |
| 174 | constexpr OptionalStorage() noexcept : empty{} {} |
| 175 | |
| 176 | constexpr OptionalStorage(OptionalStorage const &other) = default; |
| 177 | constexpr OptionalStorage(OptionalStorage &&other) = default; |
| 178 | |
| 179 | OptionalStorage &operator=(OptionalStorage const &other) = default; |
| 180 | OptionalStorage &operator=(OptionalStorage &&other) = default; |
| 181 | |
| 182 | template <class... Args> |
| 183 | constexpr explicit OptionalStorage(in_place_t, Args &&... args) |
| 184 | : value(std::forward<Args>(args)...), hasVal(true) {} |
| 185 | |
| 186 | void reset() noexcept { |
| 187 | if (hasVal) { |
| 188 | value.~T(); |
| 189 | hasVal = false; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | constexpr bool hasValue() const noexcept { return hasVal; } |
| 194 | |
| 195 | T &getValue() LLVM_LVALUE_FUNCTION& noexcept { |
| 196 | assert(hasVal)(static_cast <bool> (hasVal) ? void (0) : __assert_fail ("hasVal", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/Optional.h" , 196, __extension__ __PRETTY_FUNCTION__)); |
| 197 | return value; |
| 198 | } |
| 199 | constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept { |
| 200 | assert(hasVal)(static_cast <bool> (hasVal) ? void (0) : __assert_fail ("hasVal", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/Optional.h" , 200, __extension__ __PRETTY_FUNCTION__)); |
| 201 | return value; |
| 202 | } |
| 203 | #if LLVM_HAS_RVALUE_REFERENCE_THIS1 |
| 204 | T &&getValue() && noexcept { |
| 205 | assert(hasVal)(static_cast <bool> (hasVal) ? void (0) : __assert_fail ("hasVal", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/llvm/include/llvm/ADT/Optional.h" , 205, __extension__ __PRETTY_FUNCTION__)); |
| 206 | return std::move(value); |
| 207 | } |
| 208 | #endif |
| 209 | |
| 210 | template <class... Args> void emplace(Args &&... args) { |
| 211 | reset(); |
| 212 | ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...); |
| 213 | hasVal = true; |
| 214 | } |
| 215 | |
| 216 | OptionalStorage &operator=(T const &y) { |
| 217 | if (hasValue()) { |
| 218 | value = y; |
| 219 | } else { |
| 220 | ::new ((void *)std::addressof(value)) T(y); |
| 221 | hasVal = true; |
| 222 | } |
| 223 | return *this; |
| 224 | } |
| 225 | OptionalStorage &operator=(T &&y) { |
| 226 | if (hasValue()) { |
| 227 | value = std::move(y); |
| 228 | } else { |
| 229 | ::new ((void *)std::addressof(value)) T(std::move(y)); |
| 230 | hasVal = true; |
| 231 | } |
| 232 | return *this; |
| 233 | } |
| 234 | }; |
| 235 | |
| 236 | } // namespace optional_detail |
| 237 | |
| 238 | template <typename T> class Optional { |
| 239 | optional_detail::OptionalStorage<T> Storage; |
| 240 | |
| 241 | public: |
| 242 | using value_type = T; |
| 243 | |
| 244 | constexpr Optional() {} |
| 245 | constexpr Optional(NoneType) {} |
| 246 | |
| 247 | constexpr Optional(const T &y) : Storage(in_place, y) {} |
| 248 | constexpr Optional(const Optional &O) = default; |
| 249 | |
| 250 | constexpr Optional(T &&y) : Storage(in_place, std::move(y)) {} |
| 251 | constexpr Optional(Optional &&O) = default; |
| 252 | |
| 253 | template <typename... ArgTypes> |
| 254 | constexpr Optional(in_place_t, ArgTypes &&...Args) |
| 255 | : Storage(in_place, std::forward<ArgTypes>(Args)...) {} |
| 256 | |
| 257 | Optional &operator=(T &&y) { |
| 258 | Storage = std::move(y); |
| 259 | return *this; |
| 260 | } |
| 261 | Optional &operator=(Optional &&O) = default; |
| 262 | |
| 263 | /// Create a new object by constructing it in place with the given arguments. |
| 264 | template <typename... ArgTypes> void emplace(ArgTypes &&... Args) { |
| 265 | Storage.emplace(std::forward<ArgTypes>(Args)...); |
| 266 | } |
| 267 | |
| 268 | static constexpr Optional create(const T *y) { |
| 269 | return y ? Optional(*y) : Optional(); |
| 270 | } |
| 271 | |
| 272 | Optional &operator=(const T &y) { |
| 273 | Storage = y; |
| 274 | return *this; |
| 275 | } |
| 276 | Optional &operator=(const Optional &O) = default; |
| 277 | |
| 278 | void reset() { Storage.reset(); } |
| 279 | |
| 280 | constexpr const T *getPointer() const { return &Storage.getValue(); } |
| 281 | T *getPointer() { return &Storage.getValue(); } |
| 282 | constexpr const T &getValue() const LLVM_LVALUE_FUNCTION& { |
| 283 | return Storage.getValue(); |
| 284 | } |
| 285 | T &getValue() LLVM_LVALUE_FUNCTION& { return Storage.getValue(); } |
| 286 | |
| 287 | constexpr explicit operator bool() const { return hasValue(); } |
| 288 | constexpr bool hasValue() const { return Storage.hasValue(); } |
| 289 | constexpr const T *operator->() const { return getPointer(); } |
| 290 | T *operator->() { return getPointer(); } |
| 291 | constexpr const T &operator*() const LLVM_LVALUE_FUNCTION& { |
| 292 | return getValue(); |
| 293 | } |
| 294 | T &operator*() LLVM_LVALUE_FUNCTION& { return getValue(); } |
| 295 | |
| 296 | template <typename U> |
| 297 | constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION& { |
| 298 | return hasValue() ? getValue() : std::forward<U>(value); |
| 299 | } |
| 300 | |
| 301 | /// Apply a function to the value if present; otherwise return None. |
| 302 | template <class Function> |
| 303 | auto map(const Function &F) const LLVM_LVALUE_FUNCTION& |
| 304 | -> Optional<decltype(F(getValue()))> { |
| 305 | if (*this) return F(getValue()); |
| 306 | return None; |
| 307 | } |
| 308 | |
| 309 | #if LLVM_HAS_RVALUE_REFERENCE_THIS1 |
| 310 | T &&getValue() && { return std::move(Storage.getValue()); } |
| 311 | T &&operator*() && { return std::move(Storage.getValue()); } |
| 312 | |
| 313 | template <typename U> |
| 314 | T getValueOr(U &&value) && { |
| 315 | return hasValue() ? std::move(getValue()) : std::forward<U>(value); |
| 316 | } |
| 317 | |
| 318 | /// Apply a function to the value if present; otherwise return None. |
| 319 | template <class Function> |
| 320 | auto map(const Function &F) && |
| 321 | -> Optional<decltype(F(std::move(*this).getValue()))> { |
| 322 | if (*this) return F(std::move(*this).getValue()); |
| 323 | return None; |
| 324 | } |
| 325 | #endif |
| 326 | }; |
| 327 | |
| 328 | template <class T> llvm::hash_code hash_value(const Optional<T> &O) { |
| 329 | return O ? hash_combine(true, *O) : hash_value(false); |
| 330 | } |
| 331 | |
| 332 | template <typename T, typename U> |
| 333 | constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) { |
| 334 | if (X && Y) |
| 335 | return *X == *Y; |
| 336 | return X.hasValue() == Y.hasValue(); |
| 337 | } |
| 338 | |
| 339 | template <typename T, typename U> |
| 340 | constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) { |
| 341 | return !(X == Y); |
| 342 | } |
| 343 | |
| 344 | template <typename T, typename U> |
| 345 | constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) { |
| 346 | if (X && Y) |
| 347 | return *X < *Y; |
| 348 | return X.hasValue() < Y.hasValue(); |
| 349 | } |
| 350 | |
| 351 | template <typename T, typename U> |
| 352 | constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) { |
| 353 | return !(Y < X); |
| 354 | } |
| 355 | |
| 356 | template <typename T, typename U> |
| 357 | constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) { |
| 358 | return Y < X; |
| 359 | } |
| 360 | |
| 361 | template <typename T, typename U> |
| 362 | constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) { |
| 363 | return !(X < Y); |
| 364 | } |
| 365 | |
| 366 | template <typename T> |
| 367 | constexpr bool operator==(const Optional<T> &X, NoneType) { |
| 368 | return !X; |
| 369 | } |
| 370 | |
| 371 | template <typename T> |
| 372 | constexpr bool operator==(NoneType, const Optional<T> &X) { |
| 373 | return X == None; |
| 374 | } |
| 375 | |
| 376 | template <typename T> |
| 377 | constexpr bool operator!=(const Optional<T> &X, NoneType) { |
| 378 | return !(X == None); |
| 379 | } |
| 380 | |
| 381 | template <typename T> |
| 382 | constexpr bool operator!=(NoneType, const Optional<T> &X) { |
| 383 | return X != None; |
| 384 | } |
| 385 | |
| 386 | template <typename T> constexpr bool operator<(const Optional<T> &, NoneType) { |
| 387 | return false; |
| 388 | } |
| 389 | |
| 390 | template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) { |
| 391 | return X.hasValue(); |
| 392 | } |
| 393 | |
| 394 | template <typename T> |
| 395 | constexpr bool operator<=(const Optional<T> &X, NoneType) { |
| 396 | return !(None < X); |
| 397 | } |
| 398 | |
| 399 | template <typename T> |
| 400 | constexpr bool operator<=(NoneType, const Optional<T> &X) { |
| 401 | return !(X < None); |
| 402 | } |
| 403 | |
| 404 | template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) { |
| 405 | return None < X; |
| 406 | } |
| 407 | |
| 408 | template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) { |
| 409 | return X < None; |
| 410 | } |
| 411 | |
| 412 | template <typename T> |
| 413 | constexpr bool operator>=(const Optional<T> &X, NoneType) { |
| 414 | return None <= X; |
| 415 | } |
| 416 | |
| 417 | template <typename T> |
| 418 | constexpr bool operator>=(NoneType, const Optional<T> &X) { |
| 419 | return X <= None; |
| 420 | } |
| 421 | |
| 422 | template <typename T> |
| 423 | constexpr bool operator==(const Optional<T> &X, const T &Y) { |
| 424 | return X && *X == Y; |
| 425 | } |
| 426 | |
| 427 | template <typename T> |
| 428 | constexpr bool operator==(const T &X, const Optional<T> &Y) { |
| 429 | return Y && X == *Y; |
| 430 | } |
| 431 | |
| 432 | template <typename T> |
| 433 | constexpr bool operator!=(const Optional<T> &X, const T &Y) { |
| 434 | return !(X == Y); |
| 435 | } |
| 436 | |
| 437 | template <typename T> |
| 438 | constexpr bool operator!=(const T &X, const Optional<T> &Y) { |
| 439 | return !(X == Y); |
| 440 | } |
| 441 | |
| 442 | template <typename T> |
| 443 | constexpr bool operator<(const Optional<T> &X, const T &Y) { |
| 444 | return !X || *X < Y; |
| 445 | } |
| 446 | |
| 447 | template <typename T> |
| 448 | constexpr bool operator<(const T &X, const Optional<T> &Y) { |
| 449 | return Y && X < *Y; |
| 450 | } |
| 451 | |
| 452 | template <typename T> |
| 453 | constexpr bool operator<=(const Optional<T> &X, const T &Y) { |
| 454 | return !(Y < X); |
| 455 | } |
| 456 | |
| 457 | template <typename T> |
| 458 | constexpr bool operator<=(const T &X, const Optional<T> &Y) { |
| 459 | return !(Y < X); |
| 460 | } |
| 461 | |
| 462 | template <typename T> |
| 463 | constexpr bool operator>(const Optional<T> &X, const T &Y) { |
| 464 | return Y < X; |
| 465 | } |
| 466 | |
| 467 | template <typename T> |
| 468 | constexpr bool operator>(const T &X, const Optional<T> &Y) { |
| 469 | return Y < X; |
| 470 | } |
| 471 | |
| 472 | template <typename T> |
| 473 | constexpr bool operator>=(const Optional<T> &X, const T &Y) { |
| 474 | return !(X < Y); |
| 475 | } |
| 476 | |
| 477 | template <typename T> |
| 478 | constexpr bool operator>=(const T &X, const Optional<T> &Y) { |
| 479 | return !(X < Y); |
| 480 | } |
| 481 | |
| 482 | raw_ostream &operator<<(raw_ostream &OS, NoneType); |
| 483 | |
| 484 | template <typename T, typename = decltype(std::declval<raw_ostream &>() |
| 485 | << std::declval<const T &>())> |
| 486 | raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) { |
| 487 | if (O) |
| 488 | OS << *O; |
| 489 | else |
| 490 | OS << None; |
| 491 | return OS; |
| 492 | } |
| 493 | |
| 494 | } // end namespace llvm |
| 495 | |
| 496 | #endif // LLVM_ADT_OPTIONAL_H |