Permalink
Browse files

Rework exception matching.

- Remove typeinfo since thing break if the compiler decides to use the
  system one and merge its contents into typeinfo.h
- Make each type_info object have a vtable with the same layout as the
  public vtable in libstdc++'s <typeinfo>.  This fixes code (e.g.
  libobjc2's Objective-C++ exception handling) which rely on being able
  to add new types.
- Add some extra tests

I suspect exceptions catching pointer-to-member types will not work
correctly, but I've never seen anyone do this and don't have any tests
for it.
  • Loading branch information...
1 parent a35d8de commit cddcf8734ed06ada9384a461bc21d58b44f6eba1 David Chisnall committed Mar 20, 2012
Showing with 218 additions and 108 deletions.
  1. +79 −28 src/dynamic_cast.cc
  2. +6 −41 src/exception.cc
  3. +0 −26 src/typeinfo
  4. +97 −10 src/typeinfo.h
  5. +33 −3 test/test_exception.cc
  6. +3 −0 test/test_typeinfo.cc
View
@@ -46,9 +46,65 @@ 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
+bool std::type_info::__do_catch(std::type_info const *ex_type,
+ void **exception_object,
+ unsigned int outer) const
{
- return this == other;
+ const type_info *type = this;
+
+ if (type == ex_type)
+ {
+ return true;
+ }
+ if (const __class_type_info *cti = dynamic_cast<const __class_type_info *>(type))
+ {
+ return ex_type->__do_upcast(cti, exception_object);
+ }
+ return false;
+}
+
+bool __pbase_type_info::__do_catch(std::type_info const *ex_type,
+ void **exception_object,
+ unsigned int outer) const
+{
+ if (ex_type == this)
+ {
+ return true;
+ }
+ if (!ex_type->__is_pointer_p())
+ {
+ // Can't catch a non-pointer type in a pointer catch
+ return false;
+ }
+
+ if (!(outer & 1))
+ {
+ // If the low bit is cleared on this means that we've gone
+ // through a pointer that is not const qualified.
+ return false;
+ }
+ // Clear the low bit on outer if we're not const qualified.
+ if (!(__flags & __const_mask))
+ {
+ outer &= ~1;
+ }
+
+ const __pbase_type_info *ptr_type =
+ static_cast<const __pbase_type_info*>(ex_type);
+
+ if (ptr_type->__flags & ~__flags)
+ {
+ // Handler pointer is less qualified
+ return false;
+ }
+
+ // Special case for void* handler.
+ if(*__pointee == typeid(void))
+ {
+ return true;
+ }
+
+ return __pointee->__do_catch(ptr_type->__pointee, exception_object, outer);
}
void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
@@ -60,12 +116,6 @@ 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)
@@ -74,31 +124,32 @@ 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
+bool __si_class_type_info::__do_upcast(const __class_type_info *target,
+ void **thrown_object) const
{
- if (this == other)
+ if (this == target)
{
return true;
}
- for (unsigned int i=0 ; i<__base_count ; i++)
- {
- const __base_class_type_info *info = &__base_info[i];
- if(info->isPublic() && info->__base_type->can_cast_to(other))
- {
- return true;
- }
- }
- return false;
+ return __base_type->__do_upcast(target, thrown_object);
}
void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
{
- if (this == other)
+ if (__do_upcast(other, &obj))
{
return obj;
}
+ return 0;
+}
+
+bool __vmi_class_type_info::__do_upcast(const __class_type_info *target,
+ void **thrown_object) const
+{
+ if (this == target)
+ {
+ return true;
+ }
for (unsigned int i=0 ; i<__base_count ; i++)
{
const __base_class_type_info *info = &__base_info[i];
@@ -111,6 +162,7 @@ void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *
// virtual table of the virtual base offset for the virtual base
// referenced (negative).'
+ void *obj = *thrown_object;
if (info->isVirtual())
{
// Object's vtable
@@ -121,18 +173,17 @@ void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *
}
void *cast = ADD_TO_PTR(obj, offset);
- if (info->__base_type == other)
+ if (info->__base_type == target ||
+ (info->__base_type->__do_upcast(target, &cast)))
{
- return cast;
- }
- if ((cast = info->__base_type->cast_to(cast, other)))
- {
- return cast;
+ *thrown_object = cast;
+ return true;
}
}
return 0;
}
+
/**
* ABI function used to implement the dynamic_cast<> operator. Some cases of
* this operator are implemented entirely in the compiler (e.g. to void*).
View
@@ -847,26 +847,18 @@ static bool check_type_signature(__cxa_exception *ex,
const std::type_info *type,
void *&adjustedPtr)
{
- // TODO: For compatibility with the GNU implementation, we should move this
- // out into a __do_catch() virtual function in std::type_info
void *exception_ptr = (void*)(ex+1);
- const std::type_info *ex_type = 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)
+ bool is_ptr = ex_type->__is_pointer_p();
+ if (is_ptr)
{
exception_ptr = *(void**)exception_ptr;
}
// Always match a catchall, even with a foreign exception
//
// Note: A 0 here is a catchall, not a cleanup, so we return true to
// indicate that we found a catch.
- //
- // TODO: Provide a class for matching against foreign exceptions. This is
- // already done in libobjc2, allowing C++ exceptions to be boxed as
- // Objective-C objects. We should do something similar, allowing foreign
- // exceptions to be wrapped in a C++ exception and delivered.
if (0 == type)
{
if (ex)
@@ -878,47 +870,20 @@ static bool check_type_signature(__cxa_exception *ex,
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))
- {
- 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_type)
{
adjustedPtr = exception_ptr;
return true;
}
- 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))
+ if (type->__do_catch(ex_type, &exception_ptr, 1))
{
- adjustedPtr = cls_type->cast_to(exception_ptr, target_cls_type);
+ adjustedPtr = exception_ptr;
return true;
}
+
return false;
}
/**
View
@@ -1,26 +0,0 @@
-namespace std
-{
- /**
- * Standard type info class. The layout of this class is specified by the
- * ABI.
- */
- class type_info
- {
- public:
- /**
- * Virtual destructor. This class must have one virtual function to
- * ensure that it has a vtable.
- */
- virtual ~type_info();
- bool operator==(const type_info &) const;
- bool operator!=(const type_info &) const;
- bool before(const type_info &) const;
- const char* name() const;
- type_info();
- private:
- type_info(const type_info& rhs);
- type_info& operator= (const type_info& rhs);
- const char *__type_name;
- };
-}
-
Oops, something went wrong.

0 comments on commit cddcf87

Please sign in to comment.