[pypy-commit] stmgc default: re-add shadowstack
Raemi
noreply at buildbot.pypy.org
Wed Sep 3 15:44:40 CEST 2014
Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch:
Changeset: r1341:4a48705ca8ce
Date: 2014-09-03 15:45 +0200
http://bitbucket.org/pypy/stmgc/changeset/4a48705ca8ce/
Log: re-add shadowstack
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -130,6 +130,7 @@
#ifndef NDEBUG
STM_PSEGMENT->running_pthread = pthread_self();
#endif
+ STM_PSEGMENT->shadowstack_at_start_of_transaction = tl->shadowstack;
dprintf(("start_transaction\n"));
@@ -260,11 +261,30 @@
#pragma push_macro("STM_SEGMENT")
#undef STM_PSEGMENT
#undef STM_SEGMENT
- /* struct stm_priv_segment_info_s *pseg = get_priv_segment(segment_num); */
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(segment_num);
- /* throw_away_nursery(pseg); */
+ throw_away_nursery(pseg);
- /* reset_modified_from_other_segments(segment_num); */
+ /* XXX: reset_modified_from_other_segments(segment_num); */
+
+ stm_thread_local_t *tl = pseg->pub.running_thread;
+#ifdef STM_NO_AUTOMATIC_SETJMP
+ /* In tests, we don't save and restore the shadowstack correctly.
+ Be sure to not change items below shadowstack_at_start_of_transaction.
+ There is no such restrictions in non-Python-based tests. */
+ assert(tl->shadowstack >= pseg->shadowstack_at_start_of_transaction);
+ tl->shadowstack = pseg->shadowstack_at_start_of_transaction;
+#else
+ /* NB. careful, this function might be called more than once to
+ abort a given segment. Make sure that
+ stm_rewind_jmp_restore_shadowstack() is idempotent. */
+ /* we need to do this here and not directly in rewind_longjmp() because
+ that is called when we already released everything (safe point)
+ and a concurrent major GC could mess things up. */
+ if (tl->shadowstack != NULL)
+ stm_rewind_jmp_restore_shadowstack(tl);
+ assert(tl->shadowstack == pseg->shadowstack_at_start_of_transaction);
+#endif
#pragma pop_macro("STM_SEGMENT")
#pragma pop_macro("STM_PSEGMENT")
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -54,6 +54,8 @@
struct stm_commit_log_entry_s *last_commit_log_entry;
+ struct stm_shadowentry_s *shadowstack_at_start_of_transaction;
+
/* For debugging */
#ifndef NDEBUG
pthread_t running_pthread;
diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c
--- a/c8/stm/nursery.c
+++ b/c8/stm/nursery.c
@@ -87,6 +87,33 @@
}
+static void collect_roots_in_nursery(void)
+{
+ stm_thread_local_t *tl = STM_SEGMENT->running_thread;
+ struct stm_shadowentry_s *current = tl->shadowstack;
+ struct stm_shadowentry_s *finalbase = tl->shadowstack_base;
+ struct stm_shadowentry_s *ssbase;
+ ssbase = (struct stm_shadowentry_s *)tl->rjthread.moved_off_ssbase;
+ if (ssbase == NULL)
+ ssbase = finalbase;
+ else
+ assert(finalbase <= ssbase && ssbase <= current);
+
+ while (current > ssbase) {
+ --current;
+ uintptr_t x = (uintptr_t)current->ss;
+
+ if ((x & 3) == 0) {
+ /* the stack entry is a regular pointer (possibly NULL) */
+ minor_trace_if_young(¤t->ss);
+ }
+ else {
+ /* it is an odd-valued marker, ignore */
+ }
+ }
+}
+
+
static inline void _collect_now(object_t *obj)
{
assert(!_is_young(obj));
@@ -159,6 +186,8 @@
{
dprintf(("minor_collection commit=%d\n", (int)commit));
+ collect_roots_in_nursery();
+
collect_oldrefs_to_nursery();
assert(list_is_empty(STM_PSEGMENT->objects_pointing_to_nursery));
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -149,6 +149,45 @@
teardown_pages();
}
+static void _shadowstack_trap_page(char *start, int prot)
+{
+ size_t bsize = STM_SHADOW_STACK_DEPTH * sizeof(struct stm_shadowentry_s);
+ char *end = start + bsize + 4095;
+ end -= (((uintptr_t)end) & 4095);
+ mprotect(end, 4096, prot);
+}
+
+static void _init_shadow_stack(stm_thread_local_t *tl)
+{
+ size_t bsize = STM_SHADOW_STACK_DEPTH * sizeof(struct stm_shadowentry_s);
+ char *start = malloc(bsize + 8192); /* for the trap page, plus rounding */
+ if (!start)
+ stm_fatalerror("can't allocate shadow stack");
+
+ /* set up a trap page: if the shadowstack overflows, it will
+ crash in a clean segfault */
+ _shadowstack_trap_page(start, PROT_NONE);
+
+ struct stm_shadowentry_s *s = (struct stm_shadowentry_s *)start;
+ tl->shadowstack = s;
+ tl->shadowstack_base = s;
+ STM_PUSH_ROOT(*tl, -1);
+}
+
+static void _done_shadow_stack(stm_thread_local_t *tl)
+{
+ assert(tl->shadowstack > tl->shadowstack_base);
+ assert(tl->shadowstack_base->ss == (object_t *)-1);
+
+ char *start = (char *)tl->shadowstack_base;
+ _shadowstack_trap_page(start, PROT_READ | PROT_WRITE);
+
+ free(tl->shadowstack_base);
+ tl->shadowstack = NULL;
+ tl->shadowstack_base = NULL;
+}
+
+
static pthread_t *_get_cpth(stm_thread_local_t *tl)
{
assert(sizeof(pthread_t) <= sizeof(tl->creating_pthread));
@@ -177,6 +216,7 @@
num = (num + 1) % NB_SEGMENTS;
tl->associated_segment_num = num;
*_get_cpth(tl) = pthread_self();
+ _init_shadow_stack(tl);
set_gs_register(get_segment_base(num));
s_mutex_unlock();
}
@@ -186,7 +226,7 @@
s_mutex_lock();
assert(tl->prev != NULL);
assert(tl->next != NULL);
-
+ _done_shadow_stack(tl);
if (tl == stm_all_thread_locals) {
stm_all_thread_locals = stm_all_thread_locals->next;
if (tl == stm_all_thread_locals) {
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -48,9 +48,16 @@
#define STM_SEGMENT ((stm_segment_info_t *)4352)
+struct stm_shadowentry_s {
+ /* Like stm_read_marker_s, this is a struct to enable better
+ aliasing analysis in the C code. */
+ object_t *ss;
+};
+
typedef struct stm_thread_local_s {
/* rewind_setjmp's interface */
rewind_jmp_thread rjthread;
+ struct stm_shadowentry_s *shadowstack, *shadowstack_base;
/* the next fields are handled internally by the library */
int associated_segment_num;
struct stm_thread_local_s *prev, *next;
@@ -146,6 +153,10 @@
void stm_setup(void);
void stm_teardown(void);
+#define STM_SHADOW_STACK_DEPTH 163840
+#define STM_PUSH_ROOT(tl, p) ((tl).shadowstack++->ss = (object_t *)(p))
+#define STM_POP_ROOT(tl, p) ((p) = (typeof(p))((--(tl).shadowstack)->ss))
+#define STM_POP_ROOT_RET(tl) ((--(tl).shadowstack)->ss)
void stm_register_thread_local(stm_thread_local_t *tl);
void stm_unregister_thread_local(stm_thread_local_t *tl);
@@ -162,6 +173,13 @@
rewind_jmp_longjmp(&(tl)->rjthread)
#define stm_rewind_jmp_forget(tl) \
rewind_jmp_forget(&(tl)->rjthread)
+#define stm_rewind_jmp_restore_shadowstack(tl) do { \
+ assert(rewind_jmp_armed(&(tl)->rjthread)); \
+ (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)
long stm_start_transaction(stm_thread_local_t *tl);
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -15,8 +15,14 @@
...;
} rewind_jmp_thread;
+struct stm_shadowentry_s {
+ object_t *ss;
+};
+
+
typedef struct {
rewind_jmp_thread rjthread;
+ struct stm_shadowentry_s *shadowstack, *shadowstack_base;
int associated_segment_num;
struct stm_thread_local_s *prev, *next;
void *creating_pthread[2];
@@ -372,10 +378,15 @@
+SHADOWSTACK_LENGTH = 1000
_keepalive = weakref.WeakKeyDictionary()
def _allocate_thread_local():
tl = ffi.new("stm_thread_local_t *")
+ ss = ffi.new("struct stm_shadowentry_s[]", SHADOWSTACK_LENGTH)
+ _keepalive[tl] = ss
+ tl.shadowstack = ss
+ tl.shadowstack_base = ss
lib.stm_register_thread_local(tl)
return tl
@@ -445,10 +456,22 @@
stm_validate() # can raise
def push_root(self, o):
- assert 0
+ assert ffi.typeof(o) == ffi.typeof("object_t *")
+ tl = self.tls[self.current_thread]
+ curlength = tl.shadowstack - tl.shadowstack_base
+ assert 0 <= curlength < SHADOWSTACK_LENGTH
+ tl.shadowstack[0].ss = ffi.cast("object_t *", o)
+ tl.shadowstack += 1
def pop_root(self):
- assert 0
+ tl = self.tls[self.current_thread]
+ curlength = tl.shadowstack - tl.shadowstack_base
+ assert curlength >= 1
+ if curlength == 1:
+ raise EmptyStack
+ assert 0 < curlength <= SHADOWSTACK_LENGTH
+ tl.shadowstack -= 1
+ return ffi.cast("object_t *", tl.shadowstack[0].ss)
def push_root_no_gc(self):
"Pushes an invalid object, to crash in case the GC is called"
More information about the pypy-commit
mailing list