Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Simplify backtrace mechanism; fix #3633 #3634 #3644
Instead of preserving a backtrace in `mrb_state`, `mrb_exc_set`
keeps packed backtrace in an exception object. `#backtrace` unpacks
it to an array of strings.
  • Loading branch information
matz committed May 23, 2017
1 parent d2458e6 commit 9644ad5
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 297 deletions.
14 changes: 1 addition & 13 deletions include/mruby.h
Expand Up @@ -152,12 +152,6 @@ struct mrb_context {

struct mrb_jmpbuf;

typedef struct {
const char *filename;
int lineno;
mrb_sym method_id;
} mrb_backtrace_entry;

typedef void (*mrb_atexit_func)(struct mrb_state*);

#define MRB_STATE_NO_REGEXP 1
Expand All @@ -172,15 +166,9 @@ typedef struct mrb_state {

struct mrb_context *c;
struct mrb_context *root_c;
struct iv_tbl *globals; /* global variable table */

struct RObject *exc; /* exception */
struct {
struct RObject *exc;
int n;
int n_allocated;
mrb_backtrace_entry *entries;
} backtrace;
struct iv_tbl *globals; /* global variable table */

struct RObject *top_self;
struct RClass *object_class; /* Object class */
Expand Down
1 change: 0 additions & 1 deletion include/mruby/error.h
Expand Up @@ -25,7 +25,6 @@ MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg);
MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
MRB_API mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv);
MRB_API mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
MRB_API mrb_value mrb_get_backtrace(mrb_state *mrb);
MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);

Expand Down

6 comments on commit 9644ad5

@alexsnaps
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether this fix is "correct" per se, but I think mrb_get_backtrace is broken (so is mrb_keep_backtrace , right?):

diff --git a/src/backtrace.c b/src/backtrace.c
index ea88aca9..d0693c65 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -230,5 +230,6 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
 mrb_value
 mrb_get_backtrace(mrb_state *mrb)
 {
-  return mrb_unpack_backtrace(mrb, packed_backtrace(mrb));
+  mrb_value backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
+  return mrb_unpack_backtrace(mrb, backtrace);
 }

mrb_get_backtrace doesn't return any backtraces otherwise (supposedly 1 stack frame, where the filename is empty...)

@matz
Copy link
Member Author

@matz matz commented on 9644ad5 May 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mrb_get_backtrace() is an implementation function of caller() so it's not a function to retrieve backtrace from an exception, but retrieve backtrace from call stack. Thus it's correct.

@alexsnaps
Copy link

@alexsnaps alexsnaps commented on 9644ad5 May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@matz cool (though I'm not really sure what the function does, but I guess that's the exact issue then).
I used to:

auto ruby_backtrace = mrb_exc_backtrace(mrb, exception);
// RARRAY_PTR(ruby_backtrace) and use the backtrace as needed

But mrb_exc_backtrace got yanked. So how am I to get to the backtrace now?
Based on the diff above, I guess I could now:

mrb_value backtrace = mrb_obj_iv_get(mrb, mrb->exc, mrb_intern_lit(mrb, "backtrace"));
auto ruby_backtrace = mrb_unpack_backtrace(mrb, backtrace);

But I don't think I should have access to mrb_unpack_backtrace... I must be missing the obvious, but how does one get to the backtrace now?

I was thinking mrb_get_backtrace would provide this for me. But surprisingly, while

mrb_print_backtrace(mrb);

prints out the backtrace just fine, while

auto ruby_backtrace = mrb_get_backtrace(mrb);

doesn't seem to return anything useful...

@matz
Copy link
Member Author

@matz matz commented on 9644ad5 May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those functions work differently. mrb_print_backtrace prints the backtrace from the last exception (mrb->exc). But mrb_get_backtrace retrieves the backtrace from the current call frames (no relation to exceptions).

I think we should restore mrb_exc_backtrace.

@matz
Copy link
Member Author

@matz matz commented on 9644ad5 May 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored.

@alexsnaps
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome. Thanks!

Please sign in to comment.