Skip to content

Commit 2ec7140

Browse files
committed
use the code already included in the checker to find uninitialized LCV
1 parent 3d11777 commit 2ec7140

File tree

4 files changed

+204
-72
lines changed

4 files changed

+204
-72
lines changed

clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp

Lines changed: 107 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -179,59 +179,6 @@ static void describeUninitializedArgumentInCall(const CallEvent &Call,
179179
}
180180
}
181181

182-
bool CallAndMessageChecker::uninitRefOrPointer(
183-
CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
184-
const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
185-
186-
if (!ChecksEnabled[CK_ArgPointeeInitializedness])
187-
return false;
188-
189-
// No parameter declaration available, i.e. variadic function argument.
190-
if(!ParamDecl)
191-
return false;
192-
193-
// If parameter is declared as pointer to const in function declaration,
194-
// then check if corresponding argument in function call is
195-
// pointing to undefined symbol value (uninitialized memory).
196-
SmallString<200> Buf;
197-
llvm::raw_svector_ostream Os(Buf);
198-
199-
if (ParamDecl->getType()->isPointerType()) {
200-
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
201-
<< " function call argument is a pointer to uninitialized value";
202-
} else if (ParamDecl->getType()->isReferenceType()) {
203-
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
204-
<< " function call argument is an uninitialized value";
205-
} else
206-
return false;
207-
208-
if(!ParamDecl->getType()->getPointeeType().isConstQualified())
209-
return false;
210-
211-
if (const MemRegion *SValMemRegion = V.getAsRegion()) {
212-
const ProgramStateRef State = C.getState();
213-
QualType T = ParamDecl->getType()->getPointeeType();
214-
if (T->isVoidType())
215-
T = C.getASTContext().CharTy;
216-
const SVal PSV = State->getSVal(SValMemRegion, T);
217-
bool IsUndef = PSV.isUndef();
218-
if (auto LCV = PSV.getAs<nonloc::LazyCompoundVal>())
219-
IsUndef = LCV->getStore() == nullptr;
220-
if (IsUndef) {
221-
if (ExplodedNode *N = C.generateErrorNode()) {
222-
auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
223-
R->addRange(ArgRange);
224-
if (ArgEx)
225-
bugreporter::trackExpressionValue(N, ArgEx, *R);
226-
227-
C.emitReport(std::move(R));
228-
}
229-
return true;
230-
}
231-
}
232-
return false;
233-
}
234-
235182
namespace {
236183
class FindUninitializedField {
237184
public:
@@ -272,9 +219,115 @@ class FindUninitializedField {
272219

273220
return false;
274221
}
222+
223+
void printFieldChain(llvm::raw_ostream &OS) {
224+
if (FieldChain.size() == 1)
225+
OS << " (e.g., field: '" << *FieldChain[0] << "')";
226+
else {
227+
OS << " (e.g., via the field chain: '";
228+
bool First = true;
229+
for (SmallVectorImpl<const FieldDecl *>::iterator DI = FieldChain.begin(),
230+
DE = FieldChain.end();
231+
DI != DE; ++DI) {
232+
if (First)
233+
First = false;
234+
else
235+
OS << '.';
236+
OS << **DI;
237+
}
238+
OS << "')";
239+
}
240+
}
275241
};
276242
} // namespace
277243

244+
bool CallAndMessageChecker::uninitRefOrPointer(
245+
CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
246+
const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {
247+
248+
if (!ChecksEnabled[CK_ArgPointeeInitializedness])
249+
return false;
250+
251+
// No parameter declaration available, i.e. variadic function argument.
252+
if (!ParamDecl)
253+
return false;
254+
255+
QualType ParamT = ParamDecl->getType();
256+
if (!ParamT->isPointerOrReferenceType())
257+
return false;
258+
259+
QualType PointeeT = ParamT->getPointeeType();
260+
if (!PointeeT.isConstQualified())
261+
return false;
262+
263+
const MemRegion *SValMemRegion = V.getAsRegion();
264+
if (!SValMemRegion)
265+
return false;
266+
267+
// If parameter is declared as pointer to const in function declaration,
268+
// then check if corresponding argument in function call is
269+
// pointing to undefined symbol value (uninitialized memory).
270+
271+
const ProgramStateRef State = C.getState();
272+
if (PointeeT->isVoidType())
273+
PointeeT = C.getASTContext().CharTy;
274+
const SVal PointeeV =
275+
State->getSVal(SValMemRegion, PointeeT);
276+
277+
if (PointeeV.isUndef()) {
278+
if (ExplodedNode *N = C.generateErrorNode()) {
279+
SmallString<200> Buf;
280+
llvm::raw_svector_ostream Os(Buf);
281+
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
282+
<< " function call argument is ";
283+
if (ParamT->isPointerType())
284+
Os << "a pointer to uninitialized value";
285+
else
286+
Os << "an uninitialized value";
287+
auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
288+
R->addRange(ArgRange);
289+
if (ArgEx)
290+
bugreporter::trackExpressionValue(N, ArgEx, *R);
291+
292+
C.emitReport(std::move(R));
293+
}
294+
return true;
295+
}
296+
297+
if (auto LV = PointeeV.getAs<nonloc::LazyCompoundVal>()) {
298+
const LazyCompoundValData *D = LV->getCVData();
299+
FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
300+
C.getSValBuilder().getRegionManager(),
301+
D->getStore());
302+
303+
if (F.Find(D->getRegion())) {
304+
if (ExplodedNode *N = C.generateErrorNode()) {
305+
SmallString<512> Buf;
306+
llvm::raw_svector_ostream Os(Buf);
307+
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
308+
<< " function call argument";
309+
if (ParamT->isPointerType())
310+
Os << " points to";
311+
else
312+
Os << " references";
313+
Os << " an uninitialized value";
314+
315+
F.printFieldChain(Os);
316+
317+
auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
318+
R->addRange(ArgRange);
319+
320+
if (ArgEx)
321+
bugreporter::trackExpressionValue(N, ArgEx, *R);
322+
C.emitReport(std::move(R));
323+
}
324+
return true;
325+
}
326+
}
327+
328+
return false;
329+
}
330+
278331
bool CallAndMessageChecker::PreVisitProcessArg(
279332
CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
280333
int ArgumentNumber, bool CheckUninitFields, const CallEvent &Call,
@@ -320,22 +373,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(
320373
SmallString<512> Str;
321374
llvm::raw_svector_ostream os(Str);
322375
os << "Passed-by-value struct argument contains uninitialized data";
323-
324-
if (F.FieldChain.size() == 1)
325-
os << " (e.g., field: '" << *F.FieldChain[0] << "')";
326-
else {
327-
os << " (e.g., via the field chain: '";
328-
bool first = true;
329-
for (SmallVectorImpl<const FieldDecl *>::iterator
330-
DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
331-
if (first)
332-
first = false;
333-
else
334-
os << '.';
335-
os << **DI;
336-
}
337-
os << "')";
338-
}
376+
F.printFieldChain(os);
339377

340378
// Generate a report for this bug.
341379
auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);

clang/test/Analysis/PR40625.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
void f(const int *end);
66

77
void g(const int (&arrr)[10]) {
8-
f(arrr);
8+
f(arrr); // expected-warning{{1st function call argument is a pointer to uninitialized value}}
99
}
1010

1111
void h() {
1212
int arr[10];
1313

14-
g(arr); // expected-warning{{1st function call argument is an uninitialized value}}
14+
g(arr);
1515
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: %clang_analyze_cc1 %s -verify \
2+
// RUN: -analyzer-checker=core \
3+
// RUN: -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true \
4+
// RUN: -analyzer-config core.CallAndMessage:ArgInitializedness=false
5+
6+
struct S1 {
7+
char c;
8+
};
9+
10+
struct S {
11+
int a;
12+
S1 b;
13+
};
14+
15+
S GlobalS;
16+
17+
void doStuffP(const S *);
18+
void doStuffR(const S &);
19+
20+
void uninit_val_p() {
21+
S s;
22+
doStuffP(&s); // expected-warning{{1st function call argument points to an uninitialized value (e.g., field: 'a')}}
23+
}
24+
25+
void uninit_val_r() {
26+
S s;
27+
s.a = 0;
28+
doStuffR(s); // expected-warning{{1st function call argument references an uninitialized value (e.g., via the field chain: 'b.c')}}
29+
}
30+
31+
S *uninit_new() {
32+
S *s = new S;
33+
doStuffP(s); // expected-warning{{1st function call argument points to an uninitialized value (e.g., field: 'a')}}
34+
return s;
35+
}
36+
37+
void uninit_ctr() {
38+
S s = S();
39+
doStuffP(&s);
40+
}
41+
42+
void uninit_init() {
43+
S s{};
44+
doStuffP(&s);
45+
}
46+
47+
void uninit_init_val() {
48+
S s{1, {2}};
49+
doStuffP(&s);
50+
}
51+
52+
void uninit_parm_ptr(S *s) {
53+
doStuffP(s);
54+
}
55+
56+
void uninit_parm_val(S s) {
57+
doStuffP(&s);
58+
}
59+
60+
void uninit_parm_ref(S &s) {
61+
doStuffP(&s);
62+
}
63+
64+
void init_val() {
65+
S s;
66+
s.a = 1;
67+
s.b.c = 1;
68+
doStuffP(&s);
69+
}
70+
71+
void uninit_global() {
72+
doStuffP(&GlobalS);
73+
}
74+
75+
void uninit_static() {
76+
static S s;
77+
doStuffP(&s);
78+
}

clang/test/Analysis/call-and-message.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,23 @@ void doStuff_pointerToConstStruct(const S *s){};
3333
void pointee_uninit_struct(void) {
3434
S s;
3535
S *p = &s;
36-
doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument is a pointer to uninitialized value [core.CallAndMessage]}}
36+
doStuff_pointerToConstStruct(p); // expected-warning{{1st function call argument points to an uninitialized value (e.g., field: 'a') [core.CallAndMessage]}}
37+
}
38+
void pointee_uninit_struct_1(void) {
39+
S s;
40+
s.a = 2;
41+
doStuff_pointerToConstStruct(&s); // expected-warning{{1st function call argument points to an uninitialized value (e.g., field: 'b') [core.CallAndMessage]}}
42+
}
43+
void pointee_uninit_struct_2(void) {
44+
S s = {};
45+
doStuff_pointerToConstStruct(&s);
46+
}
47+
void pointee_uninit_struct_3(S *s) {
48+
doStuff_pointerToConstStruct(s);
49+
}
50+
void pointee_uninit_struct_4(void) {
51+
S s = {1, 2};
52+
doStuff_pointerToConstStruct(&s);
3753
}
3854

3955
// TODO: If this hash ever changes, turn

0 commit comments

Comments
 (0)