From 93643adaa38418bf3656cd92a71768fbab59b984 Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Fri, 13 Jul 2012 00:12:45 +0400
Subject: [PATCH] Fix a regression with nested @finally introduced with a new
 runtime.

Fix a regression with nested @finally not being
called, introduced in 1.4.7 release.

Big thanks to David Chisnall for a swift fix in GNUStep Objective C
runtime.

Add unit tests for two Objective C runtime properties:
nested finally handling and ability to catch C++ exceptions.
---
 .gitignore                           |  2 ++
 test/unit/CMakeLists.txt             |  7 +++++
 test/unit/objc_catchcxx.m            | 15 +++++++++
 test/unit/objc_catchcxx.result       |  1 +
 test/unit/objc_catchcxx.test         |  1 +
 test/unit/objc_finally.m             | 46 ++++++++++++++++++++++++++++
 test/unit/objc_finally.result        |  5 +++
 test/unit/objc_finally.test          |  1 +
 third_party/libobjc/eh_personality.c |  3 +-
 9 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 test/unit/objc_catchcxx.m
 create mode 100644 test/unit/objc_catchcxx.result
 create mode 100644 test/unit/objc_catchcxx.test
 create mode 100644 test/unit/objc_finally.m
 create mode 100644 test/unit/objc_finally.result
 create mode 100644 test/unit/objc_finally.test

diff --git a/.gitignore b/.gitignore
index b93343473a..6e433cc0ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,8 @@ test/box/protocol
 test/box/connector
 test/unit/queue
 test/unit/mhash
+test/unit/objc_finally
+test/unit/objc_catchcxx
 Makefile
 CMakeFiles
 CMakeCache.txt
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 6154fc20a4..7d3a49f43b 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -1,3 +1,10 @@
 add_executable(queue queue.c)
 add_executable(mhash mhash.c)
+add_executable(objc_finally objc_finally.m)
+add_executable(objc_catchcxx objc_catchcxx.m)
 set_target_properties(mhash PROPERTIES COMPILE_FLAGS "-std=c99")
+target_link_libraries(objc_finally ${LIBOBJC_LIB})
+target_link_libraries(objc_catchcxx ${LIBOBJC_LIB} ${LUAJIT_LIB})
+if (TARGET_OS_LINUX OR TARGET_OS_DEBIAN_FREEBSD)
+    target_link_libraries(objc_catchcxx dl)
+endif()
diff --git a/test/unit/objc_catchcxx.m b/test/unit/objc_catchcxx.m
new file mode 100644
index 0000000000..b90e53092b
--- /dev/null
+++ b/test/unit/objc_catchcxx.m
@@ -0,0 +1,15 @@
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+
+int main()
+{
+	lua_State *L = luaL_newstate();
+	luaL_openlibs(L);
+	@try {
+		luaL_error(L, "test");
+	} @catch (...) {
+		printf("exception handled\n");
+	}
+	lua_close(L);
+}
diff --git a/test/unit/objc_catchcxx.result b/test/unit/objc_catchcxx.result
new file mode 100644
index 0000000000..761f3a2040
--- /dev/null
+++ b/test/unit/objc_catchcxx.result
@@ -0,0 +1 @@
+exception handled
diff --git a/test/unit/objc_catchcxx.test b/test/unit/objc_catchcxx.test
new file mode 100644
index 0000000000..13f381fcb7
--- /dev/null
+++ b/test/unit/objc_catchcxx.test
@@ -0,0 +1 @@
+run_test("objc_catchcxx")
diff --git a/test/unit/objc_finally.m b/test/unit/objc_finally.m
new file mode 100644
index 0000000000..18cf5c62b5
--- /dev/null
+++ b/test/unit/objc_finally.m
@@ -0,0 +1,46 @@
+#include <stdio.h>
+#include <objc/Object.h>
+#include <objc/runtime.h>
+
+@interface Exception: Object {
+}
++ (id) new;
+@end
+
+@implementation Exception
++ (id) new
+{
+	return class_createInstance(self, 0);
+}
+@end
+
+void
+throw_exception(void)
+{
+	printf("throw\n");
+	@throw [Exception new];
+}
+
+void
+test(void)
+{
+	@try {
+		throw_exception();
+	} @finally {
+		printf("internal finally\n");
+	}
+}
+
+int
+main(int ac, char **av)
+{
+	printf("start\n");
+	@try {
+		test();
+	} @catch(id e) {
+		printf("catch\n");
+	} @finally {
+		printf("external finally\n");
+	}
+	return 0;
+}
diff --git a/test/unit/objc_finally.result b/test/unit/objc_finally.result
new file mode 100644
index 0000000000..1d09f8b413
--- /dev/null
+++ b/test/unit/objc_finally.result
@@ -0,0 +1,5 @@
+start
+throw
+internal finally
+catch
+external finally
diff --git a/test/unit/objc_finally.test b/test/unit/objc_finally.test
new file mode 100644
index 0000000000..65770394cc
--- /dev/null
+++ b/test/unit/objc_finally.test
@@ -0,0 +1 @@
+run_test("objc_finally")
diff --git a/third_party/libobjc/eh_personality.c b/third_party/libobjc/eh_personality.c
index e3e4ead29c..77feb2a271 100644
--- a/third_party/libobjc/eh_personality.c
+++ b/third_party/libobjc/eh_personality.c
@@ -204,7 +204,7 @@ static handler_type check_action_record(struct _Unwind_Context *context,
                                         Class thrown_class,
                                         unsigned long *selector)
 {
-	//if (!action_record) { return handler_cleanup; }
+	if (!action_record) { return handler_cleanup; }
 	while (action_record)
 	{
 		int filter = read_sleb128(&action_record);
@@ -343,6 +343,7 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 		action = dwarf_eh_find_callsite(context, &lsda);
 		handler_type handler = check_action_record(context, foreignException,
 				&lsda, action.action_record, thrown_class, &selector);
+		fprintf(stderr, "handler: %d\n", handler);
 		// If there's no action record, we've only found a cleanup, so keep
 		// searching for something real
 		if (handler == handler_class ||
-- 
GitLab