summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoranonymous <local@localhost>2011-01-04 07:38:25 +0600
committeranonymous <local@localhost>2011-01-04 07:38:25 +0600
commit51b577f026c241da85acdb469a3d7349a785f636 (patch)
treec52ecd31021d053171dc1a2966301888d4e2fa9f
parent36d91e1f88660a8b11147a15a05c60b8f0f0d9f0 (diff)
downloadlibcxxrt-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.cc31
-rw-r--r--src/exception.cc53
-rw-r--r--src/typeinfo.h3
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