This PR introduces a new checker `[alpha.webkit.MemoryUnsafeCastChecker]` that warns all downcasts from a base type to a derived type. rdar://137766829
267 lines
11 KiB
C++
267 lines
11 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.MemoryUnsafeCastChecker -verify %s
|
|
|
|
class Base { };
|
|
class Derived : public Base { };
|
|
|
|
template<typename Target, typename Source>
|
|
Target& downcast_ref(Source& source){
|
|
[[clang::suppress]]
|
|
return static_cast<Target&>(source);
|
|
}
|
|
|
|
template<typename Target, typename Source>
|
|
Target* downcast_ptr(Source* source){
|
|
[[clang::suppress]]
|
|
return static_cast<Target*>(source);
|
|
}
|
|
|
|
void test_pointers(Base *base) {
|
|
Derived *derived_static = static_cast<Derived*>(base);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived *derived_reinterpret = reinterpret_cast<Derived*>(base);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived *derived_c = (Derived*)base;
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived *derived_d = downcast_ptr<Derived, Base>(base); // no warning
|
|
}
|
|
|
|
void test_non_pointers(Derived derived) {
|
|
Base base_static = static_cast<Base>(derived); // no warning
|
|
}
|
|
|
|
void test_refs(Base &base) {
|
|
Derived &derived_static = static_cast<Derived&>(base);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived &derived_reinterpret = reinterpret_cast<Derived&>(base);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived &derived_c = (Derived&)base;
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived &derived_d = downcast_ref<Derived, Base>(base); // no warning
|
|
}
|
|
|
|
class BaseVirtual {
|
|
virtual void virtual_base_function();
|
|
};
|
|
|
|
class DerivedVirtual : public BaseVirtual {
|
|
void virtual_base_function() override { }
|
|
};
|
|
|
|
void test_dynamic_casts(BaseVirtual *base_ptr, BaseVirtual &base_ref) {
|
|
DerivedVirtual *derived_dynamic_ptr = dynamic_cast<DerivedVirtual*>(base_ptr);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseVirtual' to derived type 'DerivedVirtual'}}
|
|
DerivedVirtual &derived_dynamic_ref = dynamic_cast<DerivedVirtual&>(base_ref);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseVirtual' to derived type 'DerivedVirtual'}}
|
|
}
|
|
|
|
struct BaseStruct { };
|
|
struct DerivedStruct : BaseStruct { };
|
|
|
|
void test_struct_pointers(struct BaseStruct *base_struct) {
|
|
struct DerivedStruct *derived_static = static_cast<struct DerivedStruct*>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
struct DerivedStruct *derived_reinterpret = reinterpret_cast<struct DerivedStruct*>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
struct DerivedStruct *derived_c = (struct DerivedStruct*)base_struct;
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
}
|
|
|
|
typedef struct BaseStruct BStruct;
|
|
typedef struct DerivedStruct DStruct;
|
|
|
|
void test_struct_refs(BStruct &base_struct) {
|
|
DStruct &derived_static = static_cast<DStruct&>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
DStruct &derived_reinterpret = reinterpret_cast<DStruct&>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
DStruct &derived_c = (DStruct&)base_struct;
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
}
|
|
|
|
int counter = 0;
|
|
void test_recursive(BStruct &base_struct) {
|
|
if (counter == 5)
|
|
return;
|
|
counter++;
|
|
DStruct &derived_static = static_cast<DStruct&>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}}
|
|
}
|
|
|
|
template<typename T>
|
|
class BaseTemplate { };
|
|
|
|
template<typename T>
|
|
class DerivedTemplate : public BaseTemplate<T> { };
|
|
|
|
void test_templates(BaseTemplate<int> *base, BaseTemplate<int> &base_ref) {
|
|
DerivedTemplate<int> *derived_static = static_cast<DerivedTemplate<int>*>(base);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
|
|
DerivedTemplate<int> *derived_reinterpret = reinterpret_cast<DerivedTemplate<int>*>(base);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
|
|
DerivedTemplate<int> *derived_c = (DerivedTemplate<int>*)base;
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
|
|
DerivedTemplate<int> &derived_static_ref = static_cast<DerivedTemplate<int>&>(base_ref);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
|
|
DerivedTemplate<int> &derived_reinterpret_ref = reinterpret_cast<DerivedTemplate<int>&>(base_ref);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
|
|
DerivedTemplate<int> &derived_c_ref = (DerivedTemplate<int>&)base_ref;
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}}
|
|
}
|
|
|
|
#define CAST_MACRO_STATIC(X,Y) (static_cast<Y>(X))
|
|
#define CAST_MACRO_REINTERPRET(X,Y) (reinterpret_cast<Y>(X))
|
|
#define CAST_MACRO_C(X,Y) ((Y)X)
|
|
|
|
void test_macro_static(Base *base, Derived *derived, Base &base_ref) {
|
|
Derived *derived_static = CAST_MACRO_STATIC(base, Derived*);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived &derived_static_ref = CAST_MACRO_STATIC(base_ref, Derived&);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Base *base_static_same = CAST_MACRO_STATIC(base, Base*); // no warning
|
|
Base *base_static_upcast = CAST_MACRO_STATIC(derived, Base*); // no warning
|
|
}
|
|
|
|
void test_macro_reinterpret(Base *base, Derived *derived, Base &base_ref) {
|
|
Derived *derived_reinterpret = CAST_MACRO_REINTERPRET(base, Derived*);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived &derived_reinterpret_ref = CAST_MACRO_REINTERPRET(base_ref, Derived&);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Base *base_reinterpret_same = CAST_MACRO_REINTERPRET(base, Base*); // no warning
|
|
Base *base_reinterpret_upcast = CAST_MACRO_REINTERPRET(derived, Base*); // no warning
|
|
}
|
|
|
|
void test_macro_c(Base *base, Derived *derived, Base &base_ref) {
|
|
Derived *derived_c = CAST_MACRO_C(base, Derived*);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Derived &derived_c_ref = CAST_MACRO_C(base_ref, Derived&);
|
|
// expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}}
|
|
Base *base_c_same = CAST_MACRO_C(base, Base*); // no warning
|
|
Base *base_c_upcast = CAST_MACRO_C(derived, Base*); // no warning
|
|
}
|
|
|
|
struct BaseStructCpp {
|
|
int t;
|
|
void increment() { t++; }
|
|
};
|
|
struct DerivedStructCpp : BaseStructCpp {
|
|
void increment_t() {increment();}
|
|
};
|
|
|
|
void test_struct_cpp_pointers(struct BaseStructCpp *base_struct) {
|
|
struct DerivedStructCpp *derived_static = static_cast<struct DerivedStructCpp*>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
|
|
struct DerivedStructCpp *derived_reinterpret = reinterpret_cast<struct DerivedStructCpp*>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
|
|
struct DerivedStructCpp *derived_c = (struct DerivedStructCpp*)base_struct;
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
|
|
}
|
|
|
|
typedef struct BaseStructCpp BStructCpp;
|
|
typedef struct DerivedStructCpp DStructCpp;
|
|
|
|
void test_struct_cpp_refs(BStructCpp &base_struct, DStructCpp &derived_struct) {
|
|
DStructCpp &derived_static = static_cast<DStructCpp&>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
|
|
DStructCpp &derived_reinterpret = reinterpret_cast<DStructCpp&>(base_struct);
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
|
|
DStructCpp &derived_c = (DStructCpp&)base_struct;
|
|
// expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}}
|
|
BStructCpp &base = (BStructCpp&)derived_struct; // no warning
|
|
BStructCpp &base_static = static_cast<BStructCpp&>(derived_struct); // no warning
|
|
BStructCpp &base_reinterpret = reinterpret_cast<BStructCpp&>(derived_struct); // no warning
|
|
}
|
|
|
|
struct stack_st { };
|
|
|
|
#define STACK_OF(type) struct stack_st_##type
|
|
|
|
void test_stack(stack_st *base) {
|
|
STACK_OF(void) *derived = (STACK_OF(void)*)base;
|
|
// expected-warning@-1{{Unsafe cast from type 'stack_st' to an unrelated type 'stack_st_void'}}
|
|
}
|
|
|
|
class Parent { };
|
|
class Child1 : public Parent { };
|
|
class Child2 : public Parent { };
|
|
|
|
void test_common_parent(Child1 *c1, Child2 *c2) {
|
|
Child2 *c2_cstyle = (Child2 *)c1;
|
|
// expected-warning@-1{{Unsafe cast from type 'Child1' to an unrelated type 'Child2'}}
|
|
Child2 *c2_reinterpret = reinterpret_cast<Child2 *>(c1);
|
|
// expected-warning@-1{{Unsafe cast from type 'Child1' to an unrelated type 'Child2'}}
|
|
}
|
|
|
|
class Type1 { };
|
|
class Type2 { };
|
|
|
|
void test_unrelated_ref(Type1 &t1, Type2 &t2) {
|
|
Type2 &t2_cstyle = (Type2 &)t1;
|
|
// expected-warning@-1{{Unsafe cast from type 'Type1' to an unrelated type 'Type2'}}
|
|
Type2 &t2_reinterpret = reinterpret_cast<Type2 &>(t1);
|
|
// expected-warning@-1{{Unsafe cast from type 'Type1' to an unrelated type 'Type2'}}
|
|
Type2 &t2_same = reinterpret_cast<Type2 &>(t2); // no warning
|
|
}
|
|
|
|
|
|
class VirtualClass1 {
|
|
virtual void virtual_base_function();
|
|
};
|
|
|
|
class VirtualClass2 {
|
|
void virtual_base_function();
|
|
};
|
|
|
|
void test_unrelated_virtual(VirtualClass1 &v1) {
|
|
VirtualClass2 &v2 = dynamic_cast<VirtualClass2 &>(v1);
|
|
// expected-warning@-1{{Unsafe cast from type 'VirtualClass1' to an unrelated type 'VirtualClass2'}}
|
|
}
|
|
|
|
struct StructA { };
|
|
struct StructB { };
|
|
|
|
typedef struct StructA StA;
|
|
typedef struct StructB StB;
|
|
|
|
void test_struct_unrelated_refs(StA &a, StB &b) {
|
|
StB &b_reinterpret = reinterpret_cast<StB&>(a);
|
|
// expected-warning@-1{{Unsafe cast from type 'StructA' to an unrelated type 'StructB'}}
|
|
StB &b_c = (StB&)a;
|
|
// expected-warning@-1{{Unsafe cast from type 'StructA' to an unrelated type 'StructB'}}
|
|
StA &a_local = (StA&)b;
|
|
// expected-warning@-1{{Unsafe cast from type 'StructB' to an unrelated type 'StructA'}}
|
|
StA &a_reinterpret = reinterpret_cast<StA&>(b);
|
|
// expected-warning@-1{{Unsafe cast from type 'StructB' to an unrelated type 'StructA'}}
|
|
StA &a_same = (StA&)a; // no warning
|
|
}
|
|
|
|
template<typename T>
|
|
class DeferrableRefCounted {
|
|
public:
|
|
void deref() const {
|
|
auto this_to_T = static_cast<const T*>(this); // no warning
|
|
}
|
|
};
|
|
|
|
class SomeArrayClass : public DeferrableRefCounted<SomeArrayClass> { };
|
|
|
|
void test_this_to_template(SomeArrayClass *ptr) {
|
|
ptr->deref();
|
|
};
|
|
|
|
template<typename WeakPtrFactoryType>
|
|
class CanMakeWeakPtrBase {
|
|
public:
|
|
void initializeWeakPtrFactory() const {
|
|
auto &this_to_T = static_cast<const WeakPtrFactoryType&>(*this);
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
using CanMakeWeakPtr = CanMakeWeakPtrBase<T>;
|
|
|
|
class EventLoop : public CanMakeWeakPtr<EventLoop> { };
|
|
|
|
void test_this_to_template_ref(EventLoop *ptr) {
|
|
ptr->initializeWeakPtrFactory();
|
|
};
|