Casts to bool (and _Bool) are equivalent to checks against zero, not truncations to 1 bit or 8 bits. This improved reasoning does cause a change in the behavior of the alpha BoolAssignment checker. Previously, this checker complained about statements like "bool x = y" if 'y' was known not to be 0 or 1. Now it does not, since that conversion is well-defined. It's hard to say what the "best" behavior here is: this conversion is safe, but might be better written as an explicit comparison against zero. More usefully, besides improving our model of booleans, this fixes spurious warnings when returning the address of a local variable cast to bool. <rdar://problem/13296133> llvm-svn: 180638
136 lines
5.0 KiB
C++
136 lines
5.0 KiB
C++
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
|
|
|
|
typedef __INTPTR_TYPE__ intptr_t;
|
|
|
|
const int& g() {
|
|
int s;
|
|
return s; // expected-warning{{Address of stack memory associated with local variable 's' returned}} expected-warning{{reference to stack memory associated with local variable 's' returned}}
|
|
}
|
|
|
|
const int& g2() {
|
|
int s1;
|
|
int &s2 = s1; // expected-note {{binding reference variable 's2' here}}
|
|
return s2; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}}
|
|
}
|
|
|
|
const int& g3() {
|
|
int s1;
|
|
int &s2 = s1; // expected-note {{binding reference variable 's2' here}}
|
|
int &s3 = s2; // expected-note {{binding reference variable 's3' here}}
|
|
return s3; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}}
|
|
}
|
|
|
|
int get_value();
|
|
|
|
const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
|
|
|
|
const int &get_reference2() {
|
|
const int &x = get_value(); // expected-note {{binding reference variable 'x' here}}
|
|
return x; // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
|
|
}
|
|
|
|
const int &get_reference3() {
|
|
const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}}
|
|
const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}}
|
|
return x2; // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
|
|
}
|
|
|
|
int global_var;
|
|
int *f1() {
|
|
int &y = global_var;
|
|
return &y;
|
|
}
|
|
|
|
int *f2() {
|
|
int x1;
|
|
int &x2 = x1; // expected-note {{binding reference variable 'x2' here}}
|
|
return &x2; // expected-warning{{Address of stack memory associated with local variable 'x1' returned}} expected-warning {{address of stack memory associated with local variable 'x1' returned}}
|
|
}
|
|
|
|
int *f3() {
|
|
int x1;
|
|
int *const &x2 = &x1; // expected-note {{binding reference variable 'x2' here}}
|
|
return x2; // expected-warning {{address of stack memory associated with local variable 'x1' returned}} expected-warning {{Address of stack memory associated with local variable 'x1' returned to caller}}
|
|
}
|
|
|
|
const int *f4() {
|
|
const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}}
|
|
const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}}
|
|
return &x2; // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning address of local temporary}}
|
|
}
|
|
|
|
struct S {
|
|
int x;
|
|
};
|
|
|
|
int *mf() {
|
|
S s1;
|
|
S &s2 = s1; // expected-note {{binding reference variable 's2' here}}
|
|
int &x = s2.x; // expected-note {{binding reference variable 'x' here}}
|
|
return &x; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{address of stack memory associated with local variable 's1' returned}}
|
|
}
|
|
|
|
void *lf() {
|
|
label:
|
|
void *const &x = &&label; // expected-note {{binding reference variable 'x' here}}
|
|
return x; // expected-warning {{returning address of label, which is local}}
|
|
}
|
|
|
|
template <typename T>
|
|
struct TS {
|
|
int *get();
|
|
int *m() {
|
|
int *&x = get();
|
|
return x;
|
|
}
|
|
};
|
|
|
|
// rdar://11345441
|
|
int* f5() {
|
|
int& i = i; // expected-warning {{Assigned value is garbage or undefined}} expected-note {{binding reference variable 'i' here}} expected-warning{{reference 'i' is not yet bound to a value when used within its own initialization}}
|
|
return &i; // expected-warning {{address of stack memory associated with local variable 'i' returned}}
|
|
}
|
|
|
|
void *radar13226577() {
|
|
void *p = &p;
|
|
return p; // expected-warning {{stack memory associated with local variable 'p' returned to caller}}
|
|
}
|
|
|
|
namespace rdar13296133 {
|
|
class ConvertsToBool {
|
|
public:
|
|
operator bool() const { return this; }
|
|
};
|
|
|
|
class ConvertsToIntptr {
|
|
public:
|
|
operator intptr_t() const { return reinterpret_cast<intptr_t>(this); }
|
|
};
|
|
|
|
class ConvertsToPointer {
|
|
public:
|
|
operator const void *() const { return this; }
|
|
};
|
|
|
|
intptr_t returnAsNonLoc() {
|
|
ConvertsToIntptr obj;
|
|
return obj; // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}
|
|
}
|
|
|
|
bool returnAsBool() {
|
|
ConvertsToBool obj;
|
|
return obj; // no-warning
|
|
}
|
|
|
|
intptr_t returnAsNonLocViaPointer() {
|
|
ConvertsToPointer obj;
|
|
return reinterpret_cast<intptr_t>(static_cast<const void *>(obj)); // expected-warning{{Address of stack memory associated with local variable 'obj' returned to caller}}
|
|
}
|
|
|
|
bool returnAsBoolViaPointer() {
|
|
ConvertsToPointer obj;
|
|
return obj; // no-warning
|
|
}
|
|
}
|
|
|