Skip to content

Commit 5bb7ba6

Browse files
authored
[analyzer] Detect use-after-free for field address (e.g., &ptr->field) (#152462)
This patch improves MallocChecker to detect use-after-free bugs when a freed structure's field is passed by address (e.g., `&ptr->field`). Previously, MallocChecker would miss such cases, as it only checked the top-level symbol of argument values. This patch analyzes the base region of arguments and extracts the symbolic region (if any), allowing UAF detection even for field address expressions. Fixes #152446
1 parent f35e9fa commit 5bb7ba6

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3156,7 +3156,7 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
31563156
for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) {
31573157
SVal ArgSVal = Call.getArgSVal(I);
31583158
if (isa<Loc>(ArgSVal)) {
3159-
SymbolRef Sym = ArgSVal.getAsSymbol();
3159+
SymbolRef Sym = ArgSVal.getAsSymbol(/*IncludeBaseRegions=*/true);
31603160
if (!Sym)
31613161
continue;
31623162
if (checkUseAfterFree(Sym, C, Call.getArgExpr(I)))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -verify %s
2+
3+
#include "Inputs/system-header-simulator-for-malloc.h"
4+
5+
struct Obj {
6+
int field;
7+
};
8+
9+
void use(void *ptr);
10+
11+
void test_direct_param_uaf() {
12+
int *p = (int *)malloc(sizeof(int));
13+
free(p);
14+
use(p); // expected-warning{{Use of memory after it is released}}
15+
}
16+
17+
void test_struct_field_uaf() {
18+
struct Obj *o = (struct Obj *)malloc(sizeof(struct Obj));
19+
free(o);
20+
use(&o->field); // expected-warning{{Use of memory after it is released}}
21+
}
22+
23+
void test_no_warning_const_int() {
24+
use((void *)0x1234); // no-warning
25+
}
26+
27+
void test_no_warning_stack() {
28+
int x = 42;
29+
use(&x); // no-warning
30+
}
31+
32+
void test_nested_alloc() {
33+
struct Obj *o = (struct Obj *)malloc(sizeof(struct Obj));
34+
use(o); // no-warning
35+
free(o);
36+
use(o); // expected-warning{{Use of memory after it is released}}
37+
}
38+
39+
void test_nested_field() {
40+
struct Obj *o = (struct Obj *)malloc(sizeof(struct Obj));
41+
int *f = &o->field;
42+
free(o);
43+
use(f); // expected-warning{{Use of memory after it is released}}
44+
}

0 commit comments

Comments
 (0)