1 1.1 joerg //===- CastValueChecker - Model implementation of custom RTTIs --*- C++ -*-===// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // This defines CastValueChecker which models casts of custom RTTIs. 10 1.1 joerg // 11 1.1 joerg // TODO list: 12 1.1 joerg // - It only allows one succesful cast between two types however in the wild 13 1.1 joerg // the object could be casted to multiple types. 14 1.1 joerg // - It needs to check the most likely type information from the dynamic type 15 1.1 joerg // map to increase precision of dynamic casting. 16 1.1 joerg // 17 1.1 joerg //===----------------------------------------------------------------------===// 18 1.1 joerg 19 1.1 joerg #include "clang/AST/DeclTemplate.h" 20 1.1 joerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 21 1.1 joerg #include "clang/StaticAnalyzer/Core/Checker.h" 22 1.1 joerg #include "clang/StaticAnalyzer/Core/CheckerManager.h" 23 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 24 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" 26 1.1 joerg #include "llvm/ADT/Optional.h" 27 1.1 joerg #include <utility> 28 1.1 joerg 29 1.1 joerg using namespace clang; 30 1.1 joerg using namespace ento; 31 1.1 joerg 32 1.1 joerg namespace { 33 1.1.1.2 joerg class CastValueChecker : public Checker<check::DeadSymbols, eval::Call> { 34 1.1 joerg enum class CallKind { Function, Method, InstanceOf }; 35 1.1 joerg 36 1.1 joerg using CastCheck = 37 1.1 joerg std::function<void(const CastValueChecker *, const CallEvent &Call, 38 1.1 joerg DefinedOrUnknownSVal, CheckerContext &)>; 39 1.1 joerg 40 1.1 joerg public: 41 1.1 joerg // We have five cases to evaluate a cast: 42 1.1 joerg // 1) The parameter is non-null, the return value is non-null. 43 1.1 joerg // 2) The parameter is non-null, the return value is null. 44 1.1 joerg // 3) The parameter is null, the return value is null. 45 1.1 joerg // cast: 1; dyn_cast: 1, 2; cast_or_null: 1, 3; dyn_cast_or_null: 1, 2, 3. 46 1.1 joerg // 47 1.1 joerg // 4) castAs: Has no parameter, the return value is non-null. 48 1.1 joerg // 5) getAs: Has no parameter, the return value is null or non-null. 49 1.1 joerg // 50 1.1 joerg // We have two cases to check the parameter is an instance of the given type. 51 1.1 joerg // 1) isa: The parameter is non-null, returns boolean. 52 1.1 joerg // 2) isa_and_nonnull: The parameter is null or non-null, returns boolean. 53 1.1 joerg bool evalCall(const CallEvent &Call, CheckerContext &C) const; 54 1.1.1.2 joerg void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 55 1.1 joerg 56 1.1 joerg private: 57 1.1 joerg // These are known in the LLVM project. The pairs are in the following form: 58 1.1 joerg // {{{namespace, call}, argument-count}, {callback, kind}} 59 1.1 joerg const CallDescriptionMap<std::pair<CastCheck, CallKind>> CDM = { 60 1.1 joerg {{{"llvm", "cast"}, 1}, 61 1.1 joerg {&CastValueChecker::evalCast, CallKind::Function}}, 62 1.1 joerg {{{"llvm", "dyn_cast"}, 1}, 63 1.1 joerg {&CastValueChecker::evalDynCast, CallKind::Function}}, 64 1.1 joerg {{{"llvm", "cast_or_null"}, 1}, 65 1.1 joerg {&CastValueChecker::evalCastOrNull, CallKind::Function}}, 66 1.1 joerg {{{"llvm", "dyn_cast_or_null"}, 1}, 67 1.1 joerg {&CastValueChecker::evalDynCastOrNull, CallKind::Function}}, 68 1.1 joerg {{{"clang", "castAs"}, 0}, 69 1.1 joerg {&CastValueChecker::evalCastAs, CallKind::Method}}, 70 1.1 joerg {{{"clang", "getAs"}, 0}, 71 1.1 joerg {&CastValueChecker::evalGetAs, CallKind::Method}}, 72 1.1 joerg {{{"llvm", "isa"}, 1}, 73 1.1 joerg {&CastValueChecker::evalIsa, CallKind::InstanceOf}}, 74 1.1 joerg {{{"llvm", "isa_and_nonnull"}, 1}, 75 1.1 joerg {&CastValueChecker::evalIsaAndNonNull, CallKind::InstanceOf}}}; 76 1.1 joerg 77 1.1 joerg void evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 78 1.1 joerg CheckerContext &C) const; 79 1.1 joerg void evalDynCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 80 1.1 joerg CheckerContext &C) const; 81 1.1 joerg void evalCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 82 1.1 joerg CheckerContext &C) const; 83 1.1 joerg void evalDynCastOrNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 84 1.1 joerg CheckerContext &C) const; 85 1.1 joerg void evalCastAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 86 1.1 joerg CheckerContext &C) const; 87 1.1 joerg void evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 88 1.1 joerg CheckerContext &C) const; 89 1.1 joerg void evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV, 90 1.1 joerg CheckerContext &C) const; 91 1.1 joerg void evalIsaAndNonNull(const CallEvent &Call, DefinedOrUnknownSVal DV, 92 1.1 joerg CheckerContext &C) const; 93 1.1 joerg }; 94 1.1 joerg } // namespace 95 1.1 joerg 96 1.1 joerg static bool isInfeasibleCast(const DynamicCastInfo *CastInfo, 97 1.1 joerg bool CastSucceeds) { 98 1.1 joerg if (!CastInfo) 99 1.1 joerg return false; 100 1.1 joerg 101 1.1 joerg return CastSucceeds ? CastInfo->fails() : CastInfo->succeeds(); 102 1.1 joerg } 103 1.1 joerg 104 1.1 joerg static const NoteTag *getNoteTag(CheckerContext &C, 105 1.1 joerg const DynamicCastInfo *CastInfo, 106 1.1 joerg QualType CastToTy, const Expr *Object, 107 1.1 joerg bool CastSucceeds, bool IsKnownCast) { 108 1.1 joerg std::string CastToName = 109 1.1.1.2 joerg CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString() 110 1.1 joerg : CastToTy->getPointeeCXXRecordDecl()->getNameAsString(); 111 1.1 joerg Object = Object->IgnoreParenImpCasts(); 112 1.1 joerg 113 1.1 joerg return C.getNoteTag( 114 1.1 joerg [=]() -> std::string { 115 1.1 joerg SmallString<128> Msg; 116 1.1 joerg llvm::raw_svector_ostream Out(Msg); 117 1.1 joerg 118 1.1 joerg if (!IsKnownCast) 119 1.1 joerg Out << "Assuming "; 120 1.1 joerg 121 1.1 joerg if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) { 122 1.1.1.2 joerg Out << '\'' << DRE->getDecl()->getDeclName() << '\''; 123 1.1 joerg } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) { 124 1.1 joerg Out << (IsKnownCast ? "Field '" : "field '") 125 1.1.1.2 joerg << ME->getMemberDecl()->getDeclName() << '\''; 126 1.1 joerg } else { 127 1.1 joerg Out << (IsKnownCast ? "The object" : "the object"); 128 1.1 joerg } 129 1.1 joerg 130 1.1 joerg Out << ' ' << (CastSucceeds ? "is a" : "is not a") << " '" << CastToName 131 1.1 joerg << '\''; 132 1.1 joerg 133 1.1.1.2 joerg return std::string(Out.str()); 134 1.1.1.2 joerg }, 135 1.1.1.2 joerg /*IsPrunable=*/true); 136 1.1.1.2 joerg } 137 1.1.1.2 joerg 138 1.1.1.2 joerg static const NoteTag *getNoteTag(CheckerContext &C, 139 1.1.1.2 joerg SmallVector<QualType, 4> CastToTyVec, 140 1.1.1.2 joerg const Expr *Object, 141 1.1.1.2 joerg bool IsKnownCast) { 142 1.1.1.2 joerg Object = Object->IgnoreParenImpCasts(); 143 1.1.1.2 joerg 144 1.1.1.2 joerg return C.getNoteTag( 145 1.1.1.2 joerg [=]() -> std::string { 146 1.1.1.2 joerg SmallString<128> Msg; 147 1.1.1.2 joerg llvm::raw_svector_ostream Out(Msg); 148 1.1.1.2 joerg 149 1.1.1.2 joerg if (!IsKnownCast) 150 1.1.1.2 joerg Out << "Assuming "; 151 1.1.1.2 joerg 152 1.1.1.2 joerg if (const auto *DRE = dyn_cast<DeclRefExpr>(Object)) { 153 1.1.1.2 joerg Out << '\'' << DRE->getDecl()->getNameAsString() << '\''; 154 1.1.1.2 joerg } else if (const auto *ME = dyn_cast<MemberExpr>(Object)) { 155 1.1.1.2 joerg Out << (IsKnownCast ? "Field '" : "field '") 156 1.1.1.2 joerg << ME->getMemberDecl()->getNameAsString() << '\''; 157 1.1.1.2 joerg } else { 158 1.1.1.2 joerg Out << (IsKnownCast ? "The object" : "the object"); 159 1.1.1.2 joerg } 160 1.1.1.2 joerg Out << " is"; 161 1.1.1.2 joerg 162 1.1.1.2 joerg bool First = true; 163 1.1.1.2 joerg for (QualType CastToTy: CastToTyVec) { 164 1.1.1.2 joerg std::string CastToName = 165 1.1.1.2 joerg CastToTy->getAsCXXRecordDecl() ? 166 1.1.1.2 joerg CastToTy->getAsCXXRecordDecl()->getNameAsString() : 167 1.1.1.2 joerg CastToTy->getPointeeCXXRecordDecl()->getNameAsString(); 168 1.1.1.2 joerg Out << ' ' << ((CastToTyVec.size() == 1) ? "not" : 169 1.1.1.2 joerg (First ? "neither" : "nor")) << " a '" << CastToName 170 1.1.1.2 joerg << '\''; 171 1.1.1.2 joerg First = false; 172 1.1.1.2 joerg } 173 1.1.1.2 joerg 174 1.1.1.2 joerg return std::string(Out.str()); 175 1.1 joerg }, 176 1.1 joerg /*IsPrunable=*/true); 177 1.1 joerg } 178 1.1 joerg 179 1.1 joerg //===----------------------------------------------------------------------===// 180 1.1 joerg // Main logic to evaluate a cast. 181 1.1 joerg //===----------------------------------------------------------------------===// 182 1.1 joerg 183 1.1 joerg static QualType alignReferenceTypes(QualType toAlign, QualType alignTowards, 184 1.1 joerg ASTContext &ACtx) { 185 1.1 joerg if (alignTowards->isLValueReferenceType() && 186 1.1 joerg alignTowards.isConstQualified()) { 187 1.1 joerg toAlign.addConst(); 188 1.1 joerg return ACtx.getLValueReferenceType(toAlign); 189 1.1 joerg } else if (alignTowards->isLValueReferenceType()) 190 1.1 joerg return ACtx.getLValueReferenceType(toAlign); 191 1.1 joerg else if (alignTowards->isRValueReferenceType()) 192 1.1 joerg return ACtx.getRValueReferenceType(toAlign); 193 1.1 joerg 194 1.1 joerg llvm_unreachable("Must align towards a reference type!"); 195 1.1 joerg } 196 1.1 joerg 197 1.1 joerg static void addCastTransition(const CallEvent &Call, DefinedOrUnknownSVal DV, 198 1.1 joerg CheckerContext &C, bool IsNonNullParam, 199 1.1 joerg bool IsNonNullReturn, 200 1.1 joerg bool IsCheckedCast = false) { 201 1.1 joerg ProgramStateRef State = C.getState()->assume(DV, IsNonNullParam); 202 1.1 joerg if (!State) 203 1.1 joerg return; 204 1.1 joerg 205 1.1 joerg const Expr *Object; 206 1.1 joerg QualType CastFromTy; 207 1.1 joerg QualType CastToTy = Call.getResultType(); 208 1.1 joerg 209 1.1 joerg if (Call.getNumArgs() > 0) { 210 1.1 joerg Object = Call.getArgExpr(0); 211 1.1 joerg CastFromTy = Call.parameters()[0]->getType(); 212 1.1 joerg } else { 213 1.1 joerg Object = cast<CXXInstanceCall>(&Call)->getCXXThisExpr(); 214 1.1 joerg CastFromTy = Object->getType(); 215 1.1 joerg if (CastToTy->isPointerType()) { 216 1.1 joerg if (!CastFromTy->isPointerType()) 217 1.1 joerg return; 218 1.1 joerg } else { 219 1.1 joerg if (!CastFromTy->isReferenceType()) 220 1.1 joerg return; 221 1.1 joerg 222 1.1 joerg CastFromTy = alignReferenceTypes(CastFromTy, CastToTy, C.getASTContext()); 223 1.1 joerg } 224 1.1 joerg } 225 1.1 joerg 226 1.1 joerg const MemRegion *MR = DV.getAsRegion(); 227 1.1 joerg const DynamicCastInfo *CastInfo = 228 1.1 joerg getDynamicCastInfo(State, MR, CastFromTy, CastToTy); 229 1.1 joerg 230 1.1 joerg // We assume that every checked cast succeeds. 231 1.1 joerg bool CastSucceeds = IsCheckedCast || CastFromTy == CastToTy; 232 1.1 joerg if (!CastSucceeds) { 233 1.1 joerg if (CastInfo) 234 1.1 joerg CastSucceeds = IsNonNullReturn && CastInfo->succeeds(); 235 1.1 joerg else 236 1.1 joerg CastSucceeds = IsNonNullReturn; 237 1.1 joerg } 238 1.1 joerg 239 1.1 joerg // Check for infeasible casts. 240 1.1 joerg if (isInfeasibleCast(CastInfo, CastSucceeds)) { 241 1.1 joerg C.generateSink(State, C.getPredecessor()); 242 1.1 joerg return; 243 1.1 joerg } 244 1.1 joerg 245 1.1 joerg // Store the type and the cast information. 246 1.1 joerg bool IsKnownCast = CastInfo || IsCheckedCast || CastFromTy == CastToTy; 247 1.1 joerg if (!IsKnownCast || IsCheckedCast) 248 1.1 joerg State = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, 249 1.1 joerg CastSucceeds); 250 1.1 joerg 251 1.1 joerg SVal V = CastSucceeds ? C.getSValBuilder().evalCast(DV, CastToTy, CastFromTy) 252 1.1 joerg : C.getSValBuilder().makeNull(); 253 1.1 joerg C.addTransition( 254 1.1 joerg State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), V, false), 255 1.1 joerg getNoteTag(C, CastInfo, CastToTy, Object, CastSucceeds, IsKnownCast)); 256 1.1 joerg } 257 1.1 joerg 258 1.1 joerg static void addInstanceOfTransition(const CallEvent &Call, 259 1.1 joerg DefinedOrUnknownSVal DV, 260 1.1 joerg ProgramStateRef State, CheckerContext &C, 261 1.1 joerg bool IsInstanceOf) { 262 1.1 joerg const FunctionDecl *FD = Call.getDecl()->getAsFunction(); 263 1.1 joerg QualType CastFromTy = Call.parameters()[0]->getType(); 264 1.1.1.2 joerg SmallVector<QualType, 4> CastToTyVec; 265 1.1.1.2 joerg for (unsigned idx = 0; idx < FD->getTemplateSpecializationArgs()->size() - 1; 266 1.1.1.2 joerg ++idx) { 267 1.1.1.2 joerg TemplateArgument CastToTempArg = 268 1.1.1.2 joerg FD->getTemplateSpecializationArgs()->get(idx); 269 1.1.1.2 joerg switch (CastToTempArg.getKind()) { 270 1.1.1.2 joerg default: 271 1.1.1.2 joerg return; 272 1.1.1.2 joerg case TemplateArgument::Type: 273 1.1.1.2 joerg CastToTyVec.push_back(CastToTempArg.getAsType()); 274 1.1.1.2 joerg break; 275 1.1.1.2 joerg case TemplateArgument::Pack: 276 1.1.1.2 joerg for (TemplateArgument ArgInPack: CastToTempArg.pack_elements()) 277 1.1.1.2 joerg CastToTyVec.push_back(ArgInPack.getAsType()); 278 1.1.1.2 joerg break; 279 1.1.1.2 joerg } 280 1.1.1.2 joerg } 281 1.1 joerg 282 1.1 joerg const MemRegion *MR = DV.getAsRegion(); 283 1.1.1.2 joerg if (MR && CastFromTy->isReferenceType()) 284 1.1.1.2 joerg MR = State->getSVal(DV.castAs<Loc>()).getAsRegion(); 285 1.1.1.2 joerg 286 1.1.1.2 joerg bool Success = false; 287 1.1.1.2 joerg bool IsAnyKnown = false; 288 1.1.1.2 joerg for (QualType CastToTy: CastToTyVec) { 289 1.1.1.2 joerg if (CastFromTy->isPointerType()) 290 1.1.1.2 joerg CastToTy = C.getASTContext().getPointerType(CastToTy); 291 1.1.1.2 joerg else if (CastFromTy->isReferenceType()) 292 1.1.1.2 joerg CastToTy = alignReferenceTypes(CastToTy, CastFromTy, C.getASTContext()); 293 1.1.1.2 joerg else 294 1.1.1.2 joerg return; 295 1.1.1.2 joerg 296 1.1.1.2 joerg const DynamicCastInfo *CastInfo = 297 1.1 joerg getDynamicCastInfo(State, MR, CastFromTy, CastToTy); 298 1.1 joerg 299 1.1.1.2 joerg bool CastSucceeds; 300 1.1.1.2 joerg if (CastInfo) 301 1.1.1.2 joerg CastSucceeds = IsInstanceOf && CastInfo->succeeds(); 302 1.1.1.2 joerg else 303 1.1.1.2 joerg CastSucceeds = IsInstanceOf || CastFromTy == CastToTy; 304 1.1 joerg 305 1.1.1.2 joerg // Store the type and the cast information. 306 1.1.1.2 joerg bool IsKnownCast = CastInfo || CastFromTy == CastToTy; 307 1.1.1.2 joerg IsAnyKnown = IsAnyKnown || IsKnownCast; 308 1.1.1.2 joerg ProgramStateRef NewState = State; 309 1.1.1.2 joerg if (!IsKnownCast) 310 1.1.1.2 joerg NewState = setDynamicTypeAndCastInfo(State, MR, CastFromTy, CastToTy, 311 1.1.1.2 joerg IsInstanceOf); 312 1.1.1.2 joerg 313 1.1.1.2 joerg if (CastSucceeds) { 314 1.1.1.2 joerg Success = true; 315 1.1.1.2 joerg C.addTransition( 316 1.1.1.2 joerg NewState->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 317 1.1.1.2 joerg C.getSValBuilder().makeTruthVal(true)), 318 1.1.1.2 joerg getNoteTag(C, CastInfo, CastToTy, Call.getArgExpr(0), true, 319 1.1.1.2 joerg IsKnownCast)); 320 1.1.1.2 joerg if (IsKnownCast) 321 1.1.1.2 joerg return; 322 1.1.1.2 joerg } else if (CastInfo && CastInfo->succeeds()) { 323 1.1.1.2 joerg C.generateSink(NewState, C.getPredecessor()); 324 1.1.1.2 joerg return; 325 1.1.1.2 joerg } 326 1.1 joerg } 327 1.1 joerg 328 1.1.1.2 joerg if (!Success) { 329 1.1.1.2 joerg C.addTransition( 330 1.1.1.2 joerg State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), 331 1.1.1.2 joerg C.getSValBuilder().makeTruthVal(false)), 332 1.1.1.2 joerg getNoteTag(C, CastToTyVec, Call.getArgExpr(0), IsAnyKnown)); 333 1.1.1.2 joerg } 334 1.1 joerg } 335 1.1 joerg 336 1.1 joerg //===----------------------------------------------------------------------===// 337 1.1 joerg // Evaluating cast, dyn_cast, cast_or_null, dyn_cast_or_null. 338 1.1 joerg //===----------------------------------------------------------------------===// 339 1.1 joerg 340 1.1 joerg static void evalNonNullParamNonNullReturn(const CallEvent &Call, 341 1.1 joerg DefinedOrUnknownSVal DV, 342 1.1 joerg CheckerContext &C, 343 1.1 joerg bool IsCheckedCast = false) { 344 1.1 joerg addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 345 1.1 joerg /*IsNonNullReturn=*/true, IsCheckedCast); 346 1.1 joerg } 347 1.1 joerg 348 1.1 joerg static void evalNonNullParamNullReturn(const CallEvent &Call, 349 1.1 joerg DefinedOrUnknownSVal DV, 350 1.1 joerg CheckerContext &C) { 351 1.1 joerg addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 352 1.1 joerg /*IsNonNullReturn=*/false); 353 1.1 joerg } 354 1.1 joerg 355 1.1 joerg static void evalNullParamNullReturn(const CallEvent &Call, 356 1.1 joerg DefinedOrUnknownSVal DV, 357 1.1 joerg CheckerContext &C) { 358 1.1 joerg if (ProgramStateRef State = C.getState()->assume(DV, false)) 359 1.1 joerg C.addTransition(State->BindExpr(Call.getOriginExpr(), 360 1.1 joerg C.getLocationContext(), 361 1.1 joerg C.getSValBuilder().makeNull(), false), 362 1.1 joerg C.getNoteTag("Assuming null pointer is passed into cast", 363 1.1 joerg /*IsPrunable=*/true)); 364 1.1 joerg } 365 1.1 joerg 366 1.1 joerg void CastValueChecker::evalCast(const CallEvent &Call, DefinedOrUnknownSVal DV, 367 1.1 joerg CheckerContext &C) const { 368 1.1 joerg evalNonNullParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true); 369 1.1 joerg } 370 1.1 joerg 371 1.1 joerg void CastValueChecker::evalDynCast(const CallEvent &Call, 372 1.1 joerg DefinedOrUnknownSVal DV, 373 1.1 joerg CheckerContext &C) const { 374 1.1 joerg evalNonNullParamNonNullReturn(Call, DV, C); 375 1.1 joerg evalNonNullParamNullReturn(Call, DV, C); 376 1.1 joerg } 377 1.1 joerg 378 1.1 joerg void CastValueChecker::evalCastOrNull(const CallEvent &Call, 379 1.1 joerg DefinedOrUnknownSVal DV, 380 1.1 joerg CheckerContext &C) const { 381 1.1 joerg evalNonNullParamNonNullReturn(Call, DV, C); 382 1.1 joerg evalNullParamNullReturn(Call, DV, C); 383 1.1 joerg } 384 1.1 joerg 385 1.1 joerg void CastValueChecker::evalDynCastOrNull(const CallEvent &Call, 386 1.1 joerg DefinedOrUnknownSVal DV, 387 1.1 joerg CheckerContext &C) const { 388 1.1 joerg evalNonNullParamNonNullReturn(Call, DV, C); 389 1.1 joerg evalNonNullParamNullReturn(Call, DV, C); 390 1.1 joerg evalNullParamNullReturn(Call, DV, C); 391 1.1 joerg } 392 1.1 joerg 393 1.1 joerg //===----------------------------------------------------------------------===// 394 1.1 joerg // Evaluating castAs, getAs. 395 1.1 joerg //===----------------------------------------------------------------------===// 396 1.1 joerg 397 1.1 joerg static void evalZeroParamNonNullReturn(const CallEvent &Call, 398 1.1 joerg DefinedOrUnknownSVal DV, 399 1.1 joerg CheckerContext &C, 400 1.1 joerg bool IsCheckedCast = false) { 401 1.1 joerg addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 402 1.1 joerg /*IsNonNullReturn=*/true, IsCheckedCast); 403 1.1 joerg } 404 1.1 joerg 405 1.1 joerg static void evalZeroParamNullReturn(const CallEvent &Call, 406 1.1 joerg DefinedOrUnknownSVal DV, 407 1.1 joerg CheckerContext &C) { 408 1.1 joerg addCastTransition(Call, DV, C, /*IsNonNullParam=*/true, 409 1.1 joerg /*IsNonNullReturn=*/false); 410 1.1 joerg } 411 1.1 joerg 412 1.1 joerg void CastValueChecker::evalCastAs(const CallEvent &Call, 413 1.1 joerg DefinedOrUnknownSVal DV, 414 1.1 joerg CheckerContext &C) const { 415 1.1 joerg evalZeroParamNonNullReturn(Call, DV, C, /*IsCheckedCast=*/true); 416 1.1 joerg } 417 1.1 joerg 418 1.1 joerg void CastValueChecker::evalGetAs(const CallEvent &Call, DefinedOrUnknownSVal DV, 419 1.1 joerg CheckerContext &C) const { 420 1.1 joerg evalZeroParamNonNullReturn(Call, DV, C); 421 1.1 joerg evalZeroParamNullReturn(Call, DV, C); 422 1.1 joerg } 423 1.1 joerg 424 1.1 joerg //===----------------------------------------------------------------------===// 425 1.1 joerg // Evaluating isa, isa_and_nonnull. 426 1.1 joerg //===----------------------------------------------------------------------===// 427 1.1 joerg 428 1.1 joerg void CastValueChecker::evalIsa(const CallEvent &Call, DefinedOrUnknownSVal DV, 429 1.1 joerg CheckerContext &C) const { 430 1.1 joerg ProgramStateRef NonNullState, NullState; 431 1.1 joerg std::tie(NonNullState, NullState) = C.getState()->assume(DV); 432 1.1 joerg 433 1.1 joerg if (NonNullState) { 434 1.1 joerg addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true); 435 1.1 joerg addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false); 436 1.1 joerg } 437 1.1 joerg 438 1.1 joerg if (NullState) { 439 1.1 joerg C.generateSink(NullState, C.getPredecessor()); 440 1.1 joerg } 441 1.1 joerg } 442 1.1 joerg 443 1.1 joerg void CastValueChecker::evalIsaAndNonNull(const CallEvent &Call, 444 1.1 joerg DefinedOrUnknownSVal DV, 445 1.1 joerg CheckerContext &C) const { 446 1.1 joerg ProgramStateRef NonNullState, NullState; 447 1.1 joerg std::tie(NonNullState, NullState) = C.getState()->assume(DV); 448 1.1 joerg 449 1.1 joerg if (NonNullState) { 450 1.1 joerg addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/true); 451 1.1 joerg addInstanceOfTransition(Call, DV, NonNullState, C, /*IsInstanceOf=*/false); 452 1.1 joerg } 453 1.1 joerg 454 1.1 joerg if (NullState) { 455 1.1 joerg addInstanceOfTransition(Call, DV, NullState, C, /*IsInstanceOf=*/false); 456 1.1 joerg } 457 1.1 joerg } 458 1.1 joerg 459 1.1 joerg //===----------------------------------------------------------------------===// 460 1.1 joerg // Main logic to evaluate a call. 461 1.1 joerg //===----------------------------------------------------------------------===// 462 1.1 joerg 463 1.1 joerg bool CastValueChecker::evalCall(const CallEvent &Call, 464 1.1 joerg CheckerContext &C) const { 465 1.1 joerg const auto *Lookup = CDM.lookup(Call); 466 1.1 joerg if (!Lookup) 467 1.1 joerg return false; 468 1.1 joerg 469 1.1 joerg const CastCheck &Check = Lookup->first; 470 1.1 joerg CallKind Kind = Lookup->second; 471 1.1 joerg 472 1.1 joerg Optional<DefinedOrUnknownSVal> DV; 473 1.1 joerg 474 1.1 joerg switch (Kind) { 475 1.1 joerg case CallKind::Function: { 476 1.1 joerg // We only model casts from pointers to pointers or from references 477 1.1 joerg // to references. Other casts are most likely specialized and we 478 1.1 joerg // cannot model them. 479 1.1 joerg QualType ParamT = Call.parameters()[0]->getType(); 480 1.1 joerg QualType ResultT = Call.getResultType(); 481 1.1 joerg if (!(ParamT->isPointerType() && ResultT->isPointerType()) && 482 1.1.1.2 joerg !(ParamT->isReferenceType() && ResultT->isReferenceType())) { 483 1.1 joerg return false; 484 1.1.1.2 joerg } 485 1.1 joerg 486 1.1 joerg DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); 487 1.1 joerg break; 488 1.1 joerg } 489 1.1 joerg case CallKind::InstanceOf: { 490 1.1 joerg // We need to obtain the only template argument to determinte the type. 491 1.1 joerg const FunctionDecl *FD = Call.getDecl()->getAsFunction(); 492 1.1 joerg if (!FD || !FD->getTemplateSpecializationArgs()) 493 1.1 joerg return false; 494 1.1 joerg 495 1.1 joerg DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>(); 496 1.1 joerg break; 497 1.1 joerg } 498 1.1 joerg case CallKind::Method: 499 1.1 joerg const auto *InstanceCall = dyn_cast<CXXInstanceCall>(&Call); 500 1.1 joerg if (!InstanceCall) 501 1.1 joerg return false; 502 1.1 joerg 503 1.1 joerg DV = InstanceCall->getCXXThisVal().getAs<DefinedOrUnknownSVal>(); 504 1.1 joerg break; 505 1.1 joerg } 506 1.1 joerg 507 1.1 joerg if (!DV) 508 1.1 joerg return false; 509 1.1 joerg 510 1.1 joerg Check(this, Call, *DV, C); 511 1.1 joerg return true; 512 1.1 joerg } 513 1.1 joerg 514 1.1.1.2 joerg void CastValueChecker::checkDeadSymbols(SymbolReaper &SR, 515 1.1.1.2 joerg CheckerContext &C) const { 516 1.1.1.2 joerg C.addTransition(removeDeadCasts(C.getState(), SR)); 517 1.1.1.2 joerg } 518 1.1.1.2 joerg 519 1.1 joerg void ento::registerCastValueChecker(CheckerManager &Mgr) { 520 1.1 joerg Mgr.registerChecker<CastValueChecker>(); 521 1.1 joerg } 522 1.1 joerg 523 1.1.1.2 joerg bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) { 524 1.1 joerg return true; 525 1.1 joerg } 526