Author: Remi Meier <remi.me...@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" _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit