// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.MemoryUnsafeCastChecker -verify %s class Base { }; class Derived : public Base { }; template Target& downcast_ref(Source& source){ [[clang::suppress]] return static_cast(source); } template Target* downcast_ptr(Source* source){ [[clang::suppress]] return static_cast(source); } void test_pointers(Base *base) { Derived *derived_static = static_cast(base); // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}} Derived *derived_reinterpret = reinterpret_cast(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(base); // no warning } void test_non_pointers(Derived derived) { Base base_static = static_cast(derived); // no warning } void test_refs(Base &base) { Derived &derived_static = static_cast(base); // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 'Derived'}} Derived &derived_reinterpret = reinterpret_cast(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(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(base_ptr); // expected-warning@-1{{Unsafe cast from base type 'BaseVirtual' to derived type 'DerivedVirtual'}} DerivedVirtual &derived_dynamic_ref = dynamic_cast(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(base_struct); // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}} struct DerivedStruct *derived_reinterpret = reinterpret_cast(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(base_struct); // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}} DStruct &derived_reinterpret = reinterpret_cast(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(base_struct); // expected-warning@-1{{Unsafe cast from base type 'BaseStruct' to derived type 'DerivedStruct'}} } template class BaseTemplate { }; template class DerivedTemplate : public BaseTemplate { }; void test_templates(BaseTemplate *base, BaseTemplate &base_ref) { DerivedTemplate *derived_static = static_cast*>(base); // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}} DerivedTemplate *derived_reinterpret = reinterpret_cast*>(base); // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}} DerivedTemplate *derived_c = (DerivedTemplate*)base; // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}} DerivedTemplate &derived_static_ref = static_cast&>(base_ref); // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}} DerivedTemplate &derived_reinterpret_ref = reinterpret_cast&>(base_ref); // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}} DerivedTemplate &derived_c_ref = (DerivedTemplate&)base_ref; // expected-warning@-1{{Unsafe cast from base type 'BaseTemplate' to derived type 'DerivedTemplate'}} } #define CAST_MACRO_STATIC(X,Y) (static_cast(X)) #define CAST_MACRO_REINTERPRET(X,Y) (reinterpret_cast(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(base_struct); // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}} struct DerivedStructCpp *derived_reinterpret = reinterpret_cast(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(base_struct); // expected-warning@-1{{Unsafe cast from base type 'BaseStructCpp' to derived type 'DerivedStructCpp'}} DStructCpp &derived_reinterpret = reinterpret_cast(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(derived_struct); // no warning BStructCpp &base_reinterpret = reinterpret_cast(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(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(t1); // expected-warning@-1{{Unsafe cast from type 'Type1' to an unrelated type 'Type2'}} Type2 &t2_same = reinterpret_cast(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(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(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(b); // expected-warning@-1{{Unsafe cast from type 'StructB' to an unrelated type 'StructA'}} StA &a_same = (StA&)a; // no warning } template class DeferrableRefCounted { public: void deref() const { auto this_to_T = static_cast(this); // no warning } }; class SomeArrayClass : public DeferrableRefCounted { }; void test_this_to_template(SomeArrayClass *ptr) { ptr->deref(); }; template class CanMakeWeakPtrBase { public: void initializeWeakPtrFactory() const { auto &this_to_T = static_cast(*this); } }; template using CanMakeWeakPtr = CanMakeWeakPtrBase; class EventLoop : public CanMakeWeakPtr { }; void test_this_to_template_ref(EventLoop *ptr) { ptr->initializeWeakPtrFactory(); };