diff --git a/ChangeLog b/ChangeLog index 9160c0e48e..16f446e461 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Mon Oct 13 23:57:29 2003 Nobuyoshi Nakada + + * eval.c (rb_feature_p): match by classified suffix. + + * eval.c (rb_require_safe): require library in the specified safe + level. + + * variable.c (rb_autoload, rb_autoload_load): restore safe level + when autoload was called. [ruby-dev:21338] + + * intern.h: prototypes; rb_require_safe. + +Mon Oct 13 23:57:29 2003 Nobuyoshi Nakada + + * test/runner.rb: accept non-option arguments. + Mon Oct 13 20:49:51 2003 Yukihiro Matsumoto * string.c (str_new4): should not preserve FL_TAINT status in the @@ -35,7 +51,7 @@ Sat Oct 11 16:08:41 2003 Tanaka Akira Sat Oct 11 10:19:39 2003 Shugo Maeda * lib/monitor.rb: handle exceptions correctly. Thanks, Gennady - Bystritsky. + Bystritsky. Fri Oct 10 07:50:54 2003 Nobuyoshi Nakada diff --git a/eval.c b/eval.c index b00d304a2a..0c64af5f8e 100644 --- a/eval.c +++ b/eval.c @@ -5739,6 +5739,8 @@ rb_mod_module_eval(argc, argv, mod) VALUE rb_load_path; +NORETURN(static void load_failed _((VALUE))); + void rb_load(fname, wrap) VALUE fname; @@ -5761,7 +5763,7 @@ rb_load(fname, wrap) } tmp = rb_find_file(fname); if (!tmp) { - rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr); + load_failed(fname); } fname = tmp; @@ -5871,49 +5873,47 @@ VALUE ruby_dln_librefs; static VALUE rb_features; static st_table *loading_tbl; -static int -rb_feature_p(feature, wait) - const char *feature; - int wait; +#define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0) +#ifdef DLEXT2 +#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0) +#else +#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0) +#endif + +static char * +rb_feature_p(feature, ext, rb) + const char *feature, *ext; + int rb; { VALUE v; - char *f; - long i, len = strlen(feature); + char *f, *e; + long i, len, elen; + if (ext) { + len = ext - feature; + elen = strlen(ext); + } + else { + len = strlen(feature); + elen = 0; + } for (i = 0; i < RARRAY(rb_features)->len; ++i) { v = RARRAY(rb_features)->ptr[i]; f = StringValuePtr(v); - if (strcmp(f, feature) == 0) { - goto load_wait; + if (strncmp(f, feature, len) != 0) continue; + if (!*(e = f + len)) { + if (ext) continue; + return e; } - if (strncmp(f, feature, len) == 0) { - if (strcmp(f+len, ".so") == 0) { - return Qtrue; - } - if (strcmp(f+len, ".rb") == 0) { - if (wait) goto load_wait; - return Qtrue; - } + if (*e != '.') continue; + if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { + return e; + } + if ((rb || !ext) && (strcmp(e, ".rb") == 0)) { + return e; } } - return Qfalse; - - load_wait: - if (loading_tbl) { - char *ext = strrchr(f, '.'); - if (ext && strcmp(ext, ".rb") == 0) { - rb_thread_t th; - - while (st_lookup(loading_tbl, (st_data_t)f, (st_data_t *)&th)) { - if (th == curr_thread) { - return Qtrue; - } - CHECK_INTS; - rb_thread_schedule(); - } - } - } - return Qtrue; + return 0; } static const char *const loadable_ext[] = { @@ -5928,14 +5928,7 @@ int rb_provided(feature) const char *feature; { - VALUE f = rb_str_new2(feature); - - if (strrchr(feature, '.') == 0) { - if (rb_find_file_ext(&f, loadable_ext) == 0) { - return rb_feature_p(feature, Qfalse); - } - } - return rb_feature_p(RSTRING(f)->ptr, Qfalse); + return rb_feature_p(feature, 0, Qfalse) ? Qtrue : Qfalse; } static void @@ -5952,76 +5945,83 @@ rb_provide(feature) rb_provide_feature(rb_str_new2(feature)); } -NORETURN(static void load_failed _((VALUE))); -static VALUE load_dyna _((VALUE, VALUE)); -static VALUE load_rb _((VALUE, VALUE)); +static void +load_wait(ftptr) + char *ftptr; +{ + st_data_t th; + + if (!loading_tbl) return; + if (!st_lookup(loading_tbl, (st_data_t)ftptr, &th)) return; + if ((rb_thread_t)th == curr_thread) return; + do { + CHECK_INTS; + rb_thread_schedule(); + } while (st_lookup(loading_tbl, (st_data_t)ftptr, &th)); +} VALUE rb_f_require(obj, fname) VALUE obj, fname; { - VALUE feature, tmp; - char *ext; /* OK */ + return rb_require_safe(fname, ruby_safe_level); +} - if (OBJ_TAINTED(fname)) { - rb_check_safe_obj(fname); - } - StringValue(fname); - ext = strrchr(RSTRING(fname)->ptr, '.'); - if (ext && strchr(ext, '/')) ext = 0; - if (ext) { +static int +search_required(fname, featurep, path) + VALUE fname, *featurep, *path; +{ + VALUE tmp; + char *ext, *ftptr; + + *featurep = fname; + *path = 0; + ext = strrchr(ftptr = RSTRING(fname)->ptr, '.'); + if (ext && !strchr(ext, '/')) { if (strcmp(".rb", ext) == 0) { - feature = rb_str_dup(fname); - tmp = rb_find_file(fname); - if (tmp) { - return load_rb(feature, tmp); - } - load_failed(fname); + if (rb_feature_p(ftptr, ext, Qtrue)) return 'r'; + if (*path = rb_find_file(fname)) return 'r'; + return 0; } - else if (strcmp(".so", ext) == 0 || strcmp(".o", ext) == 0) { + else if (IS_SOEXT(ext)) { + if (rb_feature_p(ftptr, ext, Qfalse)) return 's'; tmp = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr); + *featurep = tmp; #ifdef DLEXT2 if (rb_find_file_ext(&tmp, loadable_ext+1)) { - return load_dyna(tmp, rb_find_file(tmp)); + *path = rb_find_file(tmp); + return 's'; } #else - feature = tmp; rb_str_cat2(tmp, DLEXT); - tmp = rb_find_file(tmp); - if (tmp) { - return load_dyna(feature, tmp); + if (*path = rb_find_file(tmp)) { + return 's'; } #endif } - else if (strcmp(DLEXT, ext) == 0) { - tmp = rb_find_file(fname); - if (tmp) { - return load_dyna(fname, tmp); - } + else if (IS_DLEXT(ext)) { + if (rb_feature_p(ftptr, ext, Qfalse)) return 's'; + if (*path = rb_find_file(fname)) return 's'; } -#ifdef DLEXT2 - else if (strcmp(DLEXT2, ext) == 0) { - tmp = rb_find_file(fname); - if (tmp) { - return load_dyna(fname, tmp); - } - } -#endif + } + if ((ext = rb_feature_p(ftptr, 0, Qfalse)) != 0) { + return strcmp(ext, ".rb") == 0 ? 'r' : 's'; } tmp = fname; switch (rb_find_file_ext(&tmp, loadable_ext)) { case 0: - break; + return 0; case 1: - return load_rb(tmp, tmp); + *featurep = tmp; + *path = rb_find_file(tmp); + return 'r'; default: - return load_dyna(tmp, rb_find_file(tmp)); + *featurep = tmp; + *path = rb_find_file(tmp); + return 's'; } - if (!rb_feature_p(RSTRING(fname)->ptr, Qfalse)) - load_failed(fname); - return Qfalse; } static void @@ -6031,85 +6031,101 @@ load_failed(fname) rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr); } -static VALUE -load_dyna(feature, fname) - VALUE feature, fname; +VALUE +rb_require_safe(fname, safe) + VALUE fname; + int safe; { + VALUE result = Qnil; int state; - volatile int safe = ruby_safe_level; + struct { + NODE *node; + ID func; + int vmode, safe; + } volatile saved; + char *volatile ftptr = 0; - if (rb_feature_p(RSTRING(feature)->ptr, Qfalse)) - return Qfalse; - rb_provide_feature(feature); - { - volatile int old_vmode = scope_vmode; - NODE *const volatile old_node = ruby_current_node; - const volatile ID old_func = ruby_frame->last_func; - - ruby_safe_level = 0; - ruby_current_node = 0; - ruby_sourcefile = rb_source_filename(RSTRING(fname)->ptr); - ruby_sourceline = 0; - ruby_frame->last_func = 0; - PUSH_TAG(PROT_NONE); - if ((state = EXEC_TAG()) == 0) { - void *handle; - - SCOPE_SET(SCOPE_PUBLIC); - handle = dln_load(RSTRING(fname)->ptr); - rb_ary_push(ruby_dln_librefs, LONG2NUM((long)handle)); - } - POP_TAG(); - ruby_current_node = old_node; - ruby_set_current_source(); - ruby_frame->last_func = old_func; - SCOPE_SET(old_vmode); + if (OBJ_TAINTED(fname)) { + rb_check_safe_obj(fname); } - ruby_safe_level = safe; - if (state) JUMP_TAG(state); - ruby_errinfo = Qnil; - - return Qtrue; -} - -static VALUE -load_rb(feature, fname) - VALUE feature, fname; -{ - int state; - char *ftptr; - volatile int safe = ruby_safe_level; - - if (rb_feature_p(RSTRING(feature)->ptr, Qtrue)) - return Qfalse; - ruby_safe_level = 0; - rb_provide_feature(feature); - /* loading ruby library should be serialized. */ - if (!loading_tbl) { - loading_tbl = st_init_strtable(); - } - /* partial state */ - ftptr = ruby_strdup(RSTRING(feature)->ptr); - st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread); - + StringValue(fname); + saved.vmode = scope_vmode; + saved.node = ruby_current_node; + saved.func = ruby_frame->last_func; + saved.safe = ruby_safe_level; PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - rb_load(fname, 0); + VALUE feature, path; + long handle; + int found; + + ruby_safe_level = safe; + found = search_required(fname, &feature, &path); + if (found) { + ftptr = RSTRING(feature)->ptr; + if (!path) { + load_wait(ftptr); + result = Qfalse; + } + else { + ruby_safe_level = 0; + rb_provide_feature(feature); + switch (found) { + case 'r': + /* loading ruby library should be serialized. */ + if (!loading_tbl) { + loading_tbl = st_init_strtable(); + } + /* partial state */ + st_insert(loading_tbl, + (st_data_t)(ftptr = ruby_strdup(ftptr)), + (st_data_t)curr_thread); + if (feature == fname && !OBJ_FROZEN(feature)) { + feature = rb_str_dup(feature); + OBJ_FREEZE(feature); + } + rb_load(path, 0); + break; + + case 's': + ruby_current_node = 0; + ruby_sourcefile = rb_source_filename(RSTRING(path)->ptr); + ruby_sourceline = 0; + ruby_frame->last_func = 0; + SCOPE_SET(SCOPE_PUBLIC); + handle = (long)dln_load(RSTRING(path)->ptr); + rb_ary_push(ruby_dln_librefs, LONG2NUM(handle)); + break; + } + result = Qtrue; + } + } } POP_TAG(); - st_delete(loading_tbl, (st_data_t *)&ftptr, 0); /* loading done */ - free(ftptr); - ruby_safe_level = safe; + ruby_current_node = saved.node; + ruby_set_current_source(); + ruby_frame->last_func = saved.func; + SCOPE_SET(saved.vmode); + ruby_safe_level = saved.safe; + if (ftptr) { + if (st_delete(loading_tbl, (st_data_t *)&ftptr, 0)) { /* loading done */ + free(ftptr); + } + } if (state) JUMP_TAG(state); + if (NIL_P(result)) { + load_failed(fname); + } + ruby_errinfo = Qnil; - return Qtrue; + return result; } VALUE rb_require(fname) const char *fname; { - return rb_f_require(Qnil, rb_str_new2(fname)); + return rb_require_safe(rb_str_new2(fname), ruby_safe_level); } static void diff --git a/intern.h b/intern.h index dacd985b74..9562f0053b 100644 --- a/intern.h +++ b/intern.h @@ -176,6 +176,7 @@ NORETURN(void rb_jump_tag _((int))); int rb_provided _((const char*)); void rb_provide _((const char*)); VALUE rb_f_require _((VALUE, VALUE)); +VALUE rb_require_safe _((VALUE, int)); void rb_obj_call_init _((VALUE, int, VALUE*)); VALUE rb_class_new_instance _((int, VALUE*, VALUE)); VALUE rb_block_proc _((void)); diff --git a/test/runner.rb b/test/runner.rb index b2841b012a..b4501bee94 100644 --- a/test/runner.rb +++ b/test/runner.rb @@ -4,4 +4,7 @@ rcsid = %w$Id$ Version = rcsid[2].scan(/\d+/).collect!(&method(:Integer)).freeze Release = rcsid[3].freeze -Test::Unit::AutoRunner.run(false, File.dirname(__FILE__)) +runner = Test::Unit::AutoRunner.new(true) +runner.to_run.concat(ARGV) +runner.to_run << File.dirname(__FILE__) if runner.to_run.empty? +runner.run diff --git a/variable.c b/variable.c index 3cee63b465..1e0aea4093 100644 --- a/variable.c +++ b/variable.c @@ -1147,7 +1147,7 @@ rb_autoload(mod, id, file) ID id; const char *file; { - VALUE av; + VALUE av, fn; struct st_table *tbl; if (!rb_is_const_id(id)) { @@ -1170,21 +1170,25 @@ rb_autoload(mod, id, file) st_add_direct(tbl, autoload, av); DATA_PTR(av) = tbl = st_init_numtable(); } - st_insert(tbl, id, rb_str_new2(file)); + fn = rb_str_new2(file); + FL_UNSET(fn, FL_TAINT); + OBJ_FREEZE(fn); + st_insert(tbl, id, (st_data_t)rb_node_newnode(NODE_MEMO, fn, ruby_safe_level, 0)); } -static VALUE +static NODE* autoload_delete(mod, id) VALUE mod; ID id; { - VALUE val, file = Qnil; + VALUE val; + st_data_t load = 0; st_delete(RCLASS(mod)->iv_tbl, (st_data_t*)&id, 0); if (st_lookup(RCLASS(mod)->iv_tbl, autoload, &val)) { struct st_table *tbl = check_autoload_table(val); - if (!st_delete(tbl, (st_data_t*)&id, &file)) file = Qnil; + st_delete(tbl, (st_data_t*)&id, &load); if (tbl->num_entries == 0) { DATA_PTR(val) = 0; @@ -1196,7 +1200,7 @@ autoload_delete(mod, id) } } - return file; + return (NODE *)load; } void @@ -1205,13 +1209,12 @@ rb_autoload_load(klass, id) ID id; { VALUE file; + NODE *load = autoload_delete(klass, id); - file = autoload_delete(klass, id); - if (NIL_P(file) || rb_provided(RSTRING(file)->ptr)) { + if (!load || !(file = load->nd_lit) || rb_provided(RSTRING(file)->ptr)) { const_missing(klass, id); } - FL_UNSET(file, FL_TAINT); - rb_f_require(Qnil, file); + rb_require_safe(file, load->nd_nth); } static VALUE @@ -1221,11 +1224,13 @@ autoload_file(mod, id) { VALUE val, file; struct st_table *tbl; + st_data_t load; if (!st_lookup(RCLASS(mod)->iv_tbl, autoload, &val) || - !(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &file)) { + !(tbl = check_autoload_table(val)) || !st_lookup(tbl, id, &load)) { return Qnil; } + file = ((NODE *)load)->nd_lit; Check_Type(file, T_STRING); if (!RSTRING(file)->ptr) { rb_raise(rb_eArgError, "empty file name");