Skip to content

Commit 2a305a9

Browse files
committed
MinGW: Use _Unwind_RaiseException to throw exceptions (#278)
The current implementation uses Vectored Exception Handlers. This implementation is too greedy, and invokes _objc_unexpected_exception for (certain) exceptions which would be handled by the application itself.
1 parent 03b9f9a commit 2a305a9

5 files changed

+363
-302
lines changed

CMakeLists.txt

+2-4
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,7 @@ set(libobjc_CXX_SRCS
124124
# Windows does not use DWARF EH, except when using the GNU ABI (MinGW)
125125
if (WIN32 AND NOT MINGW)
126126
list(APPEND libobjc_CXX_SRCS eh_win32_msvc.cc)
127-
elseif (MINGW)
128-
list(APPEND libobjc_CXX_SRCS eh_win32_mingw.m)
129-
else ()
127+
elseif (NOT MINGW)
130128
list(APPEND libobjc_C_SRCS eh_personality.c)
131129
endif ()
132130

@@ -230,7 +228,7 @@ if (WIN32 AND NOT MINGW)
230228
message(STATUS "Using MSVC-compatible exception model")
231229
elseif (MINGW)
232230
message(STATUS "Using MinGW-compatible exception model")
233-
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc)
231+
list(APPEND libobjc_CXX_SRCS objcxx_eh.cc objcxx_eh_mingw.cc)
234232
else ()
235233
separate_arguments(EH_PERSONALITY_FLAGS NATIVE_COMMAND ${CMAKE_CXX_FLAGS})
236234
if (CMAKE_CXX_COMPILER_TARGET)

eh_win32_mingw.m

-59
This file was deleted.

objcxx_eh.cc

+22-239
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
1-
typedef struct objc_object* id;
21
#include <atomic>
32
#include <stdlib.h>
43
#include <stdio.h>
54
#include "dwarf_eh.h"
5+
#include "objcxx_eh_private.h"
66
#include "objcxx_eh.h"
7-
#include "visibility.h"
8-
#include "objc/runtime.h"
97
#include "objc/objc-arc.h"
108

11-
#ifndef DEBUG_EXCEPTIONS
12-
#define DEBUG_LOG(...)
13-
#else
14-
#define DEBUG_LOG(str, ...) fprintf(stderr, str, ## __VA_ARGS__)
15-
#endif
16-
179
/**
1810
* Helper function that has a custom personality function.
1911
* This calls `cxx_throw` and has a destructor that must be run. We intercept
@@ -23,92 +15,8 @@ int eh_trampoline();
2315

2416
uint64_t cxx_exception_class;
2517

26-
/**
27-
* Our own definitions of C++ ABI functions and types. These are provided
28-
* because this file must not include cxxabi.h. We need to handle subtly
29-
* different variations of the ABI and including one specific implementation
30-
* would make that very difficult.
31-
*/
32-
namespace __cxxabiv1
33-
{
34-
/**
35-
* Type info for classes. Forward declared because the GNU ABI provides a
36-
* method on all type_info objects that the dynamic the dynamic cast header
37-
* needs.
38-
*/
39-
struct __class_type_info;
40-
/**
41-
* The C++ in-flight exception object. We will derive the offset of fields
42-
* in this, so we do not ever actually see a concrete definition of it.
43-
*/
44-
struct __cxa_exception;
45-
/**
46-
* The public ABI structure for current exception state.
47-
*/
48-
struct __cxa_eh_globals
49-
{
50-
/**
51-
* The current exception that has been caught.
52-
*/
53-
__cxa_exception *caughtExceptions;
54-
/**
55-
* The number of uncaught exceptions still in flight.
56-
*/
57-
unsigned int uncaughtExceptions;
58-
};
59-
/**
60-
* Retrieve the above structure.
61-
*/
62-
extern "C" __cxa_eh_globals *__cxa_get_globals();
63-
}
64-
65-
namespace std
66-
{
67-
struct type_info;
68-
}
69-
7018
using namespace __cxxabiv1;
7119

72-
// Define some C++ ABI types here, rather than including them. This prevents
73-
// conflicts with the libstdc++ headers, which expose only a subset of the
74-
// type_info class (the part required for standards compliance, not the
75-
// implementation details).
76-
77-
typedef void (*unexpected_handler)();
78-
typedef void (*terminate_handler)();
79-
80-
namespace std
81-
{
82-
/**
83-
* std::type_info, containing the minimum requirements for the ABI.
84-
* Public headers on some implementations also expose some implementation
85-
* details. The layout of our subclasses must respect the layout of the
86-
* C++ runtime library, but also needs to be portable across multiple
87-
* implementations and so should not depend on internal symbols from those
88-
* libraries.
89-
*/
90-
class type_info
91-
{
92-
public:
93-
virtual ~type_info();
94-
bool operator==(const type_info &) const;
95-
bool operator!=(const type_info &) const;
96-
bool before(const type_info &) const;
97-
type_info();
98-
private:
99-
type_info(const type_info& rhs);
100-
type_info& operator= (const type_info& rhs);
101-
const char *__type_name;
102-
protected:
103-
type_info(const char *name): __type_name(name) { }
104-
public:
105-
const char* name() const { return __type_name; }
106-
};
107-
}
108-
109-
extern "C" void __cxa_throw(void*, std::type_info*, void(*)(void*));
110-
extern "C" void __cxa_rethrow();
111-
11220
namespace
11321
{
11422
/**
@@ -140,49 +48,6 @@ std::atomic<ptrdiff_t> type_info_offset;
14048
*/
14149
std::atomic<size_t> exception_struct_size;
14250

143-
/**
144-
* Helper function to find a particular value scanning backwards in a
145-
* structure.
146-
*/
147-
template<typename T>
148-
ptrdiff_t find_backwards(void *addr, T val)
149-
{
150-
T *ptr = reinterpret_cast<T*>(addr);
151-
for (ptrdiff_t disp = -1 ; (disp * sizeof(T) > -128) ; disp--)
152-
{
153-
if (ptr[disp] == val)
154-
{
155-
return disp * sizeof(T);
156-
}
157-
}
158-
fprintf(stderr, "Unable to find field in C++ exception structure\n");
159-
abort();
160-
}
161-
162-
/**
163-
* Helper function to find a particular value scanning forwards in a
164-
* structure.
165-
*/
166-
template<typename T>
167-
ptrdiff_t find_forwards(void *addr, T val)
168-
{
169-
T *ptr = reinterpret_cast<T*>(addr);
170-
for (ptrdiff_t disp = 0 ; (disp * sizeof(T) < 256) ; disp++)
171-
{
172-
if (ptr[disp] == val)
173-
{
174-
return disp * sizeof(T);
175-
}
176-
}
177-
fprintf(stderr, "Unable to find field in C++ exception structure\n");
178-
abort();
179-
}
180-
181-
template<typename T>
182-
T *pointer_add(void *ptr, ptrdiff_t offset)
183-
{
184-
return reinterpret_cast<T*>(reinterpret_cast<char*>(ptr) + offset);
185-
}
18651

18752
/**
18853
* Exception cleanup function for C++ exceptions that wrap Objective-C
@@ -225,76 +90,33 @@ namespace gnustep
22590
{
22691
namespace libobjc
22792
{
228-
/**
229-
* Superclass for the type info for Objective-C exceptions.
230-
*/
231-
struct OBJC_PUBLIC __objc_type_info : std::type_info
232-
{
233-
/**
234-
* Constructor that sets the name.
235-
*/
236-
__objc_type_info(const char *name) : type_info(name) {}
237-
/**
238-
* Helper function used by libsupc++ and libcxxrt to determine if
239-
* this is a pointer type. If so, catches automatically
240-
* dereference the pointer to the thrown pointer in
241-
* `__cxa_begin_catch`.
242-
*/
243-
virtual bool __is_pointer_p() const { return true; }
244-
/**
245-
* Helper function used by libsupc++ and libcxxrt to determine if
246-
* this is a function pointer type. Irrelevant for our purposes.
247-
*/
248-
virtual bool __is_function_p() const { return false; }
249-
/**
250-
* Catch handler. This is used in the C++ personality function.
251-
* `thrown_type` is the type info of the thrown object, `this` is
252-
* the type info at the catch site. `thrown_object` is a pointer
253-
* to a pointer to the thrown object and may be adjusted by this
254-
* function.
255-
*/
256-
virtual bool __do_catch(const type_info *thrown_type,
93+
__objc_type_info::__objc_type_info(const char *name) : type_info(name) {}
94+
95+
bool __objc_type_info::__is_pointer_p() const { return true; }
96+
97+
bool __objc_type_info::__is_function_p() const { return false; }
98+
99+
bool __objc_type_info::__do_catch(const type_info *thrown_type,
257100
void **thrown_object,
258101
unsigned) const
259-
{
260-
assert(0);
261-
return false;
262-
};
263-
/**
264-
* Function used for `dynamic_cast` between two C++ class types in
265-
* libsupc++ and libcxxrt.
266-
*
267-
* This should never be called on Objective-C types.
268-
*/
269-
virtual bool __do_upcast(
102+
{
103+
assert(0);
104+
return false;
105+
};
106+
107+
bool __objc_type_info::__do_upcast(
270108
const __class_type_info *target,
271109
void **thrown_object) const
272-
{
273-
return false;
274-
};
110+
{
111+
return false;
275112
};
113+
114+
276115
/**
277-
* Singleton type info for the `id` type.
116+
* The `id` type is mangled to `@id`, which is not a valid mangling
117+
* of anything else.
278118
*/
279-
struct OBJC_PUBLIC __objc_id_type_info : __objc_type_info
280-
{
281-
/**
282-
* The `id` type is mangled to `@id`, which is not a valid mangling
283-
* of anything else.
284-
*/
285-
__objc_id_type_info() : __objc_type_info("@id") {};
286-
virtual ~__objc_id_type_info();
287-
virtual bool __do_catch(const type_info *thrownType,
288-
void **obj,
289-
unsigned outer) const;
290-
};
291-
struct OBJC_PUBLIC __objc_class_type_info : __objc_type_info
292-
{
293-
virtual ~__objc_class_type_info();
294-
virtual bool __do_catch(const type_info *thrownType,
295-
void **obj,
296-
unsigned outer) const;
297-
};
119+
__objc_id_type_info::__objc_id_type_info() : __objc_type_info("@id") {};
298120
}
299121

300122
static inline id dereference_thrown_object_pointer(void** obj) {
@@ -430,29 +252,7 @@ void* objc_object_for_cxx_exception(void *thrown_exception, int *isValid)
430252
} // extern "C"
431253

432254

433-
/**
434-
* C++ structure that is thrown through a frame with the `test_eh_personality`
435-
* personality function. This contains a well-known value that we can search
436-
* for after the unwind header.
437-
*/
438-
struct
439-
PRIVATE
440-
MagicValueHolder
441-
{
442-
/**
443-
* The constant that we will search for to identify this object.
444-
*/
445-
static constexpr uint32_t magic = 0x01020304;
446-
/**
447-
* The single field in this structure.
448-
*/
449-
uint32_t magic_value;
450-
/**
451-
* Constructor. Initialises the field with the magic constant.
452-
*/
453-
MagicValueHolder() { magic_value = magic; }
454-
};
455-
255+
MagicValueHolder::MagicValueHolder() { magic_value = magic; }
456256

457257
/**
458258
* Function that simply throws an instance of `MagicValueHolder`.
@@ -508,21 +308,4 @@ extern "C" void test_cxx_eh_implementation()
508308
}
509309
assert(caught);
510310
}
511-
#else
512-
static void eh_cleanup(void *exception)
513-
{
514-
DEBUG_LOG("eh_cleanup: Releasing 0x%x\n", *(id*)exception);
515-
objc_release(*(id*)exception);
516-
}
517-
518-
extern "C"
519-
OBJC_PUBLIC
520-
void objc_exception_throw(id object)
521-
{
522-
id *exc = (id *)__cxa_allocate_exception(sizeof(id));
523-
*exc = object;
524-
objc_retain(object);
525-
DEBUG_LOG("objc_exception_throw: Throwing 0x%x\n", *exc);
526-
__cxa_throw(exc, & __objc_id_type_info, eh_cleanup);
527-
}
528311
#endif

0 commit comments

Comments
 (0)