[analyzer] Clarify 'uninitialized function argument' messages

Differential Revision: https://reviews.llvm.org/D30341

llvm-svn: 297283
This commit is contained in:
Daniel Marjamaki 2017-03-08 15:22:24 +00:00
parent 9371bab55a
commit 3d8d6ed01f
13 changed files with 103 additions and 89 deletions

View File

@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@ -71,7 +72,7 @@ public:
private:
bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
const Expr *ArgEx, bool IsFirstArgument,
const Expr *ArgEx, int ArgumentNumber,
bool CheckUninitFields, const CallEvent &Call,
std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl) const;
@ -89,9 +90,10 @@ private:
BT.reset(new BuiltinBug(this, desc));
}
bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
SourceRange ArgRange,
const Expr *ArgEx, std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl, const char *BD) const;
SourceRange ArgRange, const Expr *ArgEx,
std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl, const char *BD,
int ArgumentNumber) const;
};
} // end anonymous namespace
@ -111,38 +113,45 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
C.emitReport(std::move(R));
}
static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
bool IsFirstArgument) {
static void describeUninitializedArgumentInCall(const CallEvent &Call,
int ArgumentNumber,
llvm::raw_svector_ostream &Os) {
switch (Call.getKind()) {
case CE_ObjCMessage: {
const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
switch (Msg.getMessageKind()) {
case OCM_Message:
return "Argument in message expression is an uninitialized value";
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
<< " argument in message expression is an uninitialized value";
return;
case OCM_PropertyAccess:
assert(Msg.isSetter() && "Getters have no args");
return "Argument for property setter is an uninitialized value";
Os << "Argument for property setter is an uninitialized value";
return;
case OCM_Subscript:
if (Msg.isSetter() && IsFirstArgument)
return "Argument for subscript setter is an uninitialized value";
return "Subscript index is an uninitialized value";
if (Msg.isSetter() && (ArgumentNumber == 0))
Os << "Argument for subscript setter is an uninitialized value";
else
Os << "Subscript index is an uninitialized value";
return;
}
llvm_unreachable("Unknown message kind.");
}
case CE_Block:
return "Block call argument is an uninitialized value";
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
<< " block call argument is an uninitialized value";
return;
default:
return "Function call argument is an uninitialized value";
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
<< " function call argument is an uninitialized value";
return;
}
}
bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
const SVal &V,
SourceRange ArgRange,
const Expr *ArgEx,
std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl,
const char *BD) const {
bool CallAndMessageChecker::uninitRefOrPointer(
CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
int ArgumentNumber) const {
if (!Filter.Check_CallAndMessageUnInitRefArg)
return false;
@ -153,12 +162,15 @@ bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
// If parameter is declared as pointer to const in function declaration,
// then check if corresponding argument in function call is
// pointing to undefined symbol value (uninitialized memory).
StringRef Message;
SmallString<200> Buf;
llvm::raw_svector_ostream Os(Buf);
if (ParamDecl->getType()->isPointerType()) {
Message = "Function call argument is a pointer to uninitialized value";
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
<< " function call argument is a pointer to uninitialized value";
} else if (ParamDecl->getType()->isReferenceType()) {
Message = "Function call argument is an uninitialized value";
Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
<< " function call argument is an uninitialized value";
} else
return false;
@ -171,7 +183,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
if (PSV.isUndef()) {
if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
auto R = llvm::make_unique<BugReport>(*BT, Message, N);
auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
R->addRange(ArgRange);
if (ArgEx) {
bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
@ -188,7 +200,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
SVal V,
SourceRange ArgRange,
const Expr *ArgEx,
bool IsFirstArgument,
int ArgumentNumber,
bool CheckUninitFields,
const CallEvent &Call,
std::unique_ptr<BugType> &BT,
@ -196,17 +208,19 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
) const {
const char *BD = "Uninitialized argument value";
if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
ArgumentNumber))
return true;
if (V.isUndef()) {
if (ExplodedNode *N = C.generateErrorNode()) {
LazyInit_BT(BD, BT);
// Generate a report for this bug.
StringRef Desc =
describeUninitializedArgumentInCall(Call, IsFirstArgument);
auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
SmallString<200> Buf;
llvm::raw_svector_ostream Os(Buf);
describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
R->addRange(ArgRange);
if (ArgEx)
bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
@ -435,7 +449,7 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
if(FD && i < FD->getNumParams())
ParamDecl = FD->getParamDecl(i);
if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
Call.getArgExpr(i), i,
checkUninitFields, Call, *BT, ParamDecl))
return;
}

View File

@ -244,7 +244,7 @@ void testUninitDeleteArray() {
void testUninitFree() {
int *x;
free(x); // expected-warning{{Function call argument is an uninitialized value}}
free(x); // expected-warning{{1st function call argument is an uninitialized value}}
}
void testUninitDeleteSink() {

View File

@ -45,8 +45,8 @@ SCDynamicStoreRef anotherCreateRef(unsigned *err, unsigned x);
CreateRefUndef(&storeRef, 4);
//expected-note@-1{{Calling 'CreateRefUndef'}}
//expected-note@-2{{Returning from 'CreateRefUndef'}}
CFRelease(storeRef); //expected-warning {{Function call argument is an uninitialized value}}
//expected-note@-1{{Function call argument is an uninitialized value}}
CFRelease(storeRef); //expected-warning {{1st function call argument is an uninitialized value}}
//expected-note@-1{{1st function call argument is an uninitialized value}}
}
@end
@ -918,12 +918,12 @@ static void CreateRefUndef(SCDynamicStoreRef *storeRef, unsigned x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Function call argument is an uninitialized value</string>
// CHECK-NEXT: <string>1st function call argument is an uninitialized value</string>
// CHECK-NEXT: <key>message</key>
// CHECK-NEXT: <string>Function call argument is an uninitialized value</string>
// CHECK-NEXT: <string>1st function call argument is an uninitialized value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Function call argument is an uninitialized value</string>
// CHECK-NEXT: <key>description</key><string>1st function call argument is an uninitialized value</string>
// CHECK-NEXT: <key>category</key><string>Logic error</string>
// CHECK-NEXT: <key>type</key><string>Uninitialized argument value</string>
// CHECK-NEXT: <key>check_name</key><string>core.CallAndMessage</string>

View File

@ -29,7 +29,7 @@ void rdar10579586(char x);
if (error != ((void*)0))
return error;
rdar10579586(buffer->str_c); // expected-warning {{Function call argument is an uninitialized value}}
rdar10579586(buffer->str_c); // expected-warning {{1st function call argument is an uninitialized value}}
free(buffer);
return ((void*)0);
}

View File

@ -396,7 +396,7 @@ void rdar_7332673_test1() {
int rdar_7332673_test2_aux(char *x);
void rdar_7332673_test2() {
char *value;
if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{Function call argument is an uninitialized value}}
if ( rdar_7332673_test2_aux(value) != 1 ) {} // expected-warning{{1st function call argument is an uninitialized value}}
}
//===----------------------------------------------------------------------===//
@ -673,7 +673,7 @@ typedef void (^RDar_7462324_Callback)(id obj);
builder = ^(id object) {
id x;
if (object) {
builder(x); // expected-warning{{Block call argument is an uninitialized value}}
builder(x); // expected-warning{{1st block call argument is an uninitialized value}}
}
};
builder(target);

View File

@ -796,7 +796,7 @@ int test_uninit_branch_c(void) {
void test_bad_call_aux(int x);
void test_bad_call(void) {
int y;
test_bad_call_aux(y); // expected-warning{{Function call argument is an uninitialized value}}
test_bad_call_aux(y); // expected-warning{{1st function call argument is an uninitialized value}}
}
@interface TestBadArg {}
@ -805,7 +805,7 @@ void test_bad_call(void) {
void test_bad_msg(TestBadArg *p) {
int y;
[p testBadArg:y]; // expected-warning{{Argument in message expression is an uninitialized value}}
[p testBadArg:y]; // expected-warning{{1st argument in message expression is an uninitialized value}}
}
//===----------------------------------------------------------------------===//

View File

@ -286,7 +286,7 @@ void pr4759_aux(int *p) __attribute__((nonnull));
void pr4759() {
int *p;
pr4759_aux(p); // expected-warning{{Function call argument is an uninitialized value}}
pr4759_aux(p); // expected-warning{{1st function call argument is an uninitialized value}}
}
// Relax function call arguments invalidation to be aware of const

View File

@ -107,7 +107,7 @@ struct Type {
void shouldNotCrash() {
decltype(nullptr) p;
if (getSymbol())
invokeF(p); // expected-warning{{Function call argument is an uninit}}
invokeF(p); // expected-warning{{1st function call argument is an uninit}}
if (getSymbol())
invokeF(nullptr);
if (getSymbol()) {

View File

@ -24,16 +24,16 @@ void doStuff_variadic(const int *u, ...){};
void f_1(void) {
int t;
int* tp = &t; // expected-note {{'tp' initialized here}}
doStuff_pointerToConstInt(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_1_1(void) {
int t;
int* tp1 = &t;
int* tp2 = tp1; // expected-note {{'tp2' initialized here}}
doStuff_pointerToConstInt(tp2); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_pointerToConstInt(tp2); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
@ -45,8 +45,8 @@ void f_2(void) {
int t;
int* p = f_2_sub(&t);
int* tp = p; // expected-note {{'tp' initialized here}}
doStuff_pointerToConstInt(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
int z;
@ -62,14 +62,14 @@ void f_4(void) {
void f_5(void) {
int ta[5];
int* tp = ta; // expected-note {{'tp' initialized here}}
doStuff_pointerToConstInt(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_pointerToConstInt(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_5_1(void) {
int ta[5]; // expected-note {{'ta' initialized here}}
doStuff_pointerToConstInt(ta); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_pointerToConstInt(ta); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_6(void) {
@ -92,27 +92,27 @@ void f_7(void) {
void f_8(void) {
int g; // expected-note {{'g' declared without an initial value}}
doStuff2(g); // expected-warning {{Function call argument is an uninitialized value}}
// expected-note@-1 {{Function call argument is an uninitialized value}}
doStuff2(g); // expected-warning {{1st function call argument is an uninitialized value}}
// expected-note@-1 {{1st function call argument is an uninitialized value}}
}
void f_9(void) {
int a[6];
int const *ptau = a; // expected-note {{'ptau' initialized here}}
doStuff_arrayOfConstInt(ptau); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_arrayOfConstInt(ptau); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_10(void) {
int a[6]; // expected-note {{'a' initialized here}}
doStuff_arrayOfConstInt(a); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_arrayOfConstInt(a); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_11(void) {
int t[10]; //expected-note {{'t' initialized here}}
doStuff_constStaticSizedArray(t); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_constStaticSizedArray(t); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f_12(void) {
@ -126,8 +126,8 @@ int f_malloc_1(void) {
ptr = (int *)malloc(sizeof(int)); // expected-note {{Value assigned to 'ptr'}}
doStuff_pointerToConstInt(ptr); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_pointerToConstInt(ptr); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
free(ptr);
return 0;
}
@ -148,16 +148,16 @@ void f_variadic_unp_unv(void) {
int t;
int v;
int* tp = &t; // expected-note {{'tp' initialized here}}
doStuff_variadic(tp,v); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_variadic(tp,v); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
// uninit pointer, init val
void f_variadic_unp_inv(void) {
int t;
int v = 3;
int* tp = &t; // expected-note {{'tp' initialized here}}
doStuff_variadic(tp,v); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_variadic(tp,v); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
// init pointer, uninit val
@ -165,8 +165,8 @@ void f_variadic_inp_unv(void) {
int t=5;
int v; // expected-note {{'v' declared without an initial value}}
int* tp = &t;
doStuff_variadic(tp,v);// expected-warning {{Function call argument is an uninitialized value}}
// expected-note@-1 {{Function call argument is an uninitialized value}}
doStuff_variadic(tp,v);// expected-warning {{2nd function call argument is an uninitialized value}}
// expected-note@-1 {{2nd function call argument is an uninitialized value}}
}
// init pointer, init val
@ -192,8 +192,8 @@ void f_variadic_unp_inp(void) {
int u=3;
int *vp = &u ;
int *tp = &t; // expected-note {{'tp' initialized here}}
doStuff_variadic(tp,vp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_variadic(tp,vp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
//init pointer, uninit pointer
@ -211,6 +211,6 @@ void f_variadic_unp_unp(void) {
int u;
int *vp = &u ;
int *tp = &t; // expected-note {{'tp' initialized here}}
doStuff_variadic(tp,vp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_variadic(tp,vp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}

View File

@ -66,8 +66,8 @@ void f6_2(void) {
int &p = t;
int &s = p;
int &q = s; //expected-note {{'q' initialized here}}
doStuff6(q); //expected-warning {{Function call argument is an uninitialized value}}
//expected-note@-1 {{Function call argument is an uninitialized value}}
doStuff6(q); //expected-warning {{1st function call argument is an uninitialized value}}
//expected-note@-1 {{1st function call argument is an uninitialized value}}
}
void doStuff6_3(int& q_, int *ptr_) {}
@ -78,15 +78,15 @@ void f6_3(void) {
int &p = t;
int &s = p;
int &q = s;
doStuff6_3(q,ptr); //expected-warning {{Function call argument is an uninitialized value}}
//expected-note@-1 {{Function call argument is an uninitialized value}}
doStuff6_3(q,ptr); //expected-warning {{2nd function call argument is an uninitialized value}}
//expected-note@-1 {{2nd function call argument is an uninitialized value}}
}
void f6(void) {
int k; // expected-note {{'k' declared without an initial value}}
doStuff6(k); // expected-warning {{Function call argument is an uninitialized value}}
// expected-note@-1 {{Function call argument is an uninitialized value}}
doStuff6(k); // expected-warning {{1st function call argument is an uninitialized value}}
// expected-note@-1 {{1st function call argument is an uninitialized value}}
}
@ -95,15 +95,15 @@ void f6(void) {
void f5(void) {
int t;
int* tp = &t; // expected-note {{'tp' initialized here}}
doStuff_uninit(tp); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_uninit(tp); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
void f4(void) {
int y; // expected-note {{'y' declared without an initial value}}
doStuff4(y); // expected-warning {{Function call argument is an uninitialized value}}
// expected-note@-1 {{Function call argument is an uninitialized value}}
doStuff4(y); // expected-warning {{1st function call argument is an uninitialized value}}
// expected-note@-1 {{1st function call argument is an uninitialized value}}
}
void f3(void) {
@ -123,6 +123,6 @@ void f1(void) {
void f_uninit(void) {
int x;
doStuff_uninit(&x); // expected-warning {{Function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{Function call argument is a pointer to uninitialized value}}
doStuff_uninit(&x); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}

View File

@ -52,5 +52,5 @@ unsigned f2() {
void f3() {
NSMutableArray *aArray = [NSArray array];
NSString *aString;
[aArray addObject:aString]; // expected-warning {{Argument in message expression is an uninitialized value}}
[aArray addObject:aString]; // expected-warning {{1st argument in message expression is an uninitialized value}}
}

View File

@ -14,7 +14,7 @@ int f1_a(struct FPRec* foo) {
int f1_b() {
int x;
return bar(x)+1; // expected-warning{{Function call argument is an uninitialized value}}
return bar(x)+1; // expected-warning{{1st function call argument is an uninitialized value}}
}
int f2() {

View File

@ -27,7 +27,7 @@ void foo() {
// case with undefined values, too.
c1.b.a = c2->b.a;
#else
c1.b.a = c2->b.a; // expected-warning{{Function call argument is an uninitialized value}}
c1.b.a = c2->b.a; // expected-warning{{1st function call argument is an uninitialized value}}
#endif
}
}