2018-08-30 04:29:17 +08:00
|
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -Wno-null-dereference -Wno-tautological-undefined-compare -analyzer-config eagerly-assume=false %s
|
2012-08-01 00:34:07 +08:00
|
|
|
|
|
|
|
void clang_analyzer_eval(bool);
|
2010-12-19 10:26:37 +08:00
|
|
|
|
2010-06-04 09:14:56 +08:00
|
|
|
typedef typeof(sizeof(int)) size_t;
|
|
|
|
void malloc (size_t);
|
2010-01-09 17:16:47 +08:00
|
|
|
|
|
|
|
void f1() {
|
2012-05-17 00:01:14 +08:00
|
|
|
int const &i = 3;
|
2010-01-09 17:16:47 +08:00
|
|
|
int b = i;
|
2010-01-10 10:52:56 +08:00
|
|
|
|
|
|
|
int *p = 0;
|
|
|
|
|
|
|
|
if (b != 3)
|
|
|
|
*p = 1; // no-warning
|
2010-01-09 17:16:47 +08:00
|
|
|
}
|
2010-06-03 14:23:18 +08:00
|
|
|
|
|
|
|
char* ptr();
|
|
|
|
char& ref();
|
|
|
|
|
|
|
|
// These next two tests just shouldn't crash.
|
|
|
|
char t1 () {
|
|
|
|
ref() = 'c';
|
|
|
|
return '0';
|
|
|
|
}
|
|
|
|
|
|
|
|
// just a sanity test, the same behavior as t1()
|
|
|
|
char t2 () {
|
|
|
|
*ptr() = 'c';
|
|
|
|
return '0';
|
|
|
|
}
|
2010-06-04 09:14:56 +08:00
|
|
|
|
|
|
|
// Each of the tests below is repeated with pointers as well as references.
|
|
|
|
// This is mostly a sanity check, but then again, both should work!
|
|
|
|
char t3 () {
|
|
|
|
char& r = ref();
|
|
|
|
r = 'c'; // no-warning
|
|
|
|
if (r) return r;
|
|
|
|
return *(char*)0; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
char t4 () {
|
|
|
|
char* p = ptr();
|
|
|
|
*p = 'c'; // no-warning
|
|
|
|
if (*p) return *p;
|
|
|
|
return *(char*)0; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
char t5 (char& r) {
|
|
|
|
r = 'c'; // no-warning
|
|
|
|
if (r) return r;
|
|
|
|
return *(char*)0; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
char t6 (char* p) {
|
|
|
|
*p = 'c'; // no-warning
|
|
|
|
if (*p) return *p;
|
|
|
|
return *(char*)0; // no-warning
|
|
|
|
}
|
2012-08-01 00:34:07 +08:00
|
|
|
|
|
|
|
|
|
|
|
// PR13440 / <rdar://problem/11977113>
|
|
|
|
// Test that the array-to-pointer decay works for array references as well.
|
|
|
|
// More generally, when we want an lvalue for a reference field, we still need
|
|
|
|
// to do one level of load.
|
|
|
|
namespace PR13440 {
|
|
|
|
typedef int T[1];
|
|
|
|
struct S {
|
|
|
|
T &x;
|
|
|
|
|
|
|
|
int *m() { return x; }
|
|
|
|
};
|
|
|
|
|
|
|
|
struct S2 {
|
|
|
|
int (&x)[1];
|
|
|
|
|
|
|
|
int *m() { return x; }
|
2013-05-29 07:24:01 +08:00
|
|
|
|
|
|
|
void testArrayToPointerDecayWithNonTypedValueRegion() {
|
|
|
|
int *p = x;
|
|
|
|
int *q = x;
|
|
|
|
clang_analyzer_eval(p[0] == q[0]); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
2012-08-01 00:34:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void test() {
|
|
|
|
int a[1];
|
|
|
|
S s = { a };
|
|
|
|
S2 s2 = { a };
|
|
|
|
|
|
|
|
if (s.x != a) return;
|
|
|
|
if (s2.x != a) return;
|
|
|
|
|
|
|
|
a[0] = 42;
|
|
|
|
clang_analyzer_eval(s.x[0] == 42); // expected-warning{{TRUE}}
|
|
|
|
clang_analyzer_eval(s2.x[0] == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 05:33:42 +08:00
|
|
|
|
2012-08-04 08:25:30 +08:00
|
|
|
void testNullReference() {
|
2012-08-03 05:33:42 +08:00
|
|
|
int *x = 0;
|
|
|
|
int &y = *x; // expected-warning{{Dereference of null pointer}}
|
|
|
|
y = 5;
|
|
|
|
}
|
|
|
|
|
2012-08-04 08:25:30 +08:00
|
|
|
void testRetroactiveNullReference(int *x) {
|
|
|
|
// According to the C++ standard, there is no such thing as a
|
|
|
|
// "null reference". So the 'if' statement ought to be dead code.
|
|
|
|
// However, Clang (and other compilers) don't actually check that a pointer
|
|
|
|
// value is non-null in the implementation of references, so it is possible
|
2013-04-18 08:15:15 +08:00
|
|
|
// to produce a supposed "null reference" at runtime. The analyzer should
|
2012-08-04 08:25:30 +08:00
|
|
|
// still warn when it can prove such errors.
|
|
|
|
int &y = *x;
|
|
|
|
if (x != 0)
|
|
|
|
return;
|
|
|
|
y = 5; // expected-warning{{Dereference of null pointer}}
|
|
|
|
}
|
|
|
|
|
2017-09-20 15:22:00 +08:00
|
|
|
namespace TestReferenceAddress {
|
|
|
|
struct S { int &x; };
|
|
|
|
S getS();
|
|
|
|
S *getSP();
|
|
|
|
|
2012-08-21 08:27:33 +08:00
|
|
|
void testReferenceAddress(int &x) {
|
2017-03-04 02:02:02 +08:00
|
|
|
// FIXME: Move non-zero reference assumption out of RangeConstraintManager.cpp:422
|
|
|
|
#ifdef ANALYZER_CM_Z3
|
|
|
|
clang_analyzer_eval(&x != 0); // expected-warning{{UNKNOWN}}
|
|
|
|
clang_analyzer_eval(&ref() != 0); // expected-warning{{UNKNOWN}}
|
|
|
|
#else
|
2012-08-21 08:27:33 +08:00
|
|
|
clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}}
|
|
|
|
clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}}
|
2017-03-04 02:02:02 +08:00
|
|
|
#endif
|
2012-08-21 08:27:33 +08:00
|
|
|
|
2017-03-04 02:02:02 +08:00
|
|
|
#ifdef ANALYZER_CM_Z3
|
|
|
|
clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
|
|
|
|
#else
|
2012-10-18 03:35:37 +08:00
|
|
|
clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
|
2017-03-04 02:02:02 +08:00
|
|
|
#endif
|
2012-09-06 01:11:26 +08:00
|
|
|
|
2017-03-04 02:02:02 +08:00
|
|
|
#ifdef ANALYZER_CM_Z3
|
|
|
|
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{UNKNOWN}}
|
|
|
|
#else
|
2012-09-06 01:11:26 +08:00
|
|
|
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
|
2017-03-04 02:02:02 +08:00
|
|
|
#endif
|
2012-08-21 08:27:33 +08:00
|
|
|
}
|
2017-09-20 15:22:00 +08:00
|
|
|
}
|
2012-08-03 05:33:42 +08:00
|
|
|
|
[analyzer] Always derive a CallEvent's return type from its origin expr.
Previously, we preferred to get a result type by looking at the callee's
declared result type. This allowed us to handlereferences, which are
represented in the AST as lvalues of their pointee type. (That is, a call
to a function returning 'int &' has type 'int' and value kind 'lvalue'.)
However, this results in us preferring the original type of a function
over a casted type. This is a problem when a function pointer is casted
to another type, because the conjured result value will have the wrong
type. AdjustedReturnValueChecker is supposed to handle this, but still
doesn't handle the case where there is no "original function" at all,
i.e. where the callee is unknown.
Now, we instead look at the call expression's value kind (lvalue, xvalue,
or prvalue), and adjust the expr's type accordingly. This will have no
effect when the function is inlined, and will conjure the value that will
actually be used when it is not.
This makes AdjustedReturnValueChecker /nearly/ unnecessary; unfortunately,
the cases where it would still be useful are where we need to cast the
result of an inlined function or a checker-evaluated function, and in these
cases we don't know what we're casting /from/ by the time we can do post-
call checks. In light of that, remove AdjustedReturnValueChecker, which
was already not checking quite a few calls.
llvm-svn: 163065
2012-09-02 01:39:00 +08:00
|
|
|
void testFunctionPointerReturn(void *opaque) {
|
|
|
|
typedef int &(*RefFn)();
|
|
|
|
|
|
|
|
RefFn getRef = (RefFn)opaque;
|
|
|
|
|
|
|
|
// Don't crash writing to or reading from this reference.
|
|
|
|
int &x = getRef();
|
|
|
|
x = 42;
|
|
|
|
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
|
|
|
|
}
|
|
|
|
|
2013-03-07 09:23:25 +08:00
|
|
|
int &testReturnNullReference() {
|
|
|
|
int *x = 0;
|
|
|
|
return *x; // expected-warning{{Returning null reference}}
|
|
|
|
}
|
|
|
|
|
|
|
|
char &refFromPointer() {
|
|
|
|
return *ptr();
|
|
|
|
}
|
|
|
|
|
|
|
|
void testReturnReference() {
|
|
|
|
clang_analyzer_eval(ptr() == 0); // expected-warning{{UNKNOWN}}
|
|
|
|
clang_analyzer_eval(&refFromPointer() == 0); // expected-warning{{FALSE}}
|
|
|
|
}
|
|
|
|
|
2013-03-07 11:02:36 +08:00
|
|
|
void intRefParam(int &r) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
void test(int *ptr) {
|
|
|
|
clang_analyzer_eval(ptr == 0); // expected-warning{{UNKNOWN}}
|
|
|
|
|
|
|
|
extern void use(int &ref);
|
|
|
|
use(*ptr);
|
|
|
|
|
|
|
|
clang_analyzer_eval(ptr == 0); // expected-warning{{FALSE}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void testIntRefParam() {
|
|
|
|
int i = 0;
|
|
|
|
intRefParam(i); // no-warning
|
|
|
|
}
|
[analyzer] Always derive a CallEvent's return type from its origin expr.
Previously, we preferred to get a result type by looking at the callee's
declared result type. This allowed us to handlereferences, which are
represented in the AST as lvalues of their pointee type. (That is, a call
to a function returning 'int &' has type 'int' and value kind 'lvalue'.)
However, this results in us preferring the original type of a function
over a casted type. This is a problem when a function pointer is casted
to another type, because the conjured result value will have the wrong
type. AdjustedReturnValueChecker is supposed to handle this, but still
doesn't handle the case where there is no "original function" at all,
i.e. where the callee is unknown.
Now, we instead look at the call expression's value kind (lvalue, xvalue,
or prvalue), and adjust the expr's type accordingly. This will have no
effect when the function is inlined, and will conjure the value that will
actually be used when it is not.
This makes AdjustedReturnValueChecker /nearly/ unnecessary; unfortunately,
the cases where it would still be useful are where we need to cast the
result of an inlined function or a checker-evaluated function, and in these
cases we don't know what we're casting /from/ by the time we can do post-
call checks. In light of that, remove AdjustedReturnValueChecker, which
was already not checking quite a few calls.
llvm-svn: 163065
2012-09-02 01:39:00 +08:00
|
|
|
|
2013-03-07 11:02:36 +08:00
|
|
|
int refParam(int &byteIndex) {
|
|
|
|
return byteIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void testRefParam(int *p) {
|
|
|
|
if (p)
|
|
|
|
;
|
|
|
|
refParam(*p); // expected-warning {{Forming reference to null pointer}}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ptrRefParam(int *&byteIndex) {
|
|
|
|
return *byteIndex; // expected-warning {{Dereference of null pointer}}
|
|
|
|
}
|
|
|
|
void testRefParam2() {
|
|
|
|
int *p = 0;
|
|
|
|
int *&rp = p;
|
|
|
|
ptrRefParam(rp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int *maybeNull() {
|
|
|
|
extern bool coin();
|
|
|
|
static int x;
|
|
|
|
return coin() ? &x : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void use(int &x) {
|
|
|
|
x = 1; // no-warning
|
|
|
|
}
|
|
|
|
|
|
|
|
void testSuppression() {
|
|
|
|
use(*maybeNull());
|
|
|
|
}
|
2012-08-03 05:33:42 +08:00
|
|
|
|
|
|
|
namespace rdar11212286 {
|
|
|
|
class B{};
|
|
|
|
|
|
|
|
B test() {
|
|
|
|
B *x = 0;
|
2013-03-07 11:02:36 +08:00
|
|
|
return *x; // expected-warning {{Forming reference to null pointer}}
|
|
|
|
}
|
|
|
|
|
|
|
|
B testif(B *x) {
|
|
|
|
if (x)
|
|
|
|
;
|
|
|
|
return *x; // expected-warning {{Forming reference to null pointer}}
|
|
|
|
}
|
|
|
|
|
|
|
|
void idc(B *x) {
|
|
|
|
if (x)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
B testidc(B *x) {
|
|
|
|
idc(x);
|
|
|
|
return *x; // no-warning
|
2012-08-03 05:33:42 +08:00
|
|
|
}
|
2012-08-21 08:27:33 +08:00
|
|
|
}
|
2013-04-11 08:58:58 +08:00
|
|
|
|
|
|
|
namespace PR15694 {
|
|
|
|
class C {
|
|
|
|
bool bit : 1;
|
|
|
|
template <class T> void bar(const T &obj) {}
|
|
|
|
void foo() {
|
|
|
|
bar(bit); // don't crash
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|