llvm-capstone/clang/test/Analysis/casts.cpp
Artem Dergachev 02955afbb4 [analyzer] pr38668: Do not attempt to cast loaded integers to floats.
This patch is a different approach to landing the reverted r349701.

It is expected to have the same object (memory region) treated as if it has
different types in different program points. The correct behavior for
RegionStore when an object is stored as an object of type T1 but loaded as
an object of type T2 is to store the object as if it has type T1 but cast it
to T2 during load.

Note that the cast here is some sort of a "reinterpret_cast" (even in C). For
instance, if you store an integer and load a float, you won't get your integer
represented as a float; instead, you will get garbage.

Admit that we cannot perform the cast and return an unknown value.

Differential Revision: https://reviews.llvm.org/D55875

rdar://problem/45062567

llvm-svn: 349984
2018-12-22 02:06:51 +00:00

117 lines
2.3 KiB
C++

// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core,debug.ExprInspection -analyzer-store=region -verify %s
void clang_analyzer_eval(bool);
bool PR14634(int x) {
double y = (double)x;
return !y;
}
bool PR14634_implicit(int x) {
double y = (double)x;
return y;
}
void intAsBoolAsSwitchCondition(int c) {
switch ((bool)c) { // expected-warning {{switch condition has boolean value}}
case 0:
break;
}
switch ((int)(bool)c) { // no-warning
case 0:
break;
}
}
int *&castToIntPtrLValueRef(char *p) {
return (int *&)*(int *)p;
}
bool testCastToIntPtrLValueRef(char *p, int *s) {
return castToIntPtrLValueRef(p) != s; // no-crash
}
int *&&castToIntPtrRValueRef(char *p) {
return (int *&&)*(int *)p;
}
bool testCastToIntPtrRValueRef(char *p, int *s) {
return castToIntPtrRValueRef(p) != s; // no-crash
}
bool retrievePointerFromBoolean(int *p) {
bool q;
*reinterpret_cast<int **>(&q) = p;
return q;
}
namespace base_to_derived {
struct A {};
struct B : public A{};
void foo(A* a) {
B* b = (B* ) a;
A* a2 = (A *) b;
clang_analyzer_eval(a2 == a); // expected-warning{{TRUE}}
}
}
namespace base_to_derived_double_inheritance {
struct A {
int x;
};
struct B {
int y;
};
struct C : A, B {};
void foo(B *b) {
C *c = (C *)b;
b->y = 1;
clang_analyzer_eval(c->x); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(c->y); // expected-warning{{TRUE}}
}
} // namespace base_to_derived_double_inheritance
namespace base_to_derived_opaque_class {
class NotInt {
public:
operator int() { return !x; } // no-crash
int x;
};
typedef struct Opaque *OpaqueRef;
typedef void *VeryOpaqueRef;
class Transparent {
public:
int getNotInt() { return NI; }
NotInt NI;
};
class SubTransparent : public Transparent {};
SubTransparent *castToDerived(Transparent *TRef) {
return (SubTransparent *)TRef;
}
void foo(OpaqueRef ORef) {
castToDerived(reinterpret_cast<Transparent *>(ORef))->getNotInt();
}
void foo(VeryOpaqueRef ORef) {
castToDerived(reinterpret_cast<Transparent *>(ORef))->getNotInt();
}
} // namespace base_to_derived_opaque_class
namespace bool_to_nullptr {
struct S {
int *a[1];
bool b;
};
void foo(S s) {
s.b = true;
for (int i = 0; i < 2; ++i)
(void)(s.a[i] != nullptr); // no-crash
}
} // namespace bool_to_nullptr