[pypy-commit] stmgc default: Add another unit test (run by test/test_demo.py) for major GC tracking

arigo noreply at buildbot.pypy.org
Tue Aug 12 18:43:29 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r1308:38dbf997b57b
Date: 2014-08-12 18:43 +0200
http://bitbucket.org/pypy/stmgc/changeset/38dbf997b57b/

Log:	Add another unit test (run by test/test_demo.py) for major GC
	tracking the parts of the shadowstacks that have been moved away

diff --git a/c7/demo/test_shadowstack.c b/c7/demo/test_shadowstack.c
new file mode 100644
--- /dev/null
+++ b/c7/demo/test_shadowstack.c
@@ -0,0 +1,68 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "stmgc.h"
+
+stm_thread_local_t stm_thread_local;
+
+typedef TLPREFIX struct node_s node_t;
+
+struct node_s {
+    struct object_s hdr;
+    long value;
+};
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    return sizeof(struct node_s);
+}
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2])
+{
+    abort();
+}
+void stmcb_trace_cards(struct object_s *obj, void visit(object_t **),
+                       uintptr_t start, uintptr_t stop)
+{
+    abort();
+}
+void stmcb_commit_soon() {}
+
+
+int main(void)
+{
+    rewind_jmp_buf rjbuf;
+
+    stm_setup();
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+
+    stm_start_transaction(&stm_thread_local);
+    node_t *node = (node_t *)stm_allocate(sizeof(struct node_s));
+    node->value = 129821;
+    STM_PUSH_ROOT(stm_thread_local, node);
+    stm_commit_transaction();
+
+    /* now in a new transaction, pop the node off the shadowstack, but
+       then do a major collection.  It should still be found by the
+       tracing logic. */
+    stm_start_transaction(&stm_thread_local);
+    STM_POP_ROOT(stm_thread_local, node);
+    assert(node->value == 129821);
+    STM_PUSH_ROOT(stm_thread_local, NULL);
+    stm_collect(9);
+
+    node_t *node2 = (node_t *)stm_allocate(sizeof(struct node_s));
+    assert(node2 != node);
+    assert(node->value == 129821);
+
+    STM_PUSH_ROOT(stm_thread_local, node2);
+    stm_collect(0);
+    STM_POP_ROOT(stm_thread_local, node2);
+    assert(node2 != node);
+    assert(node->value == 129821);
+
+    return 0;
+}
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -363,6 +363,16 @@
     mark_trace(obj, segment_base);
 }
 
+static void *mark_visit_objects_from_ss(void *_, const void *slice, size_t size)
+{
+    const struct stm_shadowentry_s *p, *end;
+    p = (const struct stm_shadowentry_s *)slice;
+    end = (const struct stm_shadowentry_s *)(slice + size);
+    for (; p < end; p++)
+        mark_visit_object(p->ss, stm_object_pages);
+    return NULL;
+}
+
 static void mark_visit_from_roots(void)
 {
     if (testing_prebuilt_objs != NULL) {
@@ -386,6 +396,7 @@
                 mark_visit_object(current->ss, segment_base);
         }
         mark_visit_object(tl->thread_local_obj, segment_base);
+        stm_rewind_jmp_enum_shadowstack(tl, mark_visit_objects_from_ss);
 
         tl = tl->next;
     } while (tl != stm_all_thread_locals);
diff --git a/c7/stm/rewind_setjmp.c b/c7/stm/rewind_setjmp.c
--- a/c7/stm/rewind_setjmp.c
+++ b/c7/stm/rewind_setjmp.c
@@ -105,21 +105,28 @@
     do_longjmp(rjthread, &_rewind_jmp_marker);
 }
 
-char *rewind_jmp_restore_shadowstack(rewind_jmp_thread *rjthread)
+
+char *rewind_jmp_enum_shadowstack(rewind_jmp_thread *rjthread,
+                                  void *callback(void *, const void *, size_t))
 {
     struct _rewind_jmp_moved_s *p = rjthread->moved_off;
     char *sstarget = rjthread->moved_off_ssbase;
 
     while (p) {
         char *ssend = sstarget + p->shadowstack_size;
-        memcpy(sstarget, ((char *)p) + RJM_HEADER + p->stack_size,
-               p->shadowstack_size);
+        callback(sstarget, ((char *)p) + RJM_HEADER + p->stack_size,
+                 p->shadowstack_size);
         sstarget = ssend;
         p = p->next;
     }
     return sstarget;
 }
 
+char *rewind_jmp_restore_shadowstack(rewind_jmp_thread *rjthread)
+{
+    return rewind_jmp_enum_shadowstack(rjthread, memcpy);
+}
+
 __attribute__((noinline))
 void _rewind_jmp_copy_stack_slice(rewind_jmp_thread *rjthread)
 {
diff --git a/c7/stm/rewind_setjmp.h b/c7/stm/rewind_setjmp.h
--- a/c7/stm/rewind_setjmp.h
+++ b/c7/stm/rewind_setjmp.h
@@ -1,6 +1,8 @@
 #ifndef _REWIND_SETJMP_H_
 #define _REWIND_SETJMP_H_
 
+#include <stddef.h>
+
 /************************************************************
 
            :                   :       ^^^^^
@@ -75,6 +77,8 @@
 long rewind_jmp_setjmp(rewind_jmp_thread *rjthread, void *ss);
 void rewind_jmp_longjmp(rewind_jmp_thread *rjthread) __attribute__((noreturn));
 char *rewind_jmp_restore_shadowstack(rewind_jmp_thread *rjthread);
+char *rewind_jmp_enum_shadowstack(rewind_jmp_thread *rjthread,
+                                  void *callback(void *, const void *, size_t));
 
 #define rewind_jmp_forget(rjthread)  do {                               \
     if ((rjthread)->moved_off) _rewind_jmp_free_stack_slices(rjthread); \
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -343,6 +343,8 @@
     (tl)->shadowstack = (struct stm_shadowentry_s *)     \
         rewind_jmp_restore_shadowstack(&(tl)->rjthread); \
 } while (0)
+#define stm_rewind_jmp_enum_shadowstack(tl, callback)    \
+    rewind_jmp_enum_shadowstack(&(tl)->rjthread, callback)
 
 /* Starting and ending transactions.  stm_read(), stm_write() and
    stm_allocate() should only be called from within a transaction.
diff --git a/c7/test/test_demo.py b/c7/test/test_demo.py
--- a/c7/test/test_demo.py
+++ b/c7/test/test_demo.py
@@ -13,6 +13,8 @@
         self._do("make -C ../demo %s" % target)
         self._do("../demo/%s 2> /dev/null" % target)
 
+    def test_shadowstack(self):   self.make_and_run("debug-test_shadowstack")
+
     def test_demo2_debug(self):   self.make_and_run("debug-demo2")
     def test_demo2_build(self):   self.make_and_run("build-demo2")
     def test_demo2_release(self): self.make_and_run("release-demo2")


More information about the pypy-commit mailing list