
We have a new policy in place making links to private resources something we try to avoid in source and test files. Normally, we'd organically switch to the new policy rather than make a sweeping change across a project. However, Clang is in a somewhat special circumstance currently: recently, I've had several new contributors run into rdar links around test code which their patch was changing the behavior of. This turns out to be a surprisingly bad experience, especially for newer folks, for a handful of reasons: not understanding what the link is and feeling intimidated by it, wondering whether their changes are actually breaking something important to a downstream in some way, having to hunt down strangers not involved with the patch to impose on them for help, accidental pressure from asking for potentially private IP to be made public, etc. Because folks run into these links entirely by chance (through fixing bugs or working on new features), there's not really a set of problematic links to focus on -- all of the links have basically the same potential for causing these problems. As a result, this is an omnibus patch to remove all such links. This was not a mechanical change; it was done by manually searching for rdar, radar, radr, and other variants to find all the various problematic links. From there, I tried to retain or reword the surrounding comments so that we would lose as little context as possible. However, because most links were just a plain link with no supporting context, the majority of the changes are simple removals. Differential Review: https://reviews.llvm.org/D158071
259 lines
5.3 KiB
C++
259 lines
5.3 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,debug.ExprInspection -verify -Wno-null-dereference -Wno-tautological-undefined-compare -analyzer-config eagerly-assume=false %s
|
|
|
|
void clang_analyzer_eval(bool);
|
|
|
|
typedef typeof(sizeof(int)) size_t;
|
|
void malloc (size_t);
|
|
|
|
void f1() {
|
|
int const &i = 3;
|
|
int b = i;
|
|
|
|
int *p = 0;
|
|
|
|
if (b != 3)
|
|
*p = 1; // no-warning
|
|
}
|
|
|
|
char* ptr();
|
|
char& ref();
|
|
|
|
// These next two tests just shouldn't crash.
|
|
char t1 () {
|
|
ref() = 'c';
|
|
return '0';
|
|
}
|
|
|
|
// just a basic correctness test, the same behavior as t1()
|
|
char t2 () {
|
|
*ptr() = 'c';
|
|
return '0';
|
|
}
|
|
|
|
// Each of the tests below is repeated with pointers as well as references.
|
|
// This is mostly a basic correctness 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
|
|
}
|
|
|
|
|
|
// PR13440
|
|
// 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; }
|
|
|
|
void testArrayToPointerDecayWithNonTypedValueRegion() {
|
|
int *p = x;
|
|
int *q = x;
|
|
clang_analyzer_eval(p[0] == q[0]); // expected-warning{{TRUE}}
|
|
}
|
|
|
|
};
|
|
|
|
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}}
|
|
}
|
|
}
|
|
|
|
void testNullReference() {
|
|
int *x = 0;
|
|
int &y = *x; // expected-warning{{Dereference of null pointer}}
|
|
y = 5;
|
|
}
|
|
|
|
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
|
|
// to produce a supposed "null reference" at runtime. The analyzer should
|
|
// still warn when it can prove such errors.
|
|
int &y = *x;
|
|
if (x != 0)
|
|
return;
|
|
y = 5; // expected-warning{{Dereference of null pointer}}
|
|
}
|
|
|
|
namespace TestReferenceAddress {
|
|
struct S { int &x; };
|
|
S getS();
|
|
S *getSP();
|
|
|
|
void testReferenceAddress(int &x) {
|
|
// 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
|
|
clang_analyzer_eval(&x != 0); // expected-warning{{TRUE}}
|
|
clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}}
|
|
#endif
|
|
|
|
#ifdef ANALYZER_CM_Z3
|
|
clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
|
|
#else
|
|
clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
|
|
#endif
|
|
|
|
#ifdef ANALYZER_CM_Z3
|
|
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{UNKNOWN}}
|
|
#else
|
|
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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}}
|
|
}
|
|
|
|
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}}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
namespace rdar11212286 {
|
|
class B{};
|
|
|
|
B test() {
|
|
B *x = 0;
|
|
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
|
|
}
|
|
}
|
|
|
|
namespace PR15694 {
|
|
class C {
|
|
bool bit : 1;
|
|
template <class T> void bar(const T &obj) {}
|
|
void foo() {
|
|
bar(bit); // don't crash
|
|
}
|
|
};
|
|
}
|