Project

General

Profile

Feature #6286 ยป 0001-Feature-6286.patch

nobu (Nobuyoshi Nakada), 04/16/2012 08:57 PM

View differences:

eval.c
Init_vm_eval();
Init_eval_method();
Init_eval_error();
rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, -1);
eval_error.c
static void
error_print(void)
{
volatile VALUE errat = Qnil; /* OK */
rb_thread_t *th = GET_THREAD();
VALUE errinfo = th->errinfo;
int raised_flag = th->raised_flag;
volatile VALUE eclass, e;
const char *volatile einfo;
volatile long elen;
if (NIL_P(errinfo))
return;
......
PUSH_TAG();
if (EXEC_TAG() == 0) {
errat = get_backtrace(errinfo);
}
else {
errat = Qnil;
VALUE mesgs = rb_funcall(errinfo, rb_intern("format"), 0);
if (RB_TYPE_P(mesgs, T_ARRAY)) {
OBJ_FREEZE(mesgs);
rb_write_error_ary(RARRAY_LEN(mesgs), RARRAY_PTR(mesgs));
}
}
if (EXEC_TAG())
goto error;
if (NIL_P(errat)) {
const char *file = rb_sourcefile();
POP_TAG();
rb_thread_raised_set(th, raised_flag);
}
static VALUE
error_error_position(VALUE errinfo, VALUE errat)
{
VALUE mesg;
if (NIL_P(errat) ||
(errat = rb_check_backtrace(errat), RARRAY_LEN(errat)) == 0 ||
NIL_P(mesg = RARRAY_PTR(errat)[0])) {
VALUE file = rb_sourcefilename();
int line = rb_sourceline();
if (!file)
warn_printf("%d", line);
else if (!line)
warn_printf("%s", file);
else
warn_printf("%s:%d", file, line);
}
else if (RARRAY_LEN(errat) == 0) {
error_pos();
}
else {
VALUE mesg = RARRAY_PTR(errat)[0];
if (NIL_P(mesg))
error_pos();
if (NIL_P(file)) {
mesg = rb_sprintf("%d", line);
}
else {
warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg));
mesg = rb_str_dup(file);
if (line) {
ID callee = rb_frame_callee();
rb_str_catf(mesg, ":%d", line);
if (callee != 0) {
rb_str_buf_cat_ascii(mesg, ":in `");
rb_str_append(mesg, rb_id2str(callee));
rb_str_buf_cat_ascii(mesg, "'");
}
}
}
}
eclass = CLASS_OF(errinfo);
if (EXEC_TAG() == 0) {
e = rb_funcall(errinfo, rb_intern("message"), 0, 0);
StringValue(e);
einfo = RSTRING_PTR(e);
elen = RSTRING_LEN(e);
}
else {
einfo = "";
elen = 0;
mesg = rb_str_dup(mesg);
}
if (EXEC_TAG())
goto error;
if (eclass == rb_eRuntimeError && elen == 0) {
warn_print(": unhandled exception\n");
return mesg;
}
static VALUE
error_append_message(VALUE errinfo, VALUE mesg, VALUE errmsg)
{
const char *einfo = StringValueCStr(errmsg);
long elen = RSTRING_LEN(errmsg);
VALUE epath = rb_class_name(CLASS_OF(errinfo));
const char *tail = 0;
long len = elen;
StringValue(mesg);
rb_str_buf_cat_ascii(mesg, ": ");
if (elen == 0) {
rb_str_append(mesg, epath);
rb_str_buf_cat_ascii(mesg, "\n");
}
else {
VALUE epath;
epath = rb_class_name(eclass);
if (elen == 0) {
warn_print(": ");
warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
warn_print("\n");
if (RSTRING_PTR(epath)[0] == '#')
epath = 0;
if ((tail = memchr(einfo, '\n', elen)) != 0) {
len = tail - einfo;
tail++; /* skip newline */
}
else {
char *tail = 0;
long len = elen;
if (RSTRING_PTR(epath)[0] == '#')
epath = 0;
if ((tail = memchr(einfo, '\n', elen)) != 0) {
len = tail - einfo;
tail++; /* skip newline */
}
warn_print(": ");
warn_print2(einfo, len);
if (epath) {
warn_print(" (");
warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
warn_print(")\n");
}
if (tail) {
warn_print2(tail, elen - len - 1);
if (einfo[elen-1] != '\n') warn_print2("\n", 1);
}
rb_str_cat(mesg, einfo, len);
if (epath) {
rb_str_buf_cat_ascii(mesg, " (");
rb_str_append(mesg, epath);
rb_str_buf_cat_ascii(mesg, ")\n");
}
if (tail) {
rb_str_buf_cat(mesg, tail, elen - len - 1);
}
if (RSTRING_PTR(mesg)[RSTRING_LEN(mesg)-1] != '\n') {
rb_str_buf_cat_ascii(mesg, "\n");
}
}
return mesg;
}
static VALUE
runtimeerror_append_message(VALUE errinfo, VALUE mesg, VALUE errmsg)
{
StringValue(mesg);
StringValue(errmsg);
if (RSTRING_LEN(errmsg) == 0) {
rb_str_buf_cat_ascii(mesg, ": unhandled exception\n");
return mesg;
}
else {
VALUE args[2];
args[0] = mesg;
args[1] = errmsg;
return rb_call_super(2, args);
}
}
static VALUE
error_format_backtrace(VALUE errinfo, VALUE errat)
{
VALUE result = Qnil;
if (!NIL_P(errat)) {
long i;
long len = RARRAY_LEN(errat);
VALUE *ptr = RARRAY_PTR(errat);
int skip = eclass == rb_eSysStackError;
#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
#define TRACE_HEAD 8
#define TRACE_TAIL 5
errat = rb_check_backtrace(errat);
result = rb_ary_new2(RARRAY_LEN(errat));
for (i = 1; i < len; i++) {
if (RB_TYPE_P(ptr[i], T_STRING)) {
warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
}
if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
warn_printf("\t ... %ld levels...\n",
len - TRACE_HEAD - TRACE_TAIL);
i = len - TRACE_TAIL;
for (i = 1; i < RARRAY_LEN(errat); i++) {
VALUE mesg = RARRAY_PTR(errat)[i];
if (RB_TYPE_P(mesg, T_STRING)) {
mesg = rb_enc_sprintf(rb_enc_get(mesg), "\tfrom %s\n", RSTRING_PTR(mesg));
rb_ary_push(result, mesg);
}
}
}
error:
POP_TAG();
rb_thread_raised_set(th, raised_flag);
return result;
}
static VALUE
error_format(VALUE errinfo)
{
VALUE errmsg = rb_funcall(errinfo, rb_intern("message"), 0, 0);
VALUE errat = get_backtrace(errinfo);
errmsg = rb_funcall(errinfo, rb_intern("append_message"), 2,
rb_funcall(errinfo, rb_intern("error_position"), 1, errat),
errmsg);
errat = rb_funcall(errinfo, rb_intern("format_backtrace"), 1, errat);
rb_funcall(errat, rb_intern("unshift"), 1, errmsg);
return errat;
}
void
......
rb_threadptr_reset_raised(th);
return status;
}
static void
Init_eval_error(void)
{
rb_define_private_method(rb_eException, "format", error_format, 0);
rb_define_private_method(rb_eException, "error_position", error_error_position, 1);
rb_define_private_method(rb_eException, "append_message", error_append_message, 2);
rb_define_private_method(rb_eException, "format_backtrace", error_format_backtrace, 1);
rb_define_private_method(rb_eRuntimeError, "append_message", runtimeerror_append_message, 2);
}
include/ruby/intern.h
VALUE rb_gets(void);
void rb_write_error(const char*);
void rb_write_error2(const char*, long);
void rb_write_error_ary(long, const VALUE*);
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds);
int rb_pipe(int *pipes);
int rb_reserved_fd_p(int fd);
io.c
}
void
rb_write_error_ary(long mesgc, const VALUE *mesgs)
{
long i;
if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
for (i = 0; i < mesgc; ++i) {
VALUE mesg = mesgs[i];
size_t len = RSTRING_LEN(mesg);
if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
/* failed to write to stderr, what can we do? */
return;
}
}
}
else {
for (i = 0; i < mesgc; ++i) {
rb_io_write(rb_stderr, mesgs[i]);
}
}
}
void
rb_write_error2(const char *mesg, long len)
{
if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
prelude.rb
}
end
end
class SystemStackError
TRACE_HEAD = 8
TRACE_TAIL = 5
TRACE_MAX = TRACE_HEAD + TRACE_TAIL + 5
private_constant :TRACE_HEAD, :TRACE_TAIL, :TRACE_MAX
private
def format_backtrace(bt)
if (size = bt.size) > TRACE_MAX
bt = super(bt[0..TRACE_HEAD] + bt[-TRACE_TAIL..-1])
bt.insert(8, "\t ... #{size - (TRACE_HEAD - TRACE_TAIL)} levels...\n")
bt
else
super
end
end
end
test/ruby/test_exception.rb
ensure
t.close(true) if t
end
class ErrorPositionTest < RuntimeError
private
def error_position(at)
"FOOBAR"
end
end
Feature6286 = '[ruby-core:44328]'
Feature6286Pos = [
"#{__FILE__}:#{__LINE__}".freeze,
"#{__FILE__}:#{__LINE__}".freeze
]
def test_format
pos = Feature6286Pos
expected = [
"#{pos[0]}: foo (RuntimeError)\n",
"\tfrom #{pos[1]}\n",
]
e = assert_raise(RuntimeError) {raise RuntimeError, "foo", pos}
assert_equal(expected, e.__send__(:format), Feature6286)
end
def test_error_position
pos = Feature6286Pos
expected = [
"FOOBAR: foo (TestException::ErrorPositionTest)\n",
"\tfrom #{pos[1]}\n",
]
e = assert_raise(ErrorPositionTest) {raise ErrorPositionTest, "foo", pos}
assert_equal(expected, e.__send__(:format), Feature6286)
end
def test_error_position_anonymous
pos = Feature6286Pos
eclass = Class.new(ErrorPositionTest)
expected = [
"FOOBAR: foo\n",
"\tfrom #{pos[1]}\n",
]
e = assert_raise(eclass) {raise eclass, "foo", pos}
assert_equal(expected, e.__send__(:format), Feature6286)
end
def test_append_message
pos = Feature6286Pos
eclass = Class.new(ErrorPositionTest) do
private
def append_message(mesg, err)
mesg << ": bar\n"
end
end
expected = [
"FOOBAR: bar\n",
"\tfrom #{pos[1]}\n",
]
e = assert_raise(eclass) {raise eclass, "foo", pos}
assert_equal(expected, e.__send__(:format), Feature6286)
end
def test_format_backtrace
pos = Feature6286Pos
eclass = Class.new(ErrorPositionTest) do
private
def format_backtrace(at)
["\tzzz\n"]
end
end
expected = [
"FOOBAR: foo\n",
"\tzzz\n",
]
e = assert_raise(eclass) {raise eclass, "foo", pos}
assert_equal(expected, e.__send__(:format), Feature6286)
end
end
    (1-1/1)