From 8e864d1e8628a99a2187044f5c987f802dee6ab0 Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 4 Dec 2008 18:29:20 +0000 Subject: [PATCH] * load.c (rb_get_load_path): returns the load path without touching. * load.c (rb_feature_provided): new function to return the loading path in addition to rb_provided(). * load.c (search_required): sets path if loading. * variable.c (autoload_provided): load paths are expanded to check if loading. * variable.c (autoload_node): keeps autoload mark while loading. [ruby-core:20235] * variable.c (rb_const_get_0): loops while autoload mark is set. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20531 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 18 ++++++++ bootstraptest/test_autoload.rb | 9 ++++ include/ruby/intern.h | 1 + load.c | 32 +++++++------- variable.c | 77 +++++++++++++++++++++------------- 5 files changed, 90 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index e483361420..ed75ef4b75 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +Fri Dec 5 03:29:17 2008 Nobuyoshi Nakada + + * load.c (rb_get_load_path): returns the load path without + touching. + + * load.c (rb_feature_provided): new function to return the loading + path in addition to rb_provided(). + + * load.c (search_required): sets path if loading. + + * variable.c (autoload_provided): load paths are expanded to check + if loading. + + * variable.c (autoload_node): keeps autoload mark while loading. + [ruby-core:20235] + + * variable.c (rb_const_get_0): loops while autoload mark is set. + Fri Dec 5 01:37:02 2008 NAKAMURA Usaku * win32/win32.c (rb_w32_read): ERROR_BROKEN_PIPE is not a real error diff --git a/bootstraptest/test_autoload.rb b/bootstraptest/test_autoload.rb index 05376df220..048256170e 100644 --- a/bootstraptest/test_autoload.rb +++ b/bootstraptest/test_autoload.rb @@ -50,3 +50,12 @@ assert_equal 'ok', %q{ module M; end Thread.new{eval('$SAFE=4; ZZZ.new.hoge')}.value } + +assert_equal 'okok', %q{ + open("zzz.rb", "w") {|f| f.puts "class ZZZ; def self.ok;:ok;end;end"} + autoload :ZZZ, "./zzz.rb" + t1 = Thread.new {ZZZ.ok} + t2 = Thread.new {ZZZ.ok} + [t1.value, t2.value].join +} + diff --git a/include/ruby/intern.h b/include/ruby/intern.h index a2d4fcb91a..25ca518f8b 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -267,6 +267,7 @@ void rb_load(VALUE, int); void rb_load_protect(VALUE, int, int*); NORETURN(void rb_jump_tag(int)); int rb_provided(const char*); +int rb_feature_provided(const char *, const char **); void rb_provide(const char*); VALUE rb_f_require(VALUE, VALUE); VALUE rb_require_safe(VALUE, int); diff --git a/load.c b/load.c index dbca370576..0140108962 100644 --- a/load.c +++ b/load.c @@ -30,13 +30,7 @@ VALUE rb_get_load_path(void) { VALUE load_path = GET_VM()->load_path; - VALUE ary = rb_ary_new2(RARRAY_LEN(load_path)); - long i; - - for (i = 0; i < RARRAY_LEN(load_path); ++i) { - rb_ary_push(ary, rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil)); - } - return ary; + return load_path; } static VALUE @@ -197,6 +191,12 @@ rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const c int rb_provided(const char *feature) +{ + return rb_feature_provided(feature, 0); +} + +int +rb_feature_provided(const char *feature, const char **loading) { const char *ext = strrchr(feature, '.'); volatile VALUE fullpath = 0; @@ -208,15 +208,15 @@ rb_provided(const char *feature) } if (ext && !strchr(ext, '/')) { if (IS_RBEXT(ext)) { - if (rb_feature_p(feature, ext, Qtrue, Qfalse, 0)) return Qtrue; + if (rb_feature_p(feature, ext, Qtrue, Qfalse, loading)) return Qtrue; return Qfalse; } else if (IS_SOEXT(ext) || IS_DLEXT(ext)) { - if (rb_feature_p(feature, ext, Qfalse, Qfalse, 0)) return Qtrue; + if (rb_feature_p(feature, ext, Qfalse, Qfalse, loading)) return Qtrue; return Qfalse; } } - if (rb_feature_p(feature, feature + strlen(feature), Qtrue, Qfalse, 0)) + if (rb_feature_p(feature, feature + strlen(feature), Qtrue, Qfalse, loading)) return Qtrue; return Qfalse; } @@ -430,9 +430,8 @@ search_required(VALUE fname, volatile VALUE *path) return 'r'; } if ((tmp = rb_find_file(fname)) != 0) { - tmp = rb_file_expand_path(tmp, Qnil); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); - if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, 0)) + if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, &loading) || loading) *path = tmp; return 'r'; } @@ -447,9 +446,8 @@ search_required(VALUE fname, volatile VALUE *path) #ifdef DLEXT2 OBJ_FREEZE(tmp); if (rb_find_file_ext(&tmp, loadable_ext + 1)) { - tmp = rb_file_expand_path(tmp, Qnil); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); - if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0)) + if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, &loading) || loading) *path = tmp; return 's'; } @@ -457,9 +455,8 @@ search_required(VALUE fname, volatile VALUE *path) rb_str_cat2(tmp, DLEXT); OBJ_FREEZE(tmp); if ((tmp = rb_find_file(tmp)) != 0) { - tmp = rb_file_expand_path(tmp, Qnil); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); - if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0)) + if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, &loading) || loading) *path = tmp; return 's'; } @@ -471,9 +468,8 @@ search_required(VALUE fname, volatile VALUE *path) return 's'; } if ((tmp = rb_find_file(fname)) != 0) { - tmp = rb_file_expand_path(tmp, Qnil); ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); - if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0)) + if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, &loading) || loading) *path = tmp; return 's'; } diff --git a/variable.c b/variable.c index 65ea8e4f83..283db99266 100644 --- a/variable.c +++ b/variable.c @@ -1387,57 +1387,76 @@ autoload_delete(VALUE mod, ID id) return (NODE *)load; } -VALUE -rb_autoload_load(VALUE klass, ID id) +static VALUE +autoload_provided(VALUE arg) { - VALUE file; - NODE *load = autoload_delete(klass, id); - - if (!load || !(file = load->nd_lit)) { - return Qfalse; - } - return rb_require_safe(file, load->nd_nth); + const char **p = (const char **)arg; + return rb_feature_provided(*p, p); } static VALUE -autoload_file(VALUE mod, ID id) +reset_safe(VALUE safe) +{ + rb_set_safe_level_force((int)safe); + return safe; +} + +static NODE * +autoload_node(VALUE mod, ID id, int noload) { VALUE file; struct st_table *tbl; - st_data_t val, load, n = id; + st_data_t val; + NODE *load; + const char *loading; + int safe; if (!st_lookup(RCLASS_IV_TBL(mod), autoload, &val) || - !(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, n, &load)) { - return Qnil; + !(tbl = check_autoload_table((VALUE)val)) || !st_lookup(tbl, (st_data_t)id, &val)) { + return 0; } - file = ((NODE *)load)->nd_lit; + load = (NODE *)val; + file = load->nd_lit; Check_Type(file, T_STRING); if (!RSTRING_PTR(file) || !*RSTRING_PTR(file)) { rb_raise(rb_eArgError, "empty file name"); } - if (!rb_provided(RSTRING_PTR(file))) { - return file; + loading = RSTRING_PTR(file); + safe = rb_safe_level(); + rb_set_safe_level_force(0); + if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) { + return load; } + if (!noload && loading) { + return load; + } + return 0; +} - /* already loaded but not defined */ - st_delete(tbl, &n, 0); - if (!tbl->num_entries) { - n = autoload; - st_delete(RCLASS_IV_TBL(mod), &n, &val); - } - return Qnil; +VALUE +rb_autoload_load(VALUE klass, ID id) +{ + VALUE file; + NODE *load = autoload_node(klass, id, 0); + + if (!load) return Qfalse; + file = load->nd_lit; + return rb_require_safe(file, load->nd_nth); } VALUE rb_autoload_p(VALUE mod, ID id) { struct st_table *tbl = RCLASS_IV_TBL(mod); - VALUE val; + st_data_t val; + NODE *load; + VALUE file; if (!tbl || !st_lookup(tbl, id, &val) || val != Qundef) { return Qnil; } - return autoload_file(mod, id); + load = autoload_node(mod, id, 0); + return load && (file = load->nd_lit) ? file : Qnil; } static VALUE @@ -1451,7 +1470,7 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse) while (RTEST(tmp)) { while (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp),id,&value)) { if (value == Qundef) { - if (!RTEST(rb_autoload_load(tmp, id))) break; + rb_autoload_load(tmp, id); continue; } if (exclude && tmp == rb_cObject && klass != rb_cObject) { @@ -1636,7 +1655,7 @@ rb_const_defined_0(VALUE klass, ID id, int exclude, int recurse) retry: while (tmp) { if (RCLASS_IV_TBL(tmp) && st_lookup(RCLASS_IV_TBL(tmp), id, &value)) { - if (value == Qundef && NIL_P(autoload_file(klass, id))) + if (value == Qundef && !autoload_node(klass, id, 1)) return Qfalse; return Qtrue; } @@ -1675,7 +1694,7 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst) const char *dest = isconst ? "constant" : "class variable"; if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4) - rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest); + rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest); if (OBJ_FROZEN(klass)) { if (BUILTIN_TYPE(klass) == T_MODULE) { rb_error_frozen("module"); @@ -1698,7 +1717,7 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst) } } - if(isconst){ + if (isconst){ rb_vm_change_state(); } st_insert(RCLASS_IV_TBL(klass), id, val);