diff options
author | anonymous <local@localhost> | 2011-01-04 07:38:25 +0600 |
---|---|---|
committer | anonymous <local@localhost> | 2011-01-04 07:38:25 +0600 |
commit | 51b577f026c241da85acdb469a3d7349a785f636 (patch) | |
tree | c52ecd31021d053171dc1a2966301888d4e2fa9f | |
parent | 36d91e1f88660a8b11147a15a05c60b8f0f0d9f0 (diff) | |
download | libcxxrt-51b577f026c241da85acdb469a3d7349a785f636.tar.gz libcxxrt-51b577f026c241da85acdb469a3d7349a785f636.tar.bz2 libcxxrt-51b577f026c241da85acdb469a3d7349a785f636.tar.xz |
fix for COMPILER-8903: throwing/catching pointers with casts, void*, etc
-rw-r--r-- | src/dynamic_cast.cc | 31 | ||||
-rw-r--r-- | src/exception.cc | 53 | ||||
-rw-r--r-- | src/typeinfo.h | 3 |
3 files changed, 71 insertions, 16 deletions
diff --git a/src/dynamic_cast.cc b/src/dynamic_cast.cc index 2d1f64c..7d15d23 100644 --- a/src/dynamic_cast.cc +++ b/src/dynamic_cast.cc @@ -16,6 +16,11 @@ struct vtable_header #define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off) +bool __class_type_info::can_cast_to(const struct __class_type_info *other) const +{ + return this == other; +} + void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const { if (this == other) @@ -24,6 +29,13 @@ void *__class_type_info::cast_to(void *obj, const struct __class_type_info *othe } return 0; } + + +bool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const +{ + return this == other || __base_type->can_cast_to(other); +} + void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const { if (this == other) @@ -32,6 +44,25 @@ void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *o } return __base_type->cast_to(obj, other); } + + +bool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const +{ + if (this == other) + { + return true; + } + for (unsigned int i=0 ; i<__base_count ; i++) + { + const __base_class_type_info *info = &__base_info[i]; + if(info->__base_type->can_cast_to(other)) + { + return true; + } + } + return false; +} + void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const { if (this == other) diff --git a/src/exception.cc b/src/exception.cc index 740eee4..3920cf7 100644 --- a/src/exception.cc +++ b/src/exception.cc @@ -575,15 +575,19 @@ static std::type_info *get_type_info_entry(_Unwind_Context *context, lsda->type_table_encoding, offset, start); } + /** * Checks the type signature found in a handler against the type of the thrown * object. If ex is 0 then it is assumed to be a foreign exception and only * matches cleanups. */ -static bool check_type_signature(__cxa_exception *ex, std::type_info *type) +static bool check_type_signature(__cxa_exception *ex, const std::type_info *type) { void *exception_ptr = (void*)(ex+1); - __pointer_type_info *ptr_type = dynamic_cast<__pointer_type_info*>(ex->exceptionType); + const std::type_info *ex_type = ex->exceptionType; + + const __pointer_type_info *ptr_type = + dynamic_cast<const __pointer_type_info*>(ex_type); if (0 != ptr_type) { exception_ptr = *(void**)exception_ptr; @@ -605,27 +609,44 @@ static bool check_type_signature(__cxa_exception *ex, std::type_info *type) if (0 == ex) { return false; } + const __pointer_type_info *target_ptr_type = + dynamic_cast<const __pointer_type_info*>(type); + + if (0 != ptr_type && 0 != target_ptr_type) + { + if (ptr_type->__flags & ~target_ptr_type->__flags) { + // handler pointer is less qualified + return false; + } + + // special case for void* handler + if(*target_ptr_type->__pointee == typeid(void)) { + ex->adjustedPtr = exception_ptr; + return true; + } + + ex_type = ptr_type->__pointee; + type = target_ptr_type->__pointee; + } + // If the types are the same, no casting is needed. - if (*type == *ex->exceptionType) + if (*type == *ex_type) { ex->adjustedPtr = exception_ptr; return true; } - __class_type_info *cls_type = dynamic_cast<__class_type_info*>(ex->exceptionType); - __class_type_info *target_cls_type = dynamic_cast<__class_type_info*>(type); - if (0 != cls_type && 0 != target_cls_type) + + const __class_type_info *cls_type = + dynamic_cast<const __class_type_info*>(ex_type); + const __class_type_info *target_cls_type = + dynamic_cast<const __class_type_info*>(type); + + if (0 != cls_type && + 0 != target_cls_type && + cls_type->can_cast_to(target_cls_type)) { ex->adjustedPtr = cls_type->cast_to(exception_ptr, target_cls_type); - return 0 != ex->adjustedPtr; - } - __pointer_type_info *target_ptr_type = dynamic_cast<__pointer_type_info*>(type); - if ((0 != ptr_type) && (0 != target_ptr_type) && - (ptr_type->__pointee == target_ptr_type->__pointee) && - ((target_ptr_type->__flags & ~__pbase_type_info::__const_mask) == - ptr_type->__flags)) - { - ex->adjustedPtr = exception_ptr; - return true; + return true; } return false; } diff --git a/src/typeinfo.h b/src/typeinfo.h index f8b6079..6bc4b60 100644 --- a/src/typeinfo.h +++ b/src/typeinfo.h @@ -27,6 +27,7 @@ namespace ABI_NAMESPACE { virtual ~__class_type_info(); virtual void *cast_to(void *obj, const struct __class_type_info *other) const; + virtual bool can_cast_to(const struct __class_type_info *other) const; }; // Single-inheritance class. @@ -35,6 +36,7 @@ namespace ABI_NAMESPACE virtual ~__si_class_type_info(); const __class_type_info *__base_type; virtual void *cast_to(void *obj, const struct __class_type_info *other) const; + virtual bool can_cast_to(const struct __class_type_info *other) const; }; struct __base_class_type_info @@ -76,6 +78,7 @@ namespace ABI_NAMESPACE __diamond_shaped_mask = 0x2 }; virtual void *cast_to(void *obj, const struct __class_type_info *other) const; + virtual bool can_cast_to(const struct __class_type_info *other) const; }; struct __pbase_type_info : public std::type_info |