
The checks for the 'z' and 't' format specifiers added in the original PR #143653 had some issues and were overly strict, causing some build failures and were consequently reverted at4c85bf2fe8
. In the latest commit27c58629ec
, I relaxed the checks for the 'z' and 't' format specifiers, so warnings are now only issued when they are used with mismatched types. The original intent of these checks was to diagnose code that assumes the underlying type of `size_t` is `unsigned` or `unsigned long`, for example: ```c printf("%zu", 1ul); // Not portable, but not an error when size_t is unsigned long ``` However, it produced a significant number of false positives. This was partly because Clang does not treat the `typedef` `size_t` and `__size_t` as having a common "sugar" type, and partly because a large amount of existing code either assumes `unsigned` (or `unsigned long`) is `size_t`, or they define the equivalent of size_t in their own way (such as sanitizer_internal_defs.h).2e67dcfdcd/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h (L203)
132 lines
6.0 KiB
C++
132 lines
6.0 KiB
C++
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -verify %s \
|
|
// RUN: -analyzer-checker=debug.ExprInspection \
|
|
// RUN: -analyzer-checker=unix.cstring \
|
|
// RUN: -analyzer-checker=unix.Malloc \
|
|
// RUN: -analyzer-config display-checker-name=false
|
|
|
|
typedef unsigned long size_t;
|
|
|
|
struct S {
|
|
struct S3 {
|
|
int y[10];
|
|
};
|
|
struct S2 : S3 {
|
|
int *x;
|
|
} s2[10];
|
|
int z;
|
|
};
|
|
|
|
|
|
void clang_analyzer_explain(int);
|
|
void clang_analyzer_explain(void *);
|
|
void clang_analyzer_explain(const int *);
|
|
void clang_analyzer_explain(S);
|
|
|
|
size_t clang_analyzer_getExtent(void *);
|
|
|
|
size_t strlen(const char *);
|
|
|
|
int conjure();
|
|
S conjure_S();
|
|
|
|
int glob;
|
|
static int stat_glob;
|
|
void *glob_ptr;
|
|
|
|
// Test strings are regex'ed because we need to match exact string
|
|
// rather than a substring.
|
|
|
|
void test_1(int param, void *ptr) {
|
|
clang_analyzer_explain(&glob); // expected-warning-re{{{{^pointer to global variable 'glob'$}}}}
|
|
clang_analyzer_explain(param); // expected-warning-re{{{{^argument 'param'$}}}}
|
|
clang_analyzer_explain(ptr); // expected-warning-re{{{{^argument 'ptr'$}}}}
|
|
if (param == 42)
|
|
clang_analyzer_explain(param); // expected-warning-re{{{{^signed 32-bit integer '42'$}}}}
|
|
}
|
|
|
|
void test_2(char *ptr, int ext) {
|
|
clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}}
|
|
clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type '__size_t' tied to pointee of argument 'ptr'$}}}}
|
|
clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at CFG element 'conjure\(\)'$}}}}
|
|
clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure\(\)'\) for global variable 'glob'$}}}}
|
|
clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure\(\)'\) for global variable 'glob_ptr'$}}}}
|
|
clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}}
|
|
int *x = new int[ext];
|
|
clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at CFG element 'CFGNewAllocator\(int \*\)'$}}}}
|
|
// Sic! What gets computed is the extent of the element-region.
|
|
clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(argument 'ext'\) \* 4$}}}}
|
|
delete[] x;
|
|
}
|
|
|
|
void test_3(S s) {
|
|
clang_analyzer_explain(&s); // expected-warning-re{{{{^pointer to parameter 's'$}}}}
|
|
clang_analyzer_explain(s.z); // expected-warning-re{{{{^initial value of field 'z' of parameter 's'$}}}}
|
|
clang_analyzer_explain(&s.s2[5].y[3]); // expected-warning-re{{{{^pointer to element of type 'int' with index 3 of field 'y' of base object 'S::S3' inside element of type 'struct S::S2' with index 5 of field 's2' of parameter 's'$}}}}
|
|
if (!s.s2[7].x) {
|
|
clang_analyzer_explain(s.s2[7].x); // expected-warning-re{{{{^concrete memory address '0'$}}}}
|
|
// FIXME: we need to be explaining '1' rather than '0' here; not explainer bug.
|
|
clang_analyzer_explain(s.s2[7].x + 1); // expected-warning-re{{{{^concrete memory address '0'$}}}}
|
|
}
|
|
}
|
|
|
|
void test_4(int x, int y) {
|
|
int z;
|
|
static int stat;
|
|
clang_analyzer_explain(-x); // expected-warning-re{{{{^\- \(argument 'x'\)$}}}}
|
|
clang_analyzer_explain(x + 1); // expected-warning-re{{{{^\(argument 'x'\) \+ 1$}}}}
|
|
clang_analyzer_explain(1 + y); // expected-warning-re{{{{^\(argument 'y'\) \+ 1$}}}}
|
|
clang_analyzer_explain(x + y); // expected-warning-re{{{{^\(argument 'x'\) \+ \(argument 'y'\)$}}}}
|
|
clang_analyzer_explain(z); // expected-warning-re{{{{^undefined value$}}}}
|
|
clang_analyzer_explain(&z); // expected-warning-re{{{{^pointer to local variable 'z'$}}}}
|
|
clang_analyzer_explain(stat); // expected-warning-re{{{{^signed 32-bit integer '0'$}}}}
|
|
clang_analyzer_explain(&stat); // expected-warning-re{{{{^pointer to static local variable 'stat'$}}}}
|
|
clang_analyzer_explain(stat_glob); // expected-warning-re{{{{^initial value of global variable 'stat_glob'$}}}}
|
|
clang_analyzer_explain(&stat_glob); // expected-warning-re{{{{^pointer to global variable 'stat_glob'$}}}}
|
|
clang_analyzer_explain((int[]){1, 2, 3}); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of temporary object constructed at statement '\(int\[3\]\)\{1, 2, 3\}'$}}}}
|
|
}
|
|
|
|
namespace {
|
|
class C {
|
|
int x[10];
|
|
|
|
public:
|
|
void test_5(int i) {
|
|
clang_analyzer_explain(this); // expected-warning-re{{{{^pointer to 'this' object$}}}}
|
|
clang_analyzer_explain(&x[i]); // expected-warning-re{{{{^pointer to element of type 'int' with index 'argument 'i'' of field 'x' of 'this' object$}}}}
|
|
clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to region allocated by '__builtin_alloca\(i\)'$}}}}
|
|
}
|
|
};
|
|
} // end of anonymous namespace
|
|
|
|
void test_6() {
|
|
clang_analyzer_explain(conjure_S()); // expected-warning-re{{{{^symbol of type 'int' conjured at CFG element 'conjure_S\(\) \(CXXRecordTypedCall, \+0\)'$}}}}
|
|
clang_analyzer_explain(conjure_S().z); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at CFG element 'conjure_S\(\) \(CXXRecordTypedCall, \)'\) for field 'z' of temporary object constructed at statement 'conjure_S\(\)'$}}}}
|
|
}
|
|
|
|
class C_top_level {
|
|
public:
|
|
C_top_level(int param) {
|
|
clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
|
|
}
|
|
};
|
|
|
|
class C_non_top_level {
|
|
public:
|
|
C_non_top_level(int param) {
|
|
clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
|
|
}
|
|
};
|
|
|
|
void test_7(int n) {
|
|
C_non_top_level c(n);
|
|
|
|
auto lambda_top_level = [n](int param) {
|
|
clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
|
|
};
|
|
auto lambda_non_top_level = [n](int param) {
|
|
clang_analyzer_explain(¶m); // expected-warning-re{{{{^pointer to parameter 'param'$}}}}
|
|
};
|
|
|
|
lambda_non_top_level(n);
|
|
}
|