Skip to content

Commit 6898332

Browse files
author
Csaba Dabis
committed
[analyzer] MallocChecker: Prevent Integer Set Library false positives
Summary: Integer Set Library using retain-count based allocation which is not modeled in MallocChecker. Reviewed By: NoQ Tags: #clang Differential Revision: https://reviews.llvm.org/D64680 llvm-svn: 366391
1 parent 4e22770 commit 6898332

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/ParentMap.h"
1818
#include "clang/Basic/SourceManager.h"
1919
#include "clang/Basic/TargetInfo.h"
20+
#include "clang/Lex/Lexer.h"
2021
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
2122
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
2223
#include "clang/StaticAnalyzer/Core/Checker.h"
@@ -359,6 +360,11 @@ class MallocChecker : public Checker<check::DeadSymbols,
359360
/// Check if the memory associated with this symbol was released.
360361
bool isReleased(SymbolRef Sym, CheckerContext &C) const;
361362

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+
362368
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
363369

364370
void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
@@ -877,6 +883,9 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
877883
State = ProcessZeroAllocation(C, CE, 0, State);
878884
State = ProcessZeroAllocation(C, CE, 1, State);
879885
} else if (FunI == II_free || FunI == II_g_free || FunI == II_kfree) {
886+
if (suppressDeallocationsInSuspiciousContexts(CE, C))
887+
return;
888+
880889
State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
881890
} else if (FunI == II_strdup || FunI == II_win_strdup ||
882891
FunI == II_wcsdup || FunI == II_win_wcsdup) {
@@ -2532,6 +2541,35 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
25322541
return (RS && RS->isReleased());
25332542
}
25342543

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+
25352573
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
25362574
const Stmt *S) const {
25372575

@@ -2833,7 +2871,6 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
28332871
if (const RefState *RS = State->get<RegionState>(sym)) {
28342872
if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
28352873
CheckRefState(RS)) {
2836-
State = State->remove<RegionState>(sym);
28372874
State = State->set<RegionState>(sym, RefState::getEscaped(RS));
28382875
}
28392876
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %clang_analyze_cc1 \
2+
// RUN: -analyzer-checker=core,unix.Malloc \
3+
// RUN: -verify %s
4+
5+
// expected-no-diagnostics: We do not model Integer Set Library's retain-count
6+
// based allocation. If any of the parameters has an
7+
// '__isl_' prefixed macro definition we escape every
8+
// of them when we are about to 'free()' something.
9+
10+
#define __isl_take
11+
#define __isl_keep
12+
13+
struct Object { int Ref; };
14+
void free(void *);
15+
16+
Object *copyObj(__isl_keep Object *O) {
17+
O->Ref++;
18+
return O;
19+
}
20+
21+
void freeObj(__isl_take Object *O) {
22+
if (--O->Ref > 0)
23+
return;
24+
25+
free(O); // Here we notice that the parameter contains '__isl_', escape it.
26+
}
27+
28+
void useAfterFree(__isl_take Object *A) {
29+
if (!A)
30+
return;
31+
32+
Object *B = copyObj(A);
33+
freeObj(B);
34+
35+
A->Ref = 13;
36+
// no-warning: 'Use of memory after it is freed' was here.
37+
}

0 commit comments

Comments
 (0)