MallocChecker.cpp revision 697462881c4b9b704c7859f4bab0a6116c684bb1
1//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines malloc/free checker, which checks for potential memory 11// leaks, double free, and use-after-free problems. 12// 13//===----------------------------------------------------------------------===// 14 15#include "ClangSACheckers.h" 16#include "InterCheckerAPI.h" 17#include "clang/AST/Attr.h" 18#include "clang/Basic/SourceManager.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20#include "clang/StaticAnalyzer/Core/Checker.h" 21#include "clang/StaticAnalyzer/Core/CheckerManager.h" 22#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 23#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 24#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 25#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 26#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" 27#include "llvm/ADT/ImmutableMap.h" 28#include "llvm/ADT/STLExtras.h" 29#include "llvm/ADT/SmallString.h" 30#include "llvm/ADT/StringExtras.h" 31#include <climits> 32 33using namespace clang; 34using namespace ento; 35 36namespace { 37 38class RefState { 39 enum Kind { // Reference to allocated memory. 40 Allocated, 41 // Reference to released/freed memory. 42 Released, 43 // The responsibility for freeing resources has transfered from 44 // this reference. A relinquished symbol should not be freed. 45 Relinquished } K; 46 const Stmt *S; 47 48public: 49 RefState(Kind k, const Stmt *s) : K(k), S(s) {} 50 51 bool isAllocated() const { return K == Allocated; } 52 bool isReleased() const { return K == Released; } 53 bool isRelinquished() const { return K == Relinquished; } 54 55 const Stmt *getStmt() const { return S; } 56 57 bool operator==(const RefState &X) const { 58 return K == X.K && S == X.S; 59 } 60 61 static RefState getAllocated(const Stmt *s) { 62 return RefState(Allocated, s); 63 } 64 static RefState getReleased(const Stmt *s) { return RefState(Released, s); } 65 static RefState getRelinquished(const Stmt *s) { 66 return RefState(Relinquished, s); 67 } 68 69 void Profile(llvm::FoldingSetNodeID &ID) const { 70 ID.AddInteger(K); 71 ID.AddPointer(S); 72 } 73 74 void dump(raw_ostream &OS) const { 75 static const char *Table[] = { 76 "Allocated", 77 "Released", 78 "Relinquished" 79 }; 80 OS << Table[(unsigned) K]; 81 } 82 83 LLVM_ATTRIBUTE_USED void dump() const { 84 dump(llvm::errs()); 85 } 86}; 87 88enum ReallocPairKind { 89 RPToBeFreedAfterFailure, 90 // The symbol has been freed when reallocation failed. 91 RPIsFreeOnFailure, 92 // The symbol does not need to be freed after reallocation fails. 93 RPDoNotTrackAfterFailure 94}; 95 96/// \class ReallocPair 97/// \brief Stores information about the symbol being reallocated by a call to 98/// 'realloc' to allow modeling failed reallocation later in the path. 99struct ReallocPair { 100 // \brief The symbol which realloc reallocated. 101 SymbolRef ReallocatedSym; 102 ReallocPairKind Kind; 103 104 ReallocPair(SymbolRef S, ReallocPairKind K) : 105 ReallocatedSym(S), Kind(K) {} 106 void Profile(llvm::FoldingSetNodeID &ID) const { 107 ID.AddInteger(Kind); 108 ID.AddPointer(ReallocatedSym); 109 } 110 bool operator==(const ReallocPair &X) const { 111 return ReallocatedSym == X.ReallocatedSym && 112 Kind == X.Kind; 113 } 114}; 115 116typedef std::pair<const ExplodedNode*, const MemRegion*> LeakInfo; 117 118class MallocChecker : public Checker<check::DeadSymbols, 119 check::PointerEscape, 120 check::PreStmt<ReturnStmt>, 121 check::PreStmt<CallExpr>, 122 check::PostStmt<CallExpr>, 123 check::PostStmt<CXXNewExpr>, 124 check::PreStmt<CXXDeleteExpr>, 125 check::PostStmt<BlockExpr>, 126 check::PostObjCMessage, 127 check::Location, 128 eval::Assume> 129{ 130 mutable OwningPtr<BugType> BT_DoubleFree; 131 mutable OwningPtr<BugType> BT_Leak; 132 mutable OwningPtr<BugType> BT_UseFree; 133 mutable OwningPtr<BugType> BT_BadFree; 134 mutable OwningPtr<BugType> BT_OffsetFree; 135 mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc, 136 *II_valloc, *II_reallocf, *II_strndup, *II_strdup; 137 138public: 139 MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0), 140 II_valloc(0), II_reallocf(0), II_strndup(0), II_strdup(0) {} 141 142 /// In pessimistic mode, the checker assumes that it does not know which 143 /// functions might free the memory. 144 struct ChecksFilter { 145 DefaultBool CMallocPessimistic; 146 DefaultBool CMallocOptimistic; 147 DefaultBool CNewDeleteChecker; 148 }; 149 150 ChecksFilter Filter; 151 152 void checkPreStmt(const CallExpr *S, CheckerContext &C) const; 153 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 154 void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const; 155 void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; 156 void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const; 157 void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; 158 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 159 void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; 160 ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, 161 bool Assumption) const; 162 void checkLocation(SVal l, bool isLoad, const Stmt *S, 163 CheckerContext &C) const; 164 165 ProgramStateRef checkPointerEscape(ProgramStateRef State, 166 const InvalidatedSymbols &Escaped, 167 const CallEvent *Call, 168 PointerEscapeKind Kind) const; 169 170 void printState(raw_ostream &Out, ProgramStateRef State, 171 const char *NL, const char *Sep) const; 172 173private: 174 void initIdentifierInfo(ASTContext &C) const; 175 176 ///@{ 177 /// Check if this is one of the functions which can allocate/reallocate memory 178 /// pointed to by one of its arguments. 179 bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const; 180 bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const; 181 bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const; 182 bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const; 183 ///@} 184 static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, 185 const CallExpr *CE, 186 const OwnershipAttr* Att); 187 static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, 188 const Expr *SizeEx, SVal Init, 189 ProgramStateRef state) { 190 return MallocMemAux(C, CE, 191 state->getSVal(SizeEx, C.getLocationContext()), 192 Init, state); 193 } 194 195 static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, 196 SVal SizeEx, SVal Init, 197 ProgramStateRef state); 198 199 /// Update the RefState to reflect the new memory allocation. 200 static ProgramStateRef MallocUpdateRefState(CheckerContext &C, 201 const Expr *E, 202 ProgramStateRef state); 203 204 ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE, 205 const OwnershipAttr* Att) const; 206 ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE, 207 ProgramStateRef state, unsigned Num, 208 bool Hold, 209 bool &ReleasedAllocated, 210 bool ReturnsNullOnFailure = false) const; 211 ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg, 212 const Expr *ParentExpr, 213 ProgramStateRef State, 214 bool Hold, 215 bool &ReleasedAllocated, 216 bool ReturnsNullOnFailure = false) const; 217 218 ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE, 219 bool FreesMemOnFailure) const; 220 static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE); 221 222 ///\brief Check if the memory associated with this symbol was released. 223 bool isReleased(SymbolRef Sym, CheckerContext &C) const; 224 225 bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; 226 227 /// Check if the function is known not to free memory, or if it is 228 /// "interesting" and should be modeled explicitly. 229 /// 230 /// We assume that pointers do not escape through calls to system functions 231 /// not handled by this checker. 232 bool doesNotFreeMemOrInteresting(const CallEvent *Call, 233 ProgramStateRef State) const; 234 235 static bool SummarizeValue(raw_ostream &os, SVal V); 236 static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); 237 void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range) const; 238 void ReportBadDealloc(CheckerContext &C, SourceRange Range, 239 const Expr *DeallocExpr, const RefState *RS) const; 240 void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range)const; 241 void ReportUseAfterFree(CheckerContext &C, SourceRange Range, 242 SymbolRef Sym) const; 243 void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released, 244 SymbolRef Sym, SymbolRef PrevSym) const; 245 246 /// Find the location of the allocation for Sym on the path leading to the 247 /// exploded node N. 248 LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, 249 CheckerContext &C) const; 250 251 void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; 252 253 /// The bug visitor which allows us to print extra diagnostics along the 254 /// BugReport path. For example, showing the allocation site of the leaked 255 /// region. 256 class MallocBugVisitor : public BugReporterVisitorImpl<MallocBugVisitor> { 257 protected: 258 enum NotificationMode { 259 Normal, 260 ReallocationFailed 261 }; 262 263 // The allocated region symbol tracked by the main analysis. 264 SymbolRef Sym; 265 266 // The mode we are in, i.e. what kind of diagnostics will be emitted. 267 NotificationMode Mode; 268 269 // A symbol from when the primary region should have been reallocated. 270 SymbolRef FailedReallocSymbol; 271 272 bool IsLeak; 273 274 public: 275 MallocBugVisitor(SymbolRef S, bool isLeak = false) 276 : Sym(S), Mode(Normal), FailedReallocSymbol(0), IsLeak(isLeak) {} 277 278 virtual ~MallocBugVisitor() {} 279 280 void Profile(llvm::FoldingSetNodeID &ID) const { 281 static int X = 0; 282 ID.AddPointer(&X); 283 ID.AddPointer(Sym); 284 } 285 286 inline bool isAllocated(const RefState *S, const RefState *SPrev, 287 const Stmt *Stmt) { 288 // Did not track -> allocated. Other state (released) -> allocated. 289 return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) && 290 (S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated())); 291 } 292 293 inline bool isReleased(const RefState *S, const RefState *SPrev, 294 const Stmt *Stmt) { 295 // Did not track -> released. Other state (allocated) -> released. 296 return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt)) && 297 (S && S->isReleased()) && (!SPrev || !SPrev->isReleased())); 298 } 299 300 inline bool isRelinquished(const RefState *S, const RefState *SPrev, 301 const Stmt *Stmt) { 302 // Did not track -> relinquished. Other state (allocated) -> relinquished. 303 return (Stmt && (isa<CallExpr>(Stmt) || isa<ObjCMessageExpr>(Stmt) || 304 isa<ObjCPropertyRefExpr>(Stmt)) && 305 (S && S->isRelinquished()) && 306 (!SPrev || !SPrev->isRelinquished())); 307 } 308 309 inline bool isReallocFailedCheck(const RefState *S, const RefState *SPrev, 310 const Stmt *Stmt) { 311 // If the expression is not a call, and the state change is 312 // released -> allocated, it must be the realloc return value 313 // check. If we have to handle more cases here, it might be cleaner just 314 // to track this extra bit in the state itself. 315 return ((!Stmt || !isa<CallExpr>(Stmt)) && 316 (S && S->isAllocated()) && (SPrev && !SPrev->isAllocated())); 317 } 318 319 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 320 const ExplodedNode *PrevN, 321 BugReporterContext &BRC, 322 BugReport &BR); 323 324 PathDiagnosticPiece* getEndPath(BugReporterContext &BRC, 325 const ExplodedNode *EndPathNode, 326 BugReport &BR) { 327 if (!IsLeak) 328 return 0; 329 330 PathDiagnosticLocation L = 331 PathDiagnosticLocation::createEndOfPath(EndPathNode, 332 BRC.getSourceManager()); 333 // Do not add the statement itself as a range in case of leak. 334 return new PathDiagnosticEventPiece(L, BR.getDescription(), false); 335 } 336 337 private: 338 class StackHintGeneratorForReallocationFailed 339 : public StackHintGeneratorForSymbol { 340 public: 341 StackHintGeneratorForReallocationFailed(SymbolRef S, StringRef M) 342 : StackHintGeneratorForSymbol(S, M) {} 343 344 virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) { 345 // Printed parameters start at 1, not 0. 346 ++ArgIndex; 347 348 SmallString<200> buf; 349 llvm::raw_svector_ostream os(buf); 350 351 os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) 352 << " parameter failed"; 353 354 return os.str(); 355 } 356 357 virtual std::string getMessageForReturn(const CallExpr *CallExpr) { 358 return "Reallocation of returned value failed"; 359 } 360 }; 361 }; 362}; 363} // end anonymous namespace 364 365REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState) 366REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) 367 368// A map from the freed symbol to the symbol representing the return value of 369// the free function. 370REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef) 371 372namespace { 373class StopTrackingCallback : public SymbolVisitor { 374 ProgramStateRef state; 375public: 376 StopTrackingCallback(ProgramStateRef st) : state(st) {} 377 ProgramStateRef getState() const { return state; } 378 379 bool VisitSymbol(SymbolRef sym) { 380 state = state->remove<RegionState>(sym); 381 return true; 382 } 383}; 384} // end anonymous namespace 385 386void MallocChecker::initIdentifierInfo(ASTContext &Ctx) const { 387 if (II_malloc) 388 return; 389 II_malloc = &Ctx.Idents.get("malloc"); 390 II_free = &Ctx.Idents.get("free"); 391 II_realloc = &Ctx.Idents.get("realloc"); 392 II_reallocf = &Ctx.Idents.get("reallocf"); 393 II_calloc = &Ctx.Idents.get("calloc"); 394 II_valloc = &Ctx.Idents.get("valloc"); 395 II_strdup = &Ctx.Idents.get("strdup"); 396 II_strndup = &Ctx.Idents.get("strndup"); 397} 398 399bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const { 400 if (isFreeFunction(FD, C)) 401 return true; 402 403 if (isAllocationFunction(FD, C)) 404 return true; 405 406 if (isStandardNewDelete(FD, C)) 407 return true; 408 409 return false; 410} 411 412bool MallocChecker::isAllocationFunction(const FunctionDecl *FD, 413 ASTContext &C) const { 414 if (!FD) 415 return false; 416 417 if (FD->getKind() == Decl::Function) { 418 IdentifierInfo *FunI = FD->getIdentifier(); 419 initIdentifierInfo(C); 420 421 if (FunI == II_malloc || FunI == II_realloc || 422 FunI == II_reallocf || FunI == II_calloc || FunI == II_valloc || 423 FunI == II_strdup || FunI == II_strndup) 424 return true; 425 } 426 427 if (Filter.CMallocOptimistic && FD->hasAttrs()) 428 for (specific_attr_iterator<OwnershipAttr> 429 i = FD->specific_attr_begin<OwnershipAttr>(), 430 e = FD->specific_attr_end<OwnershipAttr>(); 431 i != e; ++i) 432 if ((*i)->getOwnKind() == OwnershipAttr::Returns) 433 return true; 434 return false; 435} 436 437bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const { 438 if (!FD) 439 return false; 440 441 if (FD->getKind() == Decl::Function) { 442 IdentifierInfo *FunI = FD->getIdentifier(); 443 initIdentifierInfo(C); 444 445 if (FunI == II_free || FunI == II_realloc || FunI == II_reallocf) 446 return true; 447 } 448 449 if (Filter.CMallocOptimistic && FD->hasAttrs()) 450 for (specific_attr_iterator<OwnershipAttr> 451 i = FD->specific_attr_begin<OwnershipAttr>(), 452 e = FD->specific_attr_end<OwnershipAttr>(); 453 i != e; ++i) 454 if ((*i)->getOwnKind() == OwnershipAttr::Takes || 455 (*i)->getOwnKind() == OwnershipAttr::Holds) 456 return true; 457 return false; 458} 459 460// Tells if the callee is one of the following: 461// 1) A global non-placement new/delete operator function. 462// 2) A global placement operator function with the single placement argument 463// of type std::nothrow_t. 464bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD, 465 ASTContext &C) const { 466 if (!FD) 467 return false; 468 469 OverloadedOperatorKind Kind = FD->getOverloadedOperator(); 470 if (Kind != OO_New && Kind != OO_Array_New && 471 Kind != OO_Delete && Kind != OO_Array_Delete) 472 return false; 473 474 // Skip all operator new/delete methods. 475 if (isa<CXXMethodDecl>(FD)) 476 return false; 477 478 // Return true if tested operator is a standard placement nothrow operator. 479 if (FD->getNumParams() == 2) { 480 QualType T = FD->getParamDecl(1)->getType(); 481 if (const IdentifierInfo *II = T.getBaseTypeIdentifier()) 482 return II->getName().equals("nothrow_t"); 483 } 484 485 // Skip placement operators. 486 if (FD->getNumParams() != 1 || FD->isVariadic()) 487 return false; 488 489 // One of the standard new/new[]/delete/delete[] non-placement operators. 490 return true; 491} 492 493void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { 494 if (C.wasInlined) 495 return; 496 497 const FunctionDecl *FD = C.getCalleeDecl(CE); 498 if (!FD) 499 return; 500 501 ProgramStateRef State = C.getState(); 502 bool ReleasedAllocatedMemory = false; 503 504 if (FD->getKind() == Decl::Function) { 505 initIdentifierInfo(C.getASTContext()); 506 IdentifierInfo *FunI = FD->getIdentifier(); 507 508 if (Filter.CMallocOptimistic || Filter.CMallocPessimistic) { 509 if (FunI == II_malloc || FunI == II_valloc) { 510 if (CE->getNumArgs() < 1) 511 return; 512 State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); 513 } else if (FunI == II_realloc) { 514 State = ReallocMem(C, CE, false); 515 } else if (FunI == II_reallocf) { 516 State = ReallocMem(C, CE, true); 517 } else if (FunI == II_calloc) { 518 State = CallocMem(C, CE); 519 } else if (FunI == II_free) { 520 State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); 521 } else if (FunI == II_strdup) { 522 State = MallocUpdateRefState(C, CE, State); 523 } else if (FunI == II_strndup) { 524 State = MallocUpdateRefState(C, CE, State); 525 } 526 } 527 528 if (Filter.CNewDeleteChecker) { 529 if (isStandardNewDelete(FD, C.getASTContext())) { 530 // Process direct calls to operator new/new[]/delete/delete[] functions 531 // as distinct from new/new[]/delete/delete[] expressions that are 532 // processed by the checkPostStmt callbacks for CXXNewExpr and 533 // CXXDeleteExpr. 534 OverloadedOperatorKind K = FD->getOverloadedOperator(); 535 if (K == OO_New) 536 State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); 537 else if (K == OO_Array_New) 538 State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); 539 else if (K == OO_Delete || K == OO_Array_Delete) 540 State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); 541 else 542 llvm_unreachable("not a new/delete operator"); 543 } 544 } 545 } 546 547 if (Filter.CMallocOptimistic) { 548 // Check all the attributes, if there are any. 549 // There can be multiple of these attributes. 550 if (FD->hasAttrs()) 551 for (specific_attr_iterator<OwnershipAttr> 552 i = FD->specific_attr_begin<OwnershipAttr>(), 553 e = FD->specific_attr_end<OwnershipAttr>(); 554 i != e; ++i) { 555 switch ((*i)->getOwnKind()) { 556 case OwnershipAttr::Returns: 557 State = MallocMemReturnsAttr(C, CE, *i); 558 break; 559 case OwnershipAttr::Takes: 560 case OwnershipAttr::Holds: 561 State = FreeMemAttr(C, CE, *i); 562 break; 563 } 564 } 565 } 566 C.addTransition(State); 567} 568 569void MallocChecker::checkPostStmt(const CXXNewExpr *NE, 570 CheckerContext &C) const { 571 572 if (NE->getNumPlacementArgs()) 573 for (CXXNewExpr::const_arg_iterator I = NE->placement_arg_begin(), 574 E = NE->placement_arg_end(); I != E; ++I) 575 if (SymbolRef Sym = C.getSVal(*I).getAsSymbol()) 576 checkUseAfterFree(Sym, C, *I); 577 578 if (!Filter.CNewDeleteChecker) 579 return; 580 581 if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext())) 582 return; 583 584 ProgramStateRef State = C.getState(); 585 // The return value from operator new is bound to a specified initialization 586 // value (if any) and we don't want to loose this value. So we call 587 // MallocUpdateRefState() instead of MallocMemAux() which breakes the 588 // existing binding. 589 State = MallocUpdateRefState(C, NE, State); 590 C.addTransition(State); 591} 592 593void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE, 594 CheckerContext &C) const { 595 596 if (!Filter.CNewDeleteChecker) { 597 if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol()) 598 checkUseAfterFree(Sym, C, DE->getArgument()); 599 600 return; 601 } 602 603 if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext())) 604 return; 605 606 ProgramStateRef State = C.getState(); 607 bool ReleasedAllocated; 608 State = FreeMemAux(C, DE->getArgument(), DE, State, 609 /*Hold*/false, ReleasedAllocated); 610 611 C.addTransition(State); 612} 613 614static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) { 615 // If the first selector piece is one of the names below, assume that the 616 // object takes ownership of the memory, promising to eventually deallocate it 617 // with free(). 618 // Ex: [NSData dataWithBytesNoCopy:bytes length:10]; 619 // (...unless a 'freeWhenDone' parameter is false, but that's checked later.) 620 StringRef FirstSlot = Call.getSelector().getNameForSlot(0); 621 if (FirstSlot == "dataWithBytesNoCopy" || 622 FirstSlot == "initWithBytesNoCopy" || 623 FirstSlot == "initWithCharactersNoCopy") 624 return true; 625 626 return false; 627} 628 629static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) { 630 Selector S = Call.getSelector(); 631 632 // FIXME: We should not rely on fully-constrained symbols being folded. 633 for (unsigned i = 1; i < S.getNumArgs(); ++i) 634 if (S.getNameForSlot(i).equals("freeWhenDone")) 635 return !Call.getArgSVal(i).isZeroConstant(); 636 637 return None; 638} 639 640void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, 641 CheckerContext &C) const { 642 if (C.wasInlined) 643 return; 644 645 if (!isKnownDeallocObjCMethodName(Call)) 646 return; 647 648 if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call)) 649 if (!*FreeWhenDone) 650 return; 651 652 bool ReleasedAllocatedMemory; 653 ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), 654 Call.getOriginExpr(), C.getState(), 655 /*Hold=*/true, ReleasedAllocatedMemory, 656 /*RetNullOnFailure=*/true); 657 658 C.addTransition(State); 659} 660 661ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C, 662 const CallExpr *CE, 663 const OwnershipAttr* Att) { 664 if (Att->getModule() != "malloc") 665 return 0; 666 667 OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); 668 if (I != E) { 669 return MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState()); 670 } 671 return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), C.getState()); 672} 673 674ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, 675 const CallExpr *CE, 676 SVal Size, SVal Init, 677 ProgramStateRef state) { 678 679 // Bind the return value to the symbolic value from the heap region. 680 // TODO: We could rewrite post visit to eval call; 'malloc' does not have 681 // side effects other than what we model here. 682 unsigned Count = C.blockCount(); 683 SValBuilder &svalBuilder = C.getSValBuilder(); 684 const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); 685 DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count) 686 .castAs<DefinedSVal>(); 687 state = state->BindExpr(CE, C.getLocationContext(), RetVal); 688 689 // We expect the malloc functions to return a pointer. 690 if (!RetVal.getAs<Loc>()) 691 return 0; 692 693 // Fill the region with the initialization value. 694 state = state->bindDefault(RetVal, Init); 695 696 // Set the region's extent equal to the Size parameter. 697 const SymbolicRegion *R = 698 dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion()); 699 if (!R) 700 return 0; 701 if (Optional<DefinedOrUnknownSVal> DefinedSize = 702 Size.getAs<DefinedOrUnknownSVal>()) { 703 SValBuilder &svalBuilder = C.getSValBuilder(); 704 DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); 705 DefinedOrUnknownSVal extentMatchesSize = 706 svalBuilder.evalEQ(state, Extent, *DefinedSize); 707 708 state = state->assume(extentMatchesSize, true); 709 assert(state); 710 } 711 712 return MallocUpdateRefState(C, CE, state); 713} 714 715ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C, 716 const Expr *E, 717 ProgramStateRef state) { 718 // Get the return value. 719 SVal retVal = state->getSVal(E, C.getLocationContext()); 720 721 // We expect the malloc functions to return a pointer. 722 if (!retVal.getAs<Loc>()) 723 return 0; 724 725 SymbolRef Sym = retVal.getAsLocSymbol(); 726 assert(Sym); 727 728 // Set the symbol's state to Allocated. 729 return state->set<RegionState>(Sym, RefState::getAllocated(E)); 730 731} 732 733ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, 734 const CallExpr *CE, 735 const OwnershipAttr* Att) const { 736 if (Att->getModule() != "malloc") 737 return 0; 738 739 ProgramStateRef State = C.getState(); 740 bool ReleasedAllocated = false; 741 742 for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); 743 I != E; ++I) { 744 ProgramStateRef StateI = FreeMemAux(C, CE, State, *I, 745 Att->getOwnKind() == OwnershipAttr::Holds, 746 ReleasedAllocated); 747 if (StateI) 748 State = StateI; 749 } 750 return State; 751} 752 753ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, 754 const CallExpr *CE, 755 ProgramStateRef state, 756 unsigned Num, 757 bool Hold, 758 bool &ReleasedAllocated, 759 bool ReturnsNullOnFailure) const { 760 if (CE->getNumArgs() < (Num + 1)) 761 return 0; 762 763 return FreeMemAux(C, CE->getArg(Num), CE, state, Hold, 764 ReleasedAllocated, ReturnsNullOnFailure); 765} 766 767/// Checks if the previous call to free on the given symbol failed - if free 768/// failed, returns true. Also, returns the corresponding return value symbol. 769static bool didPreviousFreeFail(ProgramStateRef State, 770 SymbolRef Sym, SymbolRef &RetStatusSymbol) { 771 const SymbolRef *Ret = State->get<FreeReturnValue>(Sym); 772 if (Ret) { 773 assert(*Ret && "We should not store the null return symbol"); 774 ConstraintManager &CMgr = State->getConstraintManager(); 775 ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret); 776 RetStatusSymbol = *Ret; 777 return FreeFailed.isConstrainedTrue(); 778 } 779 return false; 780} 781 782ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, 783 const Expr *ArgExpr, 784 const Expr *ParentExpr, 785 ProgramStateRef State, 786 bool Hold, 787 bool &ReleasedAllocated, 788 bool ReturnsNullOnFailure) const { 789 790 SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext()); 791 if (!ArgVal.getAs<DefinedOrUnknownSVal>()) 792 return 0; 793 DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>(); 794 795 // Check for null dereferences. 796 if (!location.getAs<Loc>()) 797 return 0; 798 799 // The explicit NULL case, no operation is performed. 800 ProgramStateRef notNullState, nullState; 801 llvm::tie(notNullState, nullState) = State->assume(location); 802 if (nullState && !notNullState) 803 return 0; 804 805 // Unknown values could easily be okay 806 // Undefined values are handled elsewhere 807 if (ArgVal.isUnknownOrUndef()) 808 return 0; 809 810 const MemRegion *R = ArgVal.getAsRegion(); 811 812 // Nonlocs can't be freed, of course. 813 // Non-region locations (labels and fixed addresses) also shouldn't be freed. 814 if (!R) { 815 ReportBadFree(C, ArgVal, ArgExpr->getSourceRange()); 816 return 0; 817 } 818 819 R = R->StripCasts(); 820 821 // Blocks might show up as heap data, but should not be free()d 822 if (isa<BlockDataRegion>(R)) { 823 ReportBadFree(C, ArgVal, ArgExpr->getSourceRange()); 824 return 0; 825 } 826 827 const MemSpaceRegion *MS = R->getMemorySpace(); 828 829 // Parameters, locals, statics, globals, and memory returned by alloca() 830 // shouldn't be freed. 831 if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) { 832 // FIXME: at the time this code was written, malloc() regions were 833 // represented by conjured symbols, which are all in UnknownSpaceRegion. 834 // This means that there isn't actually anything from HeapSpaceRegion 835 // that should be freed, even though we allow it here. 836 // Of course, free() can work on memory allocated outside the current 837 // function, so UnknownSpaceRegion is always a possibility. 838 // False negatives are better than false positives. 839 840 ReportBadFree(C, ArgVal, ArgExpr->getSourceRange()); 841 return 0; 842 } 843 844 const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion()); 845 // Various cases could lead to non-symbol values here. 846 // For now, ignore them. 847 if (!SrBase) 848 return 0; 849 850 SymbolRef SymBase = SrBase->getSymbol(); 851 const RefState *RsBase = State->get<RegionState>(SymBase); 852 SymbolRef PreviousRetStatusSymbol = 0; 853 854 // Check double free. 855 if (RsBase && 856 (RsBase->isReleased() || RsBase->isRelinquished()) && 857 !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { 858 ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), 859 SymBase, PreviousRetStatusSymbol); 860 return 0; 861 } 862 863 // Check if the memory location being freed is the actual location 864 // allocated, or an offset. 865 RegionOffset Offset = R->getAsOffset(); 866 if (RsBase && RsBase->isAllocated() && 867 Offset.isValid() && 868 !Offset.hasSymbolicOffset() && 869 Offset.getOffset() != 0) { 870 ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange()); 871 return 0; 872 } 873 874 ReleasedAllocated = (RsBase != 0); 875 876 // Clean out the info on previous call to free return info. 877 State = State->remove<FreeReturnValue>(SymBase); 878 879 // Keep track of the return value. If it is NULL, we will know that free 880 // failed. 881 if (ReturnsNullOnFailure) { 882 SVal RetVal = C.getSVal(ParentExpr); 883 SymbolRef RetStatusSymbol = RetVal.getAsSymbol(); 884 if (RetStatusSymbol) { 885 C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol); 886 State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol); 887 } 888 } 889 890 // Normal free. 891 if (Hold) { 892 return State->set<RegionState>(SymBase, 893 RefState::getRelinquished(ParentExpr)); 894 } 895 return State->set<RegionState>(SymBase, RefState::getReleased(ParentExpr)); 896} 897 898bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { 899 if (Optional<nonloc::ConcreteInt> IntVal = V.getAs<nonloc::ConcreteInt>()) 900 os << "an integer (" << IntVal->getValue() << ")"; 901 else if (Optional<loc::ConcreteInt> ConstAddr = V.getAs<loc::ConcreteInt>()) 902 os << "a constant address (" << ConstAddr->getValue() << ")"; 903 else if (Optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>()) 904 os << "the address of the label '" << Label->getLabel()->getName() << "'"; 905 else 906 return false; 907 908 return true; 909} 910 911bool MallocChecker::SummarizeRegion(raw_ostream &os, 912 const MemRegion *MR) { 913 switch (MR->getKind()) { 914 case MemRegion::FunctionTextRegionKind: { 915 const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); 916 if (FD) 917 os << "the address of the function '" << *FD << '\''; 918 else 919 os << "the address of a function"; 920 return true; 921 } 922 case MemRegion::BlockTextRegionKind: 923 os << "block text"; 924 return true; 925 case MemRegion::BlockDataRegionKind: 926 // FIXME: where the block came from? 927 os << "a block"; 928 return true; 929 default: { 930 const MemSpaceRegion *MS = MR->getMemorySpace(); 931 932 if (isa<StackLocalsSpaceRegion>(MS)) { 933 const VarRegion *VR = dyn_cast<VarRegion>(MR); 934 const VarDecl *VD; 935 if (VR) 936 VD = VR->getDecl(); 937 else 938 VD = NULL; 939 940 if (VD) 941 os << "the address of the local variable '" << VD->getName() << "'"; 942 else 943 os << "the address of a local stack variable"; 944 return true; 945 } 946 947 if (isa<StackArgumentsSpaceRegion>(MS)) { 948 const VarRegion *VR = dyn_cast<VarRegion>(MR); 949 const VarDecl *VD; 950 if (VR) 951 VD = VR->getDecl(); 952 else 953 VD = NULL; 954 955 if (VD) 956 os << "the address of the parameter '" << VD->getName() << "'"; 957 else 958 os << "the address of a parameter"; 959 return true; 960 } 961 962 if (isa<GlobalsSpaceRegion>(MS)) { 963 const VarRegion *VR = dyn_cast<VarRegion>(MR); 964 const VarDecl *VD; 965 if (VR) 966 VD = VR->getDecl(); 967 else 968 VD = NULL; 969 970 if (VD) { 971 if (VD->isStaticLocal()) 972 os << "the address of the static variable '" << VD->getName() << "'"; 973 else 974 os << "the address of the global variable '" << VD->getName() << "'"; 975 } else 976 os << "the address of a global variable"; 977 return true; 978 } 979 980 return false; 981 } 982 } 983} 984 985void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, 986 SourceRange Range) const { 987 if (ExplodedNode *N = C.generateSink()) { 988 if (!BT_BadFree) 989 BT_BadFree.reset(new BugType("Bad free", "Memory Error")); 990 991 SmallString<100> buf; 992 llvm::raw_svector_ostream os(buf); 993 994 const MemRegion *MR = ArgVal.getAsRegion(); 995 if (MR) { 996 while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR)) 997 MR = ER->getSuperRegion(); 998 999 // Special case for alloca() 1000 if (isa<AllocaRegion>(MR)) 1001 os << "Argument to free() was allocated by alloca(), not malloc()"; 1002 else { 1003 os << "Argument to free() is "; 1004 if (SummarizeRegion(os, MR)) 1005 os << ", which is not memory allocated by malloc()"; 1006 else 1007 os << "not memory allocated by malloc()"; 1008 } 1009 } else { 1010 os << "Argument to free() is "; 1011 if (SummarizeValue(os, ArgVal)) 1012 os << ", which is not memory allocated by malloc()"; 1013 else 1014 os << "not memory allocated by malloc()"; 1015 } 1016 1017 BugReport *R = new BugReport(*BT_BadFree, os.str(), N); 1018 R->markInteresting(MR); 1019 R->addRange(Range); 1020 C.emitReport(R); 1021 } 1022} 1023 1024void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, 1025 SourceRange Range) const { 1026 ExplodedNode *N = C.generateSink(); 1027 if (N == NULL) 1028 return; 1029 1030 if (!BT_OffsetFree) 1031 BT_OffsetFree.reset(new BugType("Offset free", "Memory Error")); 1032 1033 SmallString<100> buf; 1034 llvm::raw_svector_ostream os(buf); 1035 1036 const MemRegion *MR = ArgVal.getAsRegion(); 1037 assert(MR && "Only MemRegion based symbols can have offset free errors"); 1038 1039 RegionOffset Offset = MR->getAsOffset(); 1040 assert((Offset.isValid() && 1041 !Offset.hasSymbolicOffset() && 1042 Offset.getOffset() != 0) && 1043 "Only symbols with a valid offset can have offset free errors"); 1044 1045 int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth(); 1046 1047 os << "Argument to free() is offset by " 1048 << offsetBytes 1049 << " " 1050 << ((abs(offsetBytes) > 1) ? "bytes" : "byte") 1051 << " from the start of memory allocated by malloc()"; 1052 1053 BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N); 1054 R->markInteresting(MR->getBaseRegion()); 1055 R->addRange(Range); 1056 C.emitReport(R); 1057} 1058 1059void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, 1060 SymbolRef Sym) const { 1061 1062 if (ExplodedNode *N = C.generateSink()) { 1063 if (!BT_UseFree) 1064 BT_UseFree.reset(new BugType("Use-after-free", "Memory Error")); 1065 1066 BugReport *R = new BugReport(*BT_UseFree, 1067 "Use of memory after it is freed", N); 1068 1069 R->markInteresting(Sym); 1070 R->addRange(Range); 1071 R->addVisitor(new MallocBugVisitor(Sym)); 1072 C.emitReport(R); 1073 } 1074} 1075 1076void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, 1077 bool Released, SymbolRef Sym, 1078 SymbolRef PrevSym) const { 1079 1080 if (ExplodedNode *N = C.generateSink()) { 1081 if (!BT_DoubleFree) 1082 BT_DoubleFree.reset(new BugType("Double free", "Memory Error")); 1083 1084 BugReport *R = new BugReport(*BT_DoubleFree, 1085 (Released ? "Attempt to free released memory" 1086 : "Attempt to free non-owned memory"), 1087 N); 1088 R->addRange(Range); 1089 R->markInteresting(Sym); 1090 if (PrevSym) 1091 R->markInteresting(PrevSym); 1092 R->addVisitor(new MallocBugVisitor(Sym)); 1093 C.emitReport(R); 1094 } 1095} 1096 1097ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, 1098 const CallExpr *CE, 1099 bool FreesOnFail) const { 1100 if (CE->getNumArgs() < 2) 1101 return 0; 1102 1103 ProgramStateRef state = C.getState(); 1104 const Expr *arg0Expr = CE->getArg(0); 1105 const LocationContext *LCtx = C.getLocationContext(); 1106 SVal Arg0Val = state->getSVal(arg0Expr, LCtx); 1107 if (!Arg0Val.getAs<DefinedOrUnknownSVal>()) 1108 return 0; 1109 DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>(); 1110 1111 SValBuilder &svalBuilder = C.getSValBuilder(); 1112 1113 DefinedOrUnknownSVal PtrEQ = 1114 svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull()); 1115 1116 // Get the size argument. If there is no size arg then give up. 1117 const Expr *Arg1 = CE->getArg(1); 1118 if (!Arg1) 1119 return 0; 1120 1121 // Get the value of the size argument. 1122 SVal Arg1ValG = state->getSVal(Arg1, LCtx); 1123 if (!Arg1ValG.getAs<DefinedOrUnknownSVal>()) 1124 return 0; 1125 DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>(); 1126 1127 // Compare the size argument to 0. 1128 DefinedOrUnknownSVal SizeZero = 1129 svalBuilder.evalEQ(state, Arg1Val, 1130 svalBuilder.makeIntValWithPtrWidth(0, false)); 1131 1132 ProgramStateRef StatePtrIsNull, StatePtrNotNull; 1133 llvm::tie(StatePtrIsNull, StatePtrNotNull) = state->assume(PtrEQ); 1134 ProgramStateRef StateSizeIsZero, StateSizeNotZero; 1135 llvm::tie(StateSizeIsZero, StateSizeNotZero) = state->assume(SizeZero); 1136 // We only assume exceptional states if they are definitely true; if the 1137 // state is under-constrained, assume regular realloc behavior. 1138 bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull; 1139 bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero; 1140 1141 // If the ptr is NULL and the size is not 0, the call is equivalent to 1142 // malloc(size). 1143 if ( PrtIsNull && !SizeIsZero) { 1144 ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1), 1145 UndefinedVal(), StatePtrIsNull); 1146 return stateMalloc; 1147 } 1148 1149 if (PrtIsNull && SizeIsZero) 1150 return 0; 1151 1152 // Get the from and to pointer symbols as in toPtr = realloc(fromPtr, size). 1153 assert(!PrtIsNull); 1154 SymbolRef FromPtr = arg0Val.getAsSymbol(); 1155 SVal RetVal = state->getSVal(CE, LCtx); 1156 SymbolRef ToPtr = RetVal.getAsSymbol(); 1157 if (!FromPtr || !ToPtr) 1158 return 0; 1159 1160 bool ReleasedAllocated = false; 1161 1162 // If the size is 0, free the memory. 1163 if (SizeIsZero) 1164 if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0, 1165 false, ReleasedAllocated)){ 1166 // The semantics of the return value are: 1167 // If size was equal to 0, either NULL or a pointer suitable to be passed 1168 // to free() is returned. We just free the input pointer and do not add 1169 // any constrains on the output pointer. 1170 return stateFree; 1171 } 1172 1173 // Default behavior. 1174 if (ProgramStateRef stateFree = 1175 FreeMemAux(C, CE, state, 0, false, ReleasedAllocated)) { 1176 1177 ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1), 1178 UnknownVal(), stateFree); 1179 if (!stateRealloc) 1180 return 0; 1181 1182 ReallocPairKind Kind = RPToBeFreedAfterFailure; 1183 if (FreesOnFail) 1184 Kind = RPIsFreeOnFailure; 1185 else if (!ReleasedAllocated) 1186 Kind = RPDoNotTrackAfterFailure; 1187 1188 // Record the info about the reallocated symbol so that we could properly 1189 // process failed reallocation. 1190 stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, 1191 ReallocPair(FromPtr, Kind)); 1192 // The reallocated symbol should stay alive for as long as the new symbol. 1193 C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr); 1194 return stateRealloc; 1195 } 1196 return 0; 1197} 1198 1199ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE){ 1200 if (CE->getNumArgs() < 2) 1201 return 0; 1202 1203 ProgramStateRef state = C.getState(); 1204 SValBuilder &svalBuilder = C.getSValBuilder(); 1205 const LocationContext *LCtx = C.getLocationContext(); 1206 SVal count = state->getSVal(CE->getArg(0), LCtx); 1207 SVal elementSize = state->getSVal(CE->getArg(1), LCtx); 1208 SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize, 1209 svalBuilder.getContext().getSizeType()); 1210 SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); 1211 1212 return MallocMemAux(C, CE, TotalSize, zeroVal, state); 1213} 1214 1215LeakInfo 1216MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym, 1217 CheckerContext &C) const { 1218 const LocationContext *LeakContext = N->getLocationContext(); 1219 // Walk the ExplodedGraph backwards and find the first node that referred to 1220 // the tracked symbol. 1221 const ExplodedNode *AllocNode = N; 1222 const MemRegion *ReferenceRegion = 0; 1223 1224 while (N) { 1225 ProgramStateRef State = N->getState(); 1226 if (!State->get<RegionState>(Sym)) 1227 break; 1228 1229 // Find the most recent expression bound to the symbol in the current 1230 // context. 1231 if (!ReferenceRegion) { 1232 if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { 1233 SVal Val = State->getSVal(MR); 1234 if (Val.getAsLocSymbol() == Sym) 1235 ReferenceRegion = MR; 1236 } 1237 } 1238 1239 // Allocation node, is the last node in the current context in which the 1240 // symbol was tracked. 1241 if (N->getLocationContext() == LeakContext) 1242 AllocNode = N; 1243 N = N->pred_empty() ? NULL : *(N->pred_begin()); 1244 } 1245 1246 return LeakInfo(AllocNode, ReferenceRegion); 1247} 1248 1249void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, 1250 CheckerContext &C) const { 1251 assert(N); 1252 if (!BT_Leak) { 1253 BT_Leak.reset(new BugType("Memory leak", "Memory Error")); 1254 // Leaks should not be reported if they are post-dominated by a sink: 1255 // (1) Sinks are higher importance bugs. 1256 // (2) NoReturnFunctionChecker uses sink nodes to represent paths ending 1257 // with __noreturn functions such as assert() or exit(). We choose not 1258 // to report leaks on such paths. 1259 BT_Leak->setSuppressOnSink(true); 1260 } 1261 1262 // Most bug reports are cached at the location where they occurred. 1263 // With leaks, we want to unique them by the location where they were 1264 // allocated, and only report a single path. 1265 PathDiagnosticLocation LocUsedForUniqueing; 1266 const ExplodedNode *AllocNode = 0; 1267 const MemRegion *Region = 0; 1268 llvm::tie(AllocNode, Region) = getAllocationSite(N, Sym, C); 1269 1270 ProgramPoint P = AllocNode->getLocation(); 1271 const Stmt *AllocationStmt = 0; 1272 if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) 1273 AllocationStmt = Exit->getCalleeContext()->getCallSite(); 1274 else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) 1275 AllocationStmt = SP->getStmt(); 1276 if (AllocationStmt) 1277 LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt, 1278 C.getSourceManager(), 1279 AllocNode->getLocationContext()); 1280 1281 SmallString<200> buf; 1282 llvm::raw_svector_ostream os(buf); 1283 os << "Memory is never released; potential leak"; 1284 if (Region && Region->canPrintPretty()) { 1285 os << " of memory pointed to by '"; 1286 Region->printPretty(os); 1287 os << '\''; 1288 } 1289 1290 BugReport *R = new BugReport(*BT_Leak, os.str(), N, 1291 LocUsedForUniqueing, 1292 AllocNode->getLocationContext()->getDecl()); 1293 R->markInteresting(Sym); 1294 R->addVisitor(new MallocBugVisitor(Sym, true)); 1295 C.emitReport(R); 1296} 1297 1298void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, 1299 CheckerContext &C) const 1300{ 1301 if (!SymReaper.hasDeadSymbols()) 1302 return; 1303 1304 ProgramStateRef state = C.getState(); 1305 RegionStateTy RS = state->get<RegionState>(); 1306 RegionStateTy::Factory &F = state->get_context<RegionState>(); 1307 1308 SmallVector<SymbolRef, 2> Errors; 1309 for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { 1310 if (SymReaper.isDead(I->first)) { 1311 if (I->second.isAllocated()) 1312 Errors.push_back(I->first); 1313 // Remove the dead symbol from the map. 1314 RS = F.remove(RS, I->first); 1315 1316 } 1317 } 1318 1319 // Cleanup the Realloc Pairs Map. 1320 ReallocPairsTy RP = state->get<ReallocPairs>(); 1321 for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { 1322 if (SymReaper.isDead(I->first) || 1323 SymReaper.isDead(I->second.ReallocatedSym)) { 1324 state = state->remove<ReallocPairs>(I->first); 1325 } 1326 } 1327 1328 // Cleanup the FreeReturnValue Map. 1329 FreeReturnValueTy FR = state->get<FreeReturnValue>(); 1330 for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) { 1331 if (SymReaper.isDead(I->first) || 1332 SymReaper.isDead(I->second)) { 1333 state = state->remove<FreeReturnValue>(I->first); 1334 } 1335 } 1336 1337 // Generate leak node. 1338 ExplodedNode *N = C.getPredecessor(); 1339 if (!Errors.empty()) { 1340 static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak"); 1341 N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); 1342 for (SmallVector<SymbolRef, 2>::iterator 1343 I = Errors.begin(), E = Errors.end(); I != E; ++I) { 1344 reportLeak(*I, N, C); 1345 } 1346 } 1347 1348 C.addTransition(state->set<RegionState>(RS), N); 1349} 1350 1351void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { 1352 // We will check for double free in the post visit. 1353 if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) && 1354 isFreeFunction(C.getCalleeDecl(CE), C.getASTContext())) 1355 return; 1356 1357 if (Filter.CNewDeleteChecker && 1358 isStandardNewDelete(C.getCalleeDecl(CE), C.getASTContext())) 1359 return; 1360 1361 // Check use after free, when a freed pointer is passed to a call. 1362 ProgramStateRef State = C.getState(); 1363 for (CallExpr::const_arg_iterator I = CE->arg_begin(), 1364 E = CE->arg_end(); I != E; ++I) { 1365 const Expr *A = *I; 1366 if (A->getType().getTypePtr()->isAnyPointerType()) { 1367 SymbolRef Sym = C.getSVal(A).getAsSymbol(); 1368 if (!Sym) 1369 continue; 1370 if (checkUseAfterFree(Sym, C, A)) 1371 return; 1372 } 1373 } 1374} 1375 1376void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { 1377 const Expr *E = S->getRetValue(); 1378 if (!E) 1379 return; 1380 1381 // Check if we are returning a symbol. 1382 ProgramStateRef State = C.getState(); 1383 SVal RetVal = State->getSVal(E, C.getLocationContext()); 1384 SymbolRef Sym = RetVal.getAsSymbol(); 1385 if (!Sym) 1386 // If we are returning a field of the allocated struct or an array element, 1387 // the callee could still free the memory. 1388 // TODO: This logic should be a part of generic symbol escape callback. 1389 if (const MemRegion *MR = RetVal.getAsRegion()) 1390 if (isa<FieldRegion>(MR) || isa<ElementRegion>(MR)) 1391 if (const SymbolicRegion *BMR = 1392 dyn_cast<SymbolicRegion>(MR->getBaseRegion())) 1393 Sym = BMR->getSymbol(); 1394 1395 // Check if we are returning freed memory. 1396 if (Sym) 1397 checkUseAfterFree(Sym, C, E); 1398} 1399 1400// TODO: Blocks should be either inlined or should call invalidate regions 1401// upon invocation. After that's in place, special casing here will not be 1402// needed. 1403void MallocChecker::checkPostStmt(const BlockExpr *BE, 1404 CheckerContext &C) const { 1405 1406 // Scan the BlockDecRefExprs for any object the retain count checker 1407 // may be tracking. 1408 if (!BE->getBlockDecl()->hasCaptures()) 1409 return; 1410 1411 ProgramStateRef state = C.getState(); 1412 const BlockDataRegion *R = 1413 cast<BlockDataRegion>(state->getSVal(BE, 1414 C.getLocationContext()).getAsRegion()); 1415 1416 BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(), 1417 E = R->referenced_vars_end(); 1418 1419 if (I == E) 1420 return; 1421 1422 SmallVector<const MemRegion*, 10> Regions; 1423 const LocationContext *LC = C.getLocationContext(); 1424 MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager(); 1425 1426 for ( ; I != E; ++I) { 1427 const VarRegion *VR = I.getCapturedRegion(); 1428 if (VR->getSuperRegion() == R) { 1429 VR = MemMgr.getVarRegion(VR->getDecl(), LC); 1430 } 1431 Regions.push_back(VR); 1432 } 1433 1434 state = 1435 state->scanReachableSymbols<StopTrackingCallback>(Regions.data(), 1436 Regions.data() + Regions.size()).getState(); 1437 C.addTransition(state); 1438} 1439 1440bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const { 1441 assert(Sym); 1442 const RefState *RS = C.getState()->get<RegionState>(Sym); 1443 return (RS && RS->isReleased()); 1444} 1445 1446bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, 1447 const Stmt *S) const { 1448 1449 if (isReleased(Sym, C)) { 1450 ReportUseAfterFree(C, S->getSourceRange(), Sym); 1451 return true; 1452 } 1453 1454 return false; 1455} 1456 1457// Check if the location is a freed symbolic region. 1458void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, 1459 CheckerContext &C) const { 1460 SymbolRef Sym = l.getLocSymbolInBase(); 1461 if (Sym) 1462 checkUseAfterFree(Sym, C, S); 1463} 1464 1465// If a symbolic region is assumed to NULL (or another constant), stop tracking 1466// it - assuming that allocation failed on this path. 1467ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, 1468 SVal Cond, 1469 bool Assumption) const { 1470 RegionStateTy RS = state->get<RegionState>(); 1471 for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { 1472 // If the symbol is assumed to be NULL, remove it from consideration. 1473 ConstraintManager &CMgr = state->getConstraintManager(); 1474 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); 1475 if (AllocFailed.isConstrainedTrue()) 1476 state = state->remove<RegionState>(I.getKey()); 1477 } 1478 1479 // Realloc returns 0 when reallocation fails, which means that we should 1480 // restore the state of the pointer being reallocated. 1481 ReallocPairsTy RP = state->get<ReallocPairs>(); 1482 for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { 1483 // If the symbol is assumed to be NULL, remove it from consideration. 1484 ConstraintManager &CMgr = state->getConstraintManager(); 1485 ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); 1486 if (!AllocFailed.isConstrainedTrue()) 1487 continue; 1488 1489 SymbolRef ReallocSym = I.getData().ReallocatedSym; 1490 if (const RefState *RS = state->get<RegionState>(ReallocSym)) { 1491 if (RS->isReleased()) { 1492 if (I.getData().Kind == RPToBeFreedAfterFailure) 1493 state = state->set<RegionState>(ReallocSym, 1494 RefState::getAllocated(RS->getStmt())); 1495 else if (I.getData().Kind == RPDoNotTrackAfterFailure) 1496 state = state->remove<RegionState>(ReallocSym); 1497 else 1498 assert(I.getData().Kind == RPIsFreeOnFailure); 1499 } 1500 } 1501 state = state->remove<ReallocPairs>(I.getKey()); 1502 } 1503 1504 return state; 1505} 1506 1507bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call, 1508 ProgramStateRef State) const { 1509 assert(Call); 1510 1511 // For now, assume that any C++ call can free memory. 1512 // TODO: If we want to be more optimistic here, we'll need to make sure that 1513 // regions escape to C++ containers. They seem to do that even now, but for 1514 // mysterious reasons. 1515 if (!(isa<FunctionCall>(Call) || isa<ObjCMethodCall>(Call))) 1516 return false; 1517 1518 // Check Objective-C messages by selector name. 1519 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(Call)) { 1520 // If it's not a framework call, or if it takes a callback, assume it 1521 // can free memory. 1522 if (!Call->isInSystemHeader() || Call->hasNonZeroCallbackArg()) 1523 return false; 1524 1525 // If it's a method we know about, handle it explicitly post-call. 1526 // This should happen before the "freeWhenDone" check below. 1527 if (isKnownDeallocObjCMethodName(*Msg)) 1528 return true; 1529 1530 // If there's a "freeWhenDone" parameter, but the method isn't one we know 1531 // about, we can't be sure that the object will use free() to deallocate the 1532 // memory, so we can't model it explicitly. The best we can do is use it to 1533 // decide whether the pointer escapes. 1534 if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg)) 1535 return !*FreeWhenDone; 1536 1537 // If the first selector piece ends with "NoCopy", and there is no 1538 // "freeWhenDone" parameter set to zero, we know ownership is being 1539 // transferred. Again, though, we can't be sure that the object will use 1540 // free() to deallocate the memory, so we can't model it explicitly. 1541 StringRef FirstSlot = Msg->getSelector().getNameForSlot(0); 1542 if (FirstSlot.endswith("NoCopy")) 1543 return false; 1544 1545 // If the first selector starts with addPointer, insertPointer, 1546 // or replacePointer, assume we are dealing with NSPointerArray or similar. 1547 // This is similar to C++ containers (vector); we still might want to check 1548 // that the pointers get freed by following the container itself. 1549 if (FirstSlot.startswith("addPointer") || 1550 FirstSlot.startswith("insertPointer") || 1551 FirstSlot.startswith("replacePointer")) { 1552 return false; 1553 } 1554 1555 // Otherwise, assume that the method does not free memory. 1556 // Most framework methods do not free memory. 1557 return true; 1558 } 1559 1560 // At this point the only thing left to handle is straight function calls. 1561 const FunctionDecl *FD = cast<FunctionCall>(Call)->getDecl(); 1562 if (!FD) 1563 return false; 1564 1565 ASTContext &ASTC = State->getStateManager().getContext(); 1566 1567 // If it's one of the allocation functions we can reason about, we model 1568 // its behavior explicitly. 1569 if (isMemFunction(FD, ASTC)) 1570 return true; 1571 1572 // If it's not a system call, assume it frees memory. 1573 if (!Call->isInSystemHeader()) 1574 return false; 1575 1576 // White list the system functions whose arguments escape. 1577 const IdentifierInfo *II = FD->getIdentifier(); 1578 if (!II) 1579 return false; 1580 StringRef FName = II->getName(); 1581 1582 // White list the 'XXXNoCopy' CoreFoundation functions. 1583 // We specifically check these before 1584 if (FName.endswith("NoCopy")) { 1585 // Look for the deallocator argument. We know that the memory ownership 1586 // is not transferred only if the deallocator argument is 1587 // 'kCFAllocatorNull'. 1588 for (unsigned i = 1; i < Call->getNumArgs(); ++i) { 1589 const Expr *ArgE = Call->getArgExpr(i)->IgnoreParenCasts(); 1590 if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(ArgE)) { 1591 StringRef DeallocatorName = DE->getFoundDecl()->getName(); 1592 if (DeallocatorName == "kCFAllocatorNull") 1593 return true; 1594 } 1595 } 1596 return false; 1597 } 1598 1599 // Associating streams with malloced buffers. The pointer can escape if 1600 // 'closefn' is specified (and if that function does free memory), 1601 // but it will not if closefn is not specified. 1602 // Currently, we do not inspect the 'closefn' function (PR12101). 1603 if (FName == "funopen") 1604 if (Call->getNumArgs() >= 4 && Call->getArgSVal(4).isConstant(0)) 1605 return true; 1606 1607 // Do not warn on pointers passed to 'setbuf' when used with std streams, 1608 // these leaks might be intentional when setting the buffer for stdio. 1609 // http://stackoverflow.com/questions/2671151/who-frees-setvbuf-buffer 1610 if (FName == "setbuf" || FName =="setbuffer" || 1611 FName == "setlinebuf" || FName == "setvbuf") { 1612 if (Call->getNumArgs() >= 1) { 1613 const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts(); 1614 if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE)) 1615 if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl())) 1616 if (D->getCanonicalDecl()->getName().find("std") != StringRef::npos) 1617 return false; 1618 } 1619 } 1620 1621 // A bunch of other functions which either take ownership of a pointer or 1622 // wrap the result up in a struct or object, meaning it can be freed later. 1623 // (See RetainCountChecker.) Not all the parameters here are invalidated, 1624 // but the Malloc checker cannot differentiate between them. The right way 1625 // of doing this would be to implement a pointer escapes callback. 1626 if (FName == "CGBitmapContextCreate" || 1627 FName == "CGBitmapContextCreateWithData" || 1628 FName == "CVPixelBufferCreateWithBytes" || 1629 FName == "CVPixelBufferCreateWithPlanarBytes" || 1630 FName == "OSAtomicEnqueue") { 1631 return false; 1632 } 1633 1634 // Handle cases where we know a buffer's /address/ can escape. 1635 // Note that the above checks handle some special cases where we know that 1636 // even though the address escapes, it's still our responsibility to free the 1637 // buffer. 1638 if (Call->argumentsMayEscape()) 1639 return false; 1640 1641 // Otherwise, assume that the function does not free memory. 1642 // Most system calls do not free the memory. 1643 return true; 1644} 1645 1646ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State, 1647 const InvalidatedSymbols &Escaped, 1648 const CallEvent *Call, 1649 PointerEscapeKind Kind) const { 1650 // If we know that the call does not free memory, or we want to process the 1651 // call later, keep tracking the top level arguments. 1652 if ((Kind == PSK_DirectEscapeOnCall || 1653 Kind == PSK_IndirectEscapeOnCall) && 1654 doesNotFreeMemOrInteresting(Call, State)) { 1655 return State; 1656 } 1657 1658 for (InvalidatedSymbols::const_iterator I = Escaped.begin(), 1659 E = Escaped.end(); 1660 I != E; ++I) { 1661 SymbolRef sym = *I; 1662 1663 if (const RefState *RS = State->get<RegionState>(sym)) { 1664 if (RS->isAllocated()) 1665 State = State->remove<RegionState>(sym); 1666 } 1667 } 1668 return State; 1669} 1670 1671static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, 1672 ProgramStateRef prevState) { 1673 ReallocPairsTy currMap = currState->get<ReallocPairs>(); 1674 ReallocPairsTy prevMap = prevState->get<ReallocPairs>(); 1675 1676 for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end(); 1677 I != E; ++I) { 1678 SymbolRef sym = I.getKey(); 1679 if (!currMap.lookup(sym)) 1680 return sym; 1681 } 1682 1683 return NULL; 1684} 1685 1686PathDiagnosticPiece * 1687MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, 1688 const ExplodedNode *PrevN, 1689 BugReporterContext &BRC, 1690 BugReport &BR) { 1691 ProgramStateRef state = N->getState(); 1692 ProgramStateRef statePrev = PrevN->getState(); 1693 1694 const RefState *RS = state->get<RegionState>(Sym); 1695 const RefState *RSPrev = statePrev->get<RegionState>(Sym); 1696 if (!RS) 1697 return 0; 1698 1699 const Stmt *S = 0; 1700 const char *Msg = 0; 1701 StackHintGeneratorForSymbol *StackHint = 0; 1702 1703 // Retrieve the associated statement. 1704 ProgramPoint ProgLoc = N->getLocation(); 1705 if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) { 1706 S = SP->getStmt(); 1707 } else if (Optional<CallExitEnd> Exit = ProgLoc.getAs<CallExitEnd>()) { 1708 S = Exit->getCalleeContext()->getCallSite(); 1709 } else if (Optional<BlockEdge> Edge = ProgLoc.getAs<BlockEdge>()) { 1710 // If an assumption was made on a branch, it should be caught 1711 // here by looking at the state transition. 1712 S = Edge->getSrc()->getTerminator(); 1713 } 1714 1715 if (!S) 1716 return 0; 1717 1718 // FIXME: We will eventually need to handle non-statement-based events 1719 // (__attribute__((cleanup))). 1720 1721 // Find out if this is an interesting point and what is the kind. 1722 if (Mode == Normal) { 1723 if (isAllocated(RS, RSPrev, S)) { 1724 Msg = "Memory is allocated"; 1725 StackHint = new StackHintGeneratorForSymbol(Sym, 1726 "Returned allocated memory"); 1727 } else if (isReleased(RS, RSPrev, S)) { 1728 Msg = "Memory is released"; 1729 StackHint = new StackHintGeneratorForSymbol(Sym, 1730 "Returned released memory"); 1731 } else if (isRelinquished(RS, RSPrev, S)) { 1732 Msg = "Memory ownership is transfered"; 1733 StackHint = new StackHintGeneratorForSymbol(Sym, ""); 1734 } else if (isReallocFailedCheck(RS, RSPrev, S)) { 1735 Mode = ReallocationFailed; 1736 Msg = "Reallocation failed"; 1737 StackHint = new StackHintGeneratorForReallocationFailed(Sym, 1738 "Reallocation failed"); 1739 1740 if (SymbolRef sym = findFailedReallocSymbol(state, statePrev)) { 1741 // Is it possible to fail two reallocs WITHOUT testing in between? 1742 assert((!FailedReallocSymbol || FailedReallocSymbol == sym) && 1743 "We only support one failed realloc at a time."); 1744 BR.markInteresting(sym); 1745 FailedReallocSymbol = sym; 1746 } 1747 } 1748 1749 // We are in a special mode if a reallocation failed later in the path. 1750 } else if (Mode == ReallocationFailed) { 1751 assert(FailedReallocSymbol && "No symbol to look for."); 1752 1753 // Is this is the first appearance of the reallocated symbol? 1754 if (!statePrev->get<RegionState>(FailedReallocSymbol)) { 1755 // We're at the reallocation point. 1756 Msg = "Attempt to reallocate memory"; 1757 StackHint = new StackHintGeneratorForSymbol(Sym, 1758 "Returned reallocated memory"); 1759 FailedReallocSymbol = NULL; 1760 Mode = Normal; 1761 } 1762 } 1763 1764 if (!Msg) 1765 return 0; 1766 assert(StackHint); 1767 1768 // Generate the extra diagnostic. 1769 PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 1770 N->getLocationContext()); 1771 return new PathDiagnosticEventPiece(Pos, Msg, true, StackHint); 1772} 1773 1774void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State, 1775 const char *NL, const char *Sep) const { 1776 1777 RegionStateTy RS = State->get<RegionState>(); 1778 1779 if (!RS.isEmpty()) { 1780 Out << Sep << "MallocChecker:" << NL; 1781 for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { 1782 I.getKey()->dumpToStream(Out); 1783 Out << " : "; 1784 I.getData().dump(Out); 1785 Out << NL; 1786 } 1787 } 1788} 1789 1790#define REGISTER_CHECKER(name) \ 1791void ento::register##name(CheckerManager &mgr) {\ 1792 registerCStringCheckerBasic(mgr); \ 1793 mgr.registerChecker<MallocChecker>()->Filter.C##name = true;\ 1794} 1795 1796REGISTER_CHECKER(MallocPessimistic) 1797REGISTER_CHECKER(MallocOptimistic) 1798REGISTER_CHECKER(NewDeleteChecker) 1799