aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr
diff options
context:
space:
mode:
authorYorick van Pelt <yorick@yorickvanpelt.nl>2023-01-31 17:54:35 +0100
committerYorick van Pelt <yorick@yorickvanpelt.nl>2023-03-01 13:55:37 +0100
commit0fd8f542a8ddb303f589ff6ca3343f36e3a783c0 (patch)
treeb7071fc6fd928dad676604dc22ea188a283cf1ee /src/libexpr
parent92611e6e4c1c5c712ca7d5f9a258640662d006df (diff)
tests/coro-gc: create test for boehm stack patch
Regression test for #7679
Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/tests/coro-gc.cc99
-rw-r--r--src/libexpr/tests/local.mk2
2 files changed, 100 insertions, 1 deletions
diff --git a/src/libexpr/tests/coro-gc.cc b/src/libexpr/tests/coro-gc.cc
new file mode 100644
index 000000000..6023b9b5e
--- /dev/null
+++ b/src/libexpr/tests/coro-gc.cc
@@ -0,0 +1,99 @@
+#include <gtest/gtest.h>
+#if HAVE_BOEHMGC
+#include <gc/gc.h>
+#endif
+
+#include "eval.hh"
+#include "serialise.hh"
+
+
+#define guard_gc(x) GC_register_finalizer((void*)x, finalizer, x##_collected, nullptr, nullptr)
+
+
+namespace nix {
+#if HAVE_BOEHMGC
+ static bool* uncollectable_bool() {
+ bool* res = (bool*)GC_MALLOC_UNCOLLECTABLE(1);
+ *res = false;
+ return res;
+ }
+
+ static void finalizer(void *obj, void *data) {
+ //printf("finalizer: obj %p data %p\n", obj, data);
+ *((bool*)data) = true;
+ }
+
+ // Generate 2 objects, discard one, run gc,
+ // see if one got collected and the other didn't
+ static void testFinalizerCalls() {
+ bool* do_collect_collected = uncollectable_bool();
+ bool* dont_collect_collected = uncollectable_bool();
+ {
+ volatile void* do_collect = GC_MALLOC_ATOMIC(128);
+ guard_gc(do_collect);
+ }
+ volatile void* dont_collect = GC_MALLOC_ATOMIC(128);
+ guard_gc(dont_collect);
+ GC_gcollect();
+ GC_invoke_finalizers();
+
+ ASSERT_TRUE(*do_collect_collected);
+ ASSERT_FALSE(*dont_collect_collected);
+ ASSERT_NE(nullptr, dont_collect);
+ }
+
+ // This test tests that boehm handles coroutine stacks correctly
+ TEST(CoroGC, CoroutineStackNotGCd) {
+ initGC();
+ testFinalizerCalls();
+
+ bool* dont_collect_collected = uncollectable_bool();
+ bool* do_collect_collected = uncollectable_bool();
+
+ volatile void* dont_collect = GC_MALLOC_ATOMIC(128);
+ guard_gc(dont_collect);
+ {
+ volatile void* do_collect = GC_MALLOC_ATOMIC(128);
+ guard_gc(do_collect);
+ }
+
+ auto source = sinkToSource([&](Sink& sink) {
+ testFinalizerCalls();
+
+ bool* dont_collect_inner_collected = uncollectable_bool();
+ bool* do_collect_inner_collected = uncollectable_bool();
+
+ volatile void* dont_collect_inner = GC_MALLOC_ATOMIC(128);
+ guard_gc(dont_collect_inner);
+ {
+ volatile void* do_collect_inner = GC_MALLOC_ATOMIC(128);
+ guard_gc(do_collect_inner);
+ }
+ // pass control to main
+ writeString("foo", sink);
+
+ ASSERT_TRUE(*do_collect_inner_collected);
+ ASSERT_FALSE(*dont_collect_inner_collected);
+ ASSERT_NE(nullptr, dont_collect_inner);
+
+ // pass control to main
+ writeString("bar", sink);
+ });
+
+ // pass control to coroutine
+ std::string foo = readString(*source);
+ ASSERT_EQ(foo, "foo");
+
+ GC_gcollect();
+ GC_invoke_finalizers();
+
+ // pass control to coroutine
+ std::string bar = readString(*source);
+ ASSERT_EQ(bar, "bar");
+
+ ASSERT_FALSE(*dont_collect_collected);
+ ASSERT_TRUE(*do_collect_collected);
+ ASSERT_NE(nullptr, dont_collect);
+ }
+#endif
+}
diff --git a/src/libexpr/tests/local.mk b/src/libexpr/tests/local.mk
index 3e5504f71..c36d21bfe 100644
--- a/src/libexpr/tests/local.mk
+++ b/src/libexpr/tests/local.mk
@@ -16,4 +16,4 @@ libexpr-tests_CXXFLAGS += -I src/libexpr -I src/libutil -I src/libstore -I src/l
libexpr-tests_LIBS = libstore-tests libutils-tests libexpr libutil libstore libfetchers
-libexpr-tests_LDFLAGS := $(GTEST_LIBS) -lgmock
+libexpr-tests_LDFLAGS := $(GTEST_LIBS) -lgmock -lboost_context