From 534886dbe4b6ad481ddd1928bf8bd28377cc7541 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Mon, 27 Feb 2012 14:37:01 -0700 Subject: [PATCH] limit time for getting a native (JIT) stack trace It's possible for a deep recursion to be all in C instead of JIT-generated code, in which case the caching code for `current-continuation-mark' cannot kick in to make the operation effectively constant time. Bail out (to keep things constant time) if that happens. --- src/racket/src/jitstack.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/racket/src/jitstack.c b/src/racket/src/jitstack.c index b7d39ec2bb..03149cd779 100644 --- a/src/racket/src/jitstack.c +++ b/src/racket/src/jitstack.c @@ -70,6 +70,14 @@ typedef void *(*Get_Stack_Proc)(); #define CACHE_STACK_MIN_TRIGGER 128 +/* Normally, caching of a native trace on the stack ensures that + `current-continuation-marks' is effectively constant-time. + It's possible to have a deep stack section with no recognizable anchors + for caching, however, in which case `current-continuation-marks' + can become O(n); avoid that pathological case by limiting the + number of non-anchor frames in a row that we're willing to traverse. */ +#define UNKNOWN_FRAME_LIMIT 64 + #define USE_STACK_CHECK 0 #if USE_STACK_CHECK @@ -134,6 +142,7 @@ Scheme_Object *scheme_native_stack_trace(void) int use_unw = 0; int shift_cache_to_next = 0; int added_list_elem; + int unsuccess = 0; if (!sjc.get_stack_pointer_code) return NULL; @@ -180,7 +189,7 @@ Scheme_Object *scheme_native_stack_trace(void) #endif } - while (1) { + while (unsuccess < UNKNOWN_FRAME_LIMIT) { #ifdef MZ_USE_DWARF_LIBUNWIND if (use_unw) { q = (void *)unw_get_ip(&c); @@ -270,9 +279,14 @@ Scheme_Object *scheme_native_stack_trace(void) shift_cache_to_next = 0; } added_list_elem = 1; - } else + } else added_list_elem = 0; + if (!name) + unsuccess++; + else + unsuccess = 0; + /* Cache the result halfway up the stack, if possible. Only cache on frames where the previous frame had a return address with a name, because an arbitrary frame's return address on the stack @@ -300,6 +314,8 @@ Scheme_Object *scheme_native_stack_trace(void) shift_cache_to_next = 1; halfway = stack_end; + + unsuccess = -100000; /* if we got halfway, no need to bail out later */ } prev_had_name = !!name;