assert: add `ASSERT_WITH_CLEANUP` Now that we safely assert and return, we may need to be in a place where we need to unlock mutexes or cleanup resources. Provide `ASSERT_WITH_CLEANUP` that permits for this behavior by taking a block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
diff --git a/src/util/assert_safe.h b/src/util/assert_safe.h
index 8c26110..cc0bac5 100644
--- a/src/util/assert_safe.h
+++ b/src/util/assert_safe.h
@@ -24,6 +24,8 @@
# define GIT_ASSERT_WITH_RETVAL(expr, fail) assert(expr)
# define GIT_ASSERT_ARG_WITH_RETVAL(expr, fail) assert(expr)
+
+# define GIT_ASSERT_WITH_CLEANUP(expr, cleanup) assert(expr)
#else
/** Internal consistency check to stop the function. */
@@ -53,6 +55,20 @@
} \
} while(0)
+/**
+ * Go to to the given label on assertion failures; useful when you have
+ * taken a lock or otherwise need to release a resource.
+ */
+# define GIT_ASSERT_WITH_CLEANUP(expr, cleanup) \
+ GIT_ASSERT__WITH_CLEANUP(expr, GIT_ERROR_INTERNAL, "unrecoverable internal error", cleanup)
+
+# define GIT_ASSERT__WITH_CLEANUP(expr, code, msg, cleanup) do { \
+ if (!(expr)) { \
+ git_error_set(code, "%s: '%s'", msg, #expr); \
+ cleanup; \
+ } \
+ } while(0)
+
#endif /* GIT_ASSERT_HARD */
#endif
diff --git a/tests/util/assert.c b/tests/util/assert.c
index 26c4297..3babc47 100644
--- a/tests/util/assert.c
+++ b/tests/util/assert.c
@@ -36,6 +36,21 @@ static const char *bad_returns_string(void)
return hello_world;
}
+static int has_cleanup(void)
+{
+ int error = 42;
+
+ GIT_ASSERT_WITH_CLEANUP(1 + 1 == 3, {
+ error = 99;
+ goto foobar;
+ });
+
+ return 0;
+
+foobar:
+ return error;
+}
+
void test_assert__argument(void)
{
cl_git_fail(dummy_fn(NULL));
@@ -92,3 +107,11 @@ void test_assert__internal(void)
cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass);
cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message);
}
+
+void test_assert__with_cleanup(void)
+{
+ cl_git_fail_with(99, has_cleanup());
+ cl_assert(git_error_last());
+ cl_assert_equal_i(GIT_ERROR_INTERNAL, git_error_last()->klass);
+ cl_assert_equal_s("unrecoverable internal error: '1 + 1 == 3'", git_error_last()->message);
+}