Skip to content

Commit 339282d

Browse files
authored
[analyzer] Refactor MallocChecker to use BindExpr in evalCall (llvm#106081)
PR refactors `MallocChecker` to not violate invariant of `BindExpr`, which should be called only during `evalCall` to avoid conflicts. To achieve this, most of `postCall` logic was moved to `evalCall` with addition return value binding in case of processing of allocation functions. Check functions prototypes was changed to use `State` with bound return value. `checkDelim` logic was left in `postCall` to avoid conflicts with `StreamChecker` which also evaluates `getline` and friends. PR also introduces breaking change in the unlikely case when the definition of an allocation function (e.g. `malloc()`) is visible: now checker does not try to inline allocation functions and assumes their initial semantics. Closes llvm#73830
1 parent d779685 commit 339282d

File tree

10 files changed

+261
-211
lines changed

10 files changed

+261
-211
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
3636

3737
/// Set the dynamic extent \p Extent of the region \p MR.
3838
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR,
39-
DefinedOrUnknownSVal Extent, SValBuilder &SVB);
39+
DefinedOrUnknownSVal Extent);
4040

4141
/// Get the dynamic extent for a symbolic value that represents a buffer. If
4242
/// there is an offsetting to the underlying buffer we consider that too.

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h

+6-6
Original file line numberDiff line numberDiff line change
@@ -215,17 +215,17 @@ class SValBuilder {
215215
/// Conjure a symbol representing heap allocated memory region.
216216
///
217217
/// Note, the expression should represent a location.
218-
DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E,
219-
const LocationContext *LCtx,
220-
unsigned Count);
218+
DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
219+
const LocationContext *LCtx,
220+
unsigned Count);
221221

222222
/// Conjure a symbol representing heap allocated memory region.
223223
///
224224
/// Note, now, the expression *doesn't* need to represent a location.
225225
/// But the type need to!
226-
DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E,
227-
const LocationContext *LCtx,
228-
QualType type, unsigned Count);
226+
DefinedSVal getConjuredHeapSymbolVal(const Expr *E,
227+
const LocationContext *LCtx,
228+
QualType type, unsigned Count);
229229

230230
/// Create an SVal representing the result of an alloca()-like call, that is,
231231
/// an AllocaRegion on the stack.

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

+237-135
Large diffs are not rendered by default.

clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
266266
return;
267267

268268
ASTContext &Ctx = C.getASTContext();
269-
SValBuilder &SVB = C.getSValBuilder();
270269
ProgramStateRef State = C.getState();
271270
QualType TypeToCheck;
272271

@@ -301,7 +300,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
301300
if (VD) {
302301
State =
303302
setDynamicExtent(State, State->getRegion(VD, C.getLocationContext()),
304-
ArraySize.castAs<NonLoc>(), SVB);
303+
ArraySize.castAs<NonLoc>());
305304
}
306305

307306
// Remember our assumptions!

clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State,
120120
}
121121

122122
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR,
123-
DefinedOrUnknownSVal Size, SValBuilder &SVB) {
123+
DefinedOrUnknownSVal Size) {
124124
MR = MR->StripCasts();
125125

126126
if (Size.isUnknown())

clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -817,8 +817,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
817817
if (Size.isUndef())
818818
Size = UnknownVal();
819819

820-
State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>(),
821-
svalBuilder);
820+
State = setDynamicExtent(State, MR, Size.castAs<DefinedOrUnknownSVal>());
822821
} else {
823822
R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
824823
}

clang/lib/StaticAnalyzer/Core/SValBuilder.cpp

+12-10
Original file line numberDiff line numberDiff line change
@@ -210,22 +210,24 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
210210
return nonloc::SymbolVal(sym);
211211
}
212212

213-
DefinedOrUnknownSVal
214-
SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
215-
const LocationContext *LCtx,
216-
unsigned VisitCount) {
213+
DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
214+
const LocationContext *LCtx,
215+
unsigned VisitCount) {
217216
QualType T = E->getType();
218217
return getConjuredHeapSymbolVal(E, LCtx, T, VisitCount);
219218
}
220219

221-
DefinedOrUnknownSVal
222-
SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
223-
const LocationContext *LCtx,
224-
QualType type, unsigned VisitCount) {
220+
DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
221+
const LocationContext *LCtx,
222+
QualType type,
223+
unsigned VisitCount) {
225224
assert(Loc::isLocType(type));
226225
assert(SymbolManager::canSymbolicate(type));
227-
if (type->isNullPtrType())
228-
return makeZeroVal(type);
226+
if (type->isNullPtrType()) {
227+
// makeZeroVal() returns UnknownVal only in case of FP number, which
228+
// is not the case.
229+
return makeZeroVal(type).castAs<DefinedSVal>();
230+
}
229231

230232
SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, type, VisitCount);
231233
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));

clang/test/Analysis/NewDelete-checker-test.cpp

-17
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ extern "C" void *malloc(size_t);
3737
extern "C" void free (void* ptr);
3838
int *global;
3939

40-
//------------------
41-
// check for leaks
42-
//------------------
43-
4440
//----- Standard non-placement operators
4541
void testGlobalOpNew() {
4642
void *p = operator new(0);
@@ -67,19 +63,6 @@ void testGlobalNoThrowPlacementExprNewBeforeOverload() {
6763
int *p = new(std::nothrow) int;
6864
} // leak-warning{{Potential leak of memory pointed to by 'p'}}
6965

70-
//----- Standard pointer placement operators
71-
void testGlobalPointerPlacementNew() {
72-
int i;
73-
74-
void *p1 = operator new(0, &i); // no warn
75-
76-
void *p2 = operator new[](0, &i); // no warn
77-
78-
int *p3 = new(&i) int; // no warn
79-
80-
int *p4 = new(&i) int[0]; // no warn
81-
}
82-
8366
//----- Other cases
8467
void testNewMemoryIsInHeap() {
8568
int *p = new int;

clang/test/Analysis/NewDelete-intersections.mm

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
// RUN: -analyzer-checker=core \
44
// RUN: -analyzer-checker=cplusplus.NewDelete
55

6+
// leak-no-diagnostics
7+
68
// RUN: %clang_analyze_cc1 -std=c++11 -DLEAKS -fblocks %s \
79
// RUN: -verify=leak \
810
// RUN: -analyzer-checker=core \
911
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
1012

11-
// leak-no-diagnostics
12-
1313
// RUN: %clang_analyze_cc1 -std=c++11 -DLEAKS -fblocks %s \
1414
// RUN: -verify=mismatch \
1515
// RUN: -analyzer-checker=core \

clang/test/Analysis/malloc-interprocedural.c

-35
Original file line numberDiff line numberDiff line change
@@ -98,38 +98,3 @@ int uafAndCallsFooWithEmptyReturn(void) {
9898
fooWithEmptyReturn(12);
9999
return *x; // expected-warning {{Use of memory after it is freed}}
100100
}
101-
102-
103-
// If we inline any of the malloc-family functions, the checker shouldn't also
104-
// try to do additional modeling.
105-
char *strndup(const char *str, size_t n) {
106-
if (!str)
107-
return 0;
108-
109-
// DO NOT FIX. This is to test that we are actually using the inlined
110-
// behavior!
111-
if (n < 5)
112-
return 0;
113-
114-
size_t length = strlen(str);
115-
if (length < n)
116-
n = length;
117-
118-
char *result = malloc(n + 1);
119-
memcpy(result, str, n);
120-
result[n] = '\0';
121-
return result;
122-
}
123-
124-
void useStrndup(size_t n) {
125-
if (n == 0) {
126-
(void)strndup(0, 20); // no-warning
127-
return;
128-
} else if (n < 5) {
129-
(void)strndup("hi there", n); // no-warning
130-
return;
131-
} else {
132-
(void)strndup("hi there", n);
133-
return; // expected-warning{{leak}}
134-
}
135-
}

0 commit comments

Comments
 (0)