|
17 | 17 | #include "clang/AST/ParentMap.h"
|
18 | 18 | #include "clang/Basic/SourceManager.h"
|
19 | 19 | #include "clang/Basic/TargetInfo.h"
|
| 20 | +#include "clang/Lex/Lexer.h" |
20 | 21 | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
21 | 22 | #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
|
22 | 23 | #include "clang/StaticAnalyzer/Core/Checker.h"
|
@@ -359,6 +360,11 @@ class MallocChecker : public Checker<check::DeadSymbols,
|
359 | 360 | /// Check if the memory associated with this symbol was released.
|
360 | 361 | bool isReleased(SymbolRef Sym, CheckerContext &C) const;
|
361 | 362 |
|
| 363 | + /// See if deallocation happens in a suspicious context. If so, escape the |
| 364 | + /// pointers that otherwise would have been deallocated and return true. |
| 365 | + bool suppressDeallocationsInSuspiciousContexts(const CallExpr *CE, |
| 366 | + CheckerContext &C) const; |
| 367 | + |
362 | 368 | bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
|
363 | 369 |
|
364 | 370 | void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
|
@@ -877,6 +883,9 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
|
877 | 883 | State = ProcessZeroAllocation(C, CE, 0, State);
|
878 | 884 | State = ProcessZeroAllocation(C, CE, 1, State);
|
879 | 885 | } else if (FunI == II_free || FunI == II_g_free || FunI == II_kfree) {
|
| 886 | + if (suppressDeallocationsInSuspiciousContexts(CE, C)) |
| 887 | + return; |
| 888 | + |
880 | 889 | State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
|
881 | 890 | } else if (FunI == II_strdup || FunI == II_win_strdup ||
|
882 | 891 | FunI == II_wcsdup || FunI == II_win_wcsdup) {
|
@@ -2532,6 +2541,35 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
|
2532 | 2541 | return (RS && RS->isReleased());
|
2533 | 2542 | }
|
2534 | 2543 |
|
| 2544 | +bool MallocChecker::suppressDeallocationsInSuspiciousContexts( |
| 2545 | + const CallExpr *CE, CheckerContext &C) const { |
| 2546 | + if (CE->getNumArgs() == 0) |
| 2547 | + return false; |
| 2548 | + |
| 2549 | + StringRef FunctionStr = ""; |
| 2550 | + if (const auto *FD = dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) |
| 2551 | + if (const Stmt *Body = FD->getBody()) |
| 2552 | + if (Body->getBeginLoc().isValid()) |
| 2553 | + FunctionStr = |
| 2554 | + Lexer::getSourceText(CharSourceRange::getTokenRange( |
| 2555 | + {FD->getBeginLoc(), Body->getBeginLoc()}), |
| 2556 | + C.getSourceManager(), C.getLangOpts()); |
| 2557 | + |
| 2558 | + // We do not model the Integer Set Library's retain-count based allocation. |
| 2559 | + if (!FunctionStr.contains("__isl_")) |
| 2560 | + return false; |
| 2561 | + |
| 2562 | + ProgramStateRef State = C.getState(); |
| 2563 | + |
| 2564 | + for (const Expr *Arg : CE->arguments()) |
| 2565 | + if (SymbolRef Sym = C.getSVal(Arg).getAsSymbol()) |
| 2566 | + if (const RefState *RS = State->get<RegionState>(Sym)) |
| 2567 | + State = State->set<RegionState>(Sym, RefState::getEscaped(RS)); |
| 2568 | + |
| 2569 | + C.addTransition(State); |
| 2570 | + return true; |
| 2571 | +} |
| 2572 | + |
2535 | 2573 | bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
|
2536 | 2574 | const Stmt *S) const {
|
2537 | 2575 |
|
@@ -2833,7 +2871,6 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
|
2833 | 2871 | if (const RefState *RS = State->get<RegionState>(sym)) {
|
2834 | 2872 | if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
|
2835 | 2873 | CheckRefState(RS)) {
|
2836 |
| - State = State->remove<RegionState>(sym); |
2837 | 2874 | State = State->set<RegionState>(sym, RefState::getEscaped(RS));
|
2838 | 2875 | }
|
2839 | 2876 | }
|
|
0 commit comments