Null dereferences are suppressed if the lvalue was constrained to 0 for the first time inside a sub-function that was inlined during analysis, because such constraint is a valid defensive check that does not, by itself, indicate that null pointer case is anyhow special for the caller. If further operations on the lvalue are performed, the symbolic lvalue is collapsed to concrete null pointer, and we need to track where does the null pointer come from. Improve such tracking for lvalue operations involving operator &. rdar://problem/27876009 Differential Revision: https://reviews.llvm.org/D31982 llvm-svn: 301224
87 lines
1.5 KiB
C++
87 lines
1.5 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
|
|
// expected-no-diagnostics
|
|
|
|
extern void __assert_fail (__const char *__assertion, __const char *__file,
|
|
unsigned int __line, __const char *__function)
|
|
__attribute__ ((__noreturn__));
|
|
#define assert(expr) \
|
|
((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
|
|
|
|
class ButterFly {
|
|
private:
|
|
ButterFly() { }
|
|
public:
|
|
int triggerderef() {
|
|
return 0;
|
|
}
|
|
};
|
|
ButterFly *getInP();
|
|
class X{
|
|
ButterFly *p;
|
|
void setP(ButterFly *inP) {
|
|
if(inP)
|
|
;
|
|
p = inP;
|
|
};
|
|
void subtest1() {
|
|
ButterFly *inP = getInP();
|
|
setP(inP);
|
|
}
|
|
int subtest2() {
|
|
int c = p->triggerderef(); // no-warning
|
|
return c;
|
|
}
|
|
int test() {
|
|
subtest1();
|
|
return subtest2();
|
|
}
|
|
};
|
|
|
|
typedef const int *Ty;
|
|
extern
|
|
Ty notNullArg(Ty cf) __attribute__((nonnull));
|
|
typedef const void *CFTypeRef;
|
|
extern Ty getTyVal();
|
|
inline void radar13224271_callee(Ty def, Ty& result ) {
|
|
result = def;
|
|
// Clearly indicates that result cannot be 0 if def is not NULL.
|
|
assert( (result != 0) || (def == 0) );
|
|
}
|
|
void radar13224271_caller()
|
|
{
|
|
Ty value;
|
|
radar13224271_callee(getTyVal(), value );
|
|
notNullArg(value); // no-warning
|
|
}
|
|
|
|
struct Foo {
|
|
int *ptr;
|
|
Foo(int *p) {
|
|
*p = 1; // no-warning
|
|
}
|
|
};
|
|
void idc(int *p3) {
|
|
if (p3)
|
|
;
|
|
}
|
|
int *retNull() {
|
|
return 0;
|
|
}
|
|
void test(int *p1, int *p2) {
|
|
idc(p1);
|
|
Foo f(p1);
|
|
}
|
|
|
|
struct Bar {
|
|
int x;
|
|
};
|
|
void idcBar(Bar *b) {
|
|
if (b)
|
|
;
|
|
}
|
|
void testRefToField(Bar *b) {
|
|
idcBar(b);
|
|
int &x = b->x; // no-warning
|
|
x = 5;
|
|
}
|