|
From: Kazuhiro Y. <nul...@cl...> - 2014-01-30 13:28:57
|
Kazuhiro Yamato 2014-01-30 10:15:24 +0900 (Thu, 30 Jan 2014) New Revision: 4c7e91f3abd0d5fa1314f0dd712f4287502e6519 https://github.com/clear-code/cutter/commit/4c7e91f3abd0d5fa1314f0dd712f4287502e6519 Merged 2ea8341: Merge pull request #11 from kz0817/unwind-jump-buffers-on-exception Message: Unwind jump buffers to avoid an invalid memory access on an unhandled exception If jump buffers are stacked, the previous catch handler calls longjmp() with the top of the jump buffers. However, it is no longer valid, because it was on a stack unwound by the exception. This situation typically happens when an exception is thrown in cutter's assertion function. This patch forces to use the base jump buffer when an unhandled exception is caught. Modified files: cppcutter/cppcut-test-methods.cpp cutter/cut-test.c cutter/cut-test.h test/cppcutter/test-cppcut-test.cpp Modified: cppcutter/cppcut-test-methods.cpp (+10 -0) =================================================================== --- cppcutter/cppcut-test-methods.cpp 2014-01-27 21:39:02 +0900 (2f16b9f) +++ cppcutter/cppcut-test-methods.cpp 2014-01-30 10:15:24 +0900 (992e1f5) @@ -46,6 +46,15 @@ struct CppCutTestTerminated { static const gchar *invoking_data_key = "cppcut-test-invoking"; +static void +force_unwind_jump_buffers (CutTest *test) +{ + CutTestContext *test_context = cut_get_current_test_context(); + while (cut_test_context_in_user_message_jump(test_context)) + cut_test_context_finish_user_message_jump(test_context); + cut_test_context_set_jump_buffer(test_context, cut_test_get_jump_buffer(test)); +} + void cut::test::long_jump (CutTestClass *cut_test_class, CutTest *test, @@ -100,6 +109,7 @@ cut::test::invoke (CutTestClass *cut_test_class, } if (terminate_message) { + force_unwind_jump_buffers(test); cut_test_terminate(ERROR, terminate_message); } } Modified: cutter/cut-test.c (+7 -0) =================================================================== --- cutter/cut-test.c 2014-01-27 21:39:02 +0900 (d9ef5d9) +++ cutter/cut-test.c 2014-01-30 10:15:24 +0900 (4621bc4) @@ -551,6 +551,13 @@ cut_test_is_own_jump_buffer (CutTest *test, jmp_buf *jump_buffer) return priv->jump_buffer == jump_buffer; } +jmp_buf * +cut_test_get_jump_buffer (CutTest *test) +{ + CutTestPrivate *priv = CUT_TEST_GET_PRIVATE(test); + return priv->jump_buffer; +} + const gchar * cut_test_get_name (CutTest *test) { Modified: cutter/cut-test.h (+1 -0) =================================================================== --- cutter/cut-test.h 2014-01-27 21:39:02 +0900 (32f311a) +++ cutter/cut-test.h 2014-01-30 10:15:24 +0900 (b1b6dc2) @@ -118,6 +118,7 @@ void cut_test_long_jump (CutTest *test, gint value); gboolean cut_test_is_own_jump_buffer (CutTest *test, jmp_buf *jump_buffer); +jmp_buf *cut_test_get_jump_buffer (CutTest *test); const gchar *cut_test_get_name (CutTest *test); void cut_test_set_name (CutTest *test, Modified: test/cppcutter/test-cppcut-test.cpp (+43 -0) =================================================================== --- test/cppcutter/test-cppcut-test.cpp 2014-01-27 21:39:02 +0900 (3862137) +++ test/cppcutter/test-cppcut-test.cpp 2014-01-30 10:15:24 +0900 (2047b1d) @@ -27,6 +27,14 @@ #include "../lib/cuttest-assertions.h" +#define MARK_FAIL(assertion) do \ +{ \ + fail_line = __LINE__; \ + assertion; \ +} while (0) + +#define FAIL_LOCATION (cut_take_printf("%s:%d", __FILE__, fail_line)) + namespace cppcut_test { CppCutTest *test; @@ -34,6 +42,7 @@ namespace cppcut_test CutTestContext *test_context; CutTestResult *test_result; gint n_destructor_calls; + gint fail_line; static gboolean run (void) @@ -61,6 +70,7 @@ namespace cppcut_test test_result = NULL; n_destructor_calls = 0; + fail_line = 0; } void @@ -149,6 +159,39 @@ namespace cppcut_test NULL); } + static void + stub_exception_on_stacked_jump_buffer (void) + { + struct { + bool operator ()(void) { + stub_not_std_exception(); + throw "exception on stacked jump buffer"; + } + } stub_throw; + MARK_FAIL(cppcut_assert_equal(true, stub_throw())); + } + + void + test_exception_on_stacked_jump_buffer (void) + { + test = cppcut_test_new("exception on stacked jump buffer test", + stub_exception_on_stacked_jump_buffer); + cut_assert_not_null(test); + + cut_assert_false(run()); + cut_assert_test_result_summary(run_context, 1, 0, 0, 0, 1, 0, 0, 0); + const gchar *system_message = + "Unhandled C++ non-standard exception is thrown"; + cut_assert_test_result(run_context, 0, CUT_TEST_RESULT_ERROR, + "exception on stacked jump buffer test", + NULL, + system_message, + NULL, NULL, + FAIL_LOCATION, + "void cppcut_test::stub_exception_on_stacked_jump_buffer()", + NULL); + } + class DestructorCallCounter { public: |