Author: Armin Rigo <ar...@tunes.org> Branch: reverse-debugger Changeset: r85468:550befa14f60 Date: 2016-06-30 12:36 +0200 http://bitbucket.org/pypy/pypy/changeset/550befa14f60/
Log: bug fixes, there is more diff --git a/pypy/interpreter/reverse_debugging.py b/pypy/interpreter/reverse_debugging.py --- a/pypy/interpreter/reverse_debugging.py +++ b/pypy/interpreter/reverse_debugging.py @@ -140,10 +140,13 @@ def stop_point_at_start_of_line(): if revdb.watch_save_state(): any_watch_point = False + space = dbstate.space for prog, watch_id, expected in dbstate.watch_progs: any_watch_point = True - got = _run_watch(prog) - if got != expected: + try: + if _run_watch(space, prog) != expected: + break + except OperationError: break else: watch_id = -1 @@ -466,19 +469,15 @@ space = dbstate.space try: code = interp_marshal.loads(space, space.wrap(marshalled_code)) - w_res = code.exec_code(space, space.builtin, space.builtin) - text = space.str_w(space.repr(w_res)) + text = _run_watch(space, code) except OperationError as e: revdb.send_watch(e.errorstr(space), ok_flag=0) else: revdb.send_watch(text, ok_flag=1) lambda_checkwatch = lambda: command_checkwatch -def _run_watch(code): - space = dbstate.space - try: - w_res = code.exec_code(space, space.builtin, space.builtin) - text = space.str_w(space.repr(w_res)) - except OperationError as e: - return e.errorstr(space) - return text + +def _run_watch(space, prog): + w_dict = space.builtin.w_dict + w_res = prog.exec_code(space, w_dict, w_dict) + return space.str_w(space.repr(w_res)) diff --git a/rpython/memory/gctransform/boehm.py b/rpython/memory/gctransform/boehm.py --- a/rpython/memory/gctransform/boehm.py +++ b/rpython/memory/gctransform/boehm.py @@ -29,7 +29,7 @@ ll_malloc_varsize = mh.ll_malloc_varsize fields = [("hash", lltype.Signed)] - if translator.config.translation.reverse_debugger: + if translator and translator.config.translation.reverse_debugger: fields.append(("uid", lltype.SignedLongLong)) self.HDR = lltype.Struct("header", *fields) HDRPTR = lltype.Ptr(self.HDR) @@ -74,11 +74,21 @@ # XXX same behavior for zero=True: in theory that's wrong if TYPE._is_atomic(): funcptr = self.malloc_fixedsize_atomic_ptr + opname = 'boehm_malloc_atomic' else: funcptr = self.malloc_fixedsize_ptr - v_raw = hop.genop("direct_call", - [funcptr, c_size], - resulttype=llmemory.GCREF) + opname = 'boehm_malloc' + tr = self.translator + if tr and tr.config.translation.reverse_debugger: + # Don't check for NULLs after the operation (it crashes anyway + # with an explicit error message in case of out-of-memory). + # Avoiding a direct_call lets _RPY_REVDB_PRUID() prints the + # right file/line, at least for fixed-size mallocs. + v_raw = hop.genop(opname, [c_size], resulttype=llmemory.GCREF) + else: + v_raw = hop.genop("direct_call", + [funcptr, c_size], + resulttype=llmemory.GCREF) finalizer_ptr = self.finalizer_funcptr_for_type(TYPE) if finalizer_ptr: c_finalizer_ptr = Constant(finalizer_ptr, self.FINALIZER_PTR) diff --git a/rpython/translator/revdb/src-revdb/revdb.c b/rpython/translator/revdb/src-revdb/revdb.c --- a/rpython/translator/revdb/src-revdb/revdb.c +++ b/rpython/translator/revdb/src-revdb/revdb.c @@ -279,20 +279,13 @@ { /* Boehm only */ if (obj->h_hash == 0) { - Signed h; - if (flag_io_disabled != FID_REGULAR_MODE) { - /* This is when running debug commands. Don't cache the - hash on the object at all. */ - return ~((Signed)obj); - } - /* When recording, we get the hash the normal way from the - pointer casted to an int, and record that. When replaying, - we read it from the record. In both cases, we cache the - hash in the object, so that we record/replay only once per - object. */ - RPY_REVDB_EMIT(h = ~((Signed)obj);, Signed _e, h); - assert(h != 0); - obj->h_hash = h; + /* We never need to record anything: if h_hash is zero (which + is the case for all newly allocated objects), then we just + copy h_uid. This gives a stable answer. This would give + 0 for all prebuilt objects, but these should not have a + null h_hash anyway. + */ + obj->h_hash = obj->h_uid; } return obj->h_hash; } @@ -853,6 +846,13 @@ static void check_at_end(uint64_t stop_points) { char dummy[1]; + if (rpy_revdb.buf_p != rpy_revdb.buf_limit - 1 || + read(rpy_rev_fileno, dummy, 1) > 0) { + fprintf(stderr, "RevDB file error: corrupted file (too much data or, " + "more likely, non-deterministic run, e.g. a " + "watchpoint with side effects)\n"); + exit(1); + } if (stop_points != rpy_revdb.stop_point_seen) { fprintf(stderr, "Bad number of stop points " "(seen %lld, recorded %lld)\n", @@ -860,11 +860,6 @@ (long long)stop_points); exit(1); } - if (rpy_revdb.buf_p != rpy_revdb.buf_limit - 1 || - read(rpy_rev_fileno, dummy, 1) > 0) { - fprintf(stderr, "RevDB file error: corrupted file (too much data?)\n"); - exit(1); - } if (stop_points != total_stop_points) { fprintf(stderr, "RevDB file modified while reading?\n"); exit(1); @@ -971,6 +966,7 @@ memcpy(future_ids, extra, cmd->extra_size); future_ids[cmd->extra_size / sizeof(uint64_t)] = 0; uid_break = *future_ids; + attach_gdb(); } future_next_id = future_ids; } @@ -1168,10 +1164,17 @@ return uid; } +struct destructor_s { + void *d_obj; + void (*d_callback)(void *); +}; + static int _ftree_compare(const void *obj1, const void *obj2) { - const struct pypy_header0 *h1 = obj1; - const struct pypy_header0 *h2 = obj2; + const struct destructor_s *d1 = obj1; + const struct destructor_s *d2 = obj2; + struct pypy_header0 *h1 = d1->d_obj; + struct pypy_header0 *h2 = d2->d_obj; if (h1->h_uid < h2->h_uid) return -1; if (h1->h_uid == h2->h_uid) @@ -1180,26 +1183,60 @@ return 1; } +static void _ftree_add(void **tree, void *obj, void (*callback)(void *)) +{ + /* Note: we always allocate an indirection through a + struct destructor_s, so that Boehm knows that 'obj' must be + kept alive. */ + struct destructor_s *node, **item; + node = GC_MALLOC_UNCOLLECTABLE(sizeof(struct destructor_s)); + node->d_obj = obj; + node->d_callback = callback; + item = tsearch(node, tree, _ftree_compare); + if (item == NULL) { + fprintf(stderr, "_ftree_add: out of memory\n"); + exit(1); + } + if (*item != node) { + fprintf(stderr, "_ftree_add: duplicate object\n"); + exit(1); + } +} + +static struct pypy_header0 *_ftree_pop(void **tree, uint64_t uid, + void (**callback_out)(void *)) +{ + struct destructor_s d_dummy, *entry, **item; + struct pypy_header0 o_dummy, *result; + + d_dummy.d_obj = &o_dummy; + o_dummy.h_uid = uid; + item = tfind(&d_dummy, tree, _ftree_compare); + if (item == NULL) { + fprintf(stderr, "_ftree_pop: object not found\n"); + exit(1); + } + entry = *item; + result = entry->d_obj; + if (callback_out) + *callback_out = entry->d_callback; + assert(result->h_uid == uid); + tdelete(entry, tree, _ftree_compare); + GC_FREE(entry); + return result; +} + RPY_EXTERN int rpy_reverse_db_fq_register(void *obj) { - /*fprintf(stderr, "FINALIZER_TREE: %lld -> %p\n", + fprintf(stderr, "FINALIZER_TREE: %lld -> %p\n", ((struct pypy_header0 *)obj)->h_uid, obj); - */ if (!RPY_RDB_REPLAY) { return 0; /* recording */ } else { - /* add the object into the finalizer_tree, keyed by the h_uid */ - void **item = tsearch(obj, &finalizer_tree, _ftree_compare); - if (item == NULL) { - fprintf(stderr, "fq_register: out of memory\n"); - exit(1); - } - if (*item != obj) { - fprintf(stderr, "fq_register: duplicate object\n"); - exit(1); - } + /* add the object into the finalizer_tree, keyed by the h_uid. */ + _ftree_add(&finalizer_tree, obj, NULL); return 1; /* replaying */ } } @@ -1210,47 +1247,19 @@ int64_t uid; RPY_REVDB_EMIT(uid = result ? ((struct pypy_header0 *)result)->h_uid : -1;, int64_t _e, uid); + fprintf(stderr, "next_dead: object %lld\n", uid); if (RPY_RDB_REPLAY) { if (uid == -1) { result = NULL; } else { /* fetch and remove the object from the finalizer_tree */ - void **item; - struct pypy_header0 dummy; - dummy.h_uid = uid; - item = tfind(&dummy, &finalizer_tree, _ftree_compare); - if (item == NULL) { - fprintf(stderr, "next_dead: object not found\n"); - exit(1); - } - result = *item; - assert(((struct pypy_header0 *)result)->h_uid == uid); - tdelete(result, &finalizer_tree, _ftree_compare); + result = _ftree_pop(&finalizer_tree, uid, NULL); } } return result; } -struct destructor_s { - void *obj; - void (*callback)(void *); -}; - - static int _dtree_compare(const void *obj1, const void *obj2) -{ - const struct destructor_s *d1 = obj1; - const struct destructor_s *d2 = obj2; - const struct pypy_header0 *h1 = d1->obj; - const struct pypy_header0 *h2 = d2->obj; - if (h1->h_uid < h2->h_uid) - return -1; - if (h1->h_uid == h2->h_uid) - return 0; - else - return 1; -} - RPY_EXTERN void rpy_reverse_db_register_destructor(void *obj, void (*callback)(void *)) { @@ -1259,23 +1268,7 @@ NULL, NULL, NULL); } else { - struct destructor_s **item; - struct destructor_s *node = malloc(sizeof(struct destructor_s)); - if (!node) { - fprintf(stderr, "register_destructor: malloc: out of memory\n"); - exit(1); - } - node->obj = obj; - node->callback = callback; - item = tsearch(node, &destructor_tree, _dtree_compare); - if (item == NULL) { - fprintf(stderr, "register_destructor: tsearch: out of memory\n"); - exit(1); - } - if (*item != node) { - fprintf(stderr, "register_destructor: duplicate object\n"); - exit(1); - } + _ftree_add(&destructor_tree, obj, callback); } } @@ -1292,26 +1285,15 @@ while (1) { int64_t uid; - struct destructor_s d_dummy, *entry, **item; - struct pypy_header0 o_dummy; + struct pypy_header0 *obj; + void (*callback)(void *); RPY_REVDB_EMIT(abort();, int64_t _e, uid); if (uid == -1) break; - d_dummy.obj = &o_dummy; - o_dummy.h_uid = uid; - item = tfind(&d_dummy, &destructor_tree, _dtree_compare); - if (item == NULL) { - fprintf(stderr, "replay_call_destructors: object not found\n"); - exit(1); - } - entry = *item; - assert(((struct pypy_header0 *)entry->obj)->h_uid == uid); - tdelete(entry, &destructor_tree, _dtree_compare); - - entry->callback(entry->obj); - free(entry); + obj = _ftree_pop(&destructor_tree, uid, &callback); + callback(obj); } } diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h b/rpython/translator/revdb/src-revdb/revdb_include.h --- a/rpython/translator/revdb/src-revdb/revdb_include.h +++ b/rpython/translator/revdb/src-revdb/revdb_include.h @@ -35,12 +35,19 @@ "%s:%d: %0*llx\n", \ __FILE__, __LINE__, 2 * sizeof(_e), \ ((unsigned long long)_e) & ((2ULL << (8*sizeof(_e)-1)) - 1)) +#endif + +#if 1 /* enable to print all allocs to stderr */ # define _RPY_REVDB_PRUID() \ fprintf(stderr, \ "%s:%d: obj %llu\n", \ __FILE__, __LINE__, (unsigned long long) uid) -#else +#endif + +#ifndef _RPY_REVDB_PRINT # define _RPY_REVDB_PRINT(mode) /* nothing */ +#endif +#ifndef _RPY_REVDB_PRUID # define _RPY_REVDB_PRUID() /* nothing */ #endif diff --git a/rpython/translator/revdb/test/test_basic.py b/rpython/translator/revdb/test/test_basic.py --- a/rpython/translator/revdb/test/test_basic.py +++ b/rpython/translator/revdb/test/test_basic.py @@ -150,8 +150,7 @@ assert match hash_value = int(match.group(1)) rdb = self.fetch_rdb([self.exename, 'Xx']) - # compute_identity_hash() call, but only the first one - x = rdb.next(); assert intmask(x) == intmask(hash_value) + # compute_identity_hash() doesn't record anything # write() call x = rdb.next(); assert x == len(out) x = rdb.next('i'); assert x == 0 # errno _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit