summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog18
-rw-r--r--bootstraptest/test_autoload.rb9
-rw-r--r--include/ruby/intern.h1
-rw-r--r--load.c32
-rw-r--r--variable.c77
5 files changed, 90 insertions, 47 deletions
diff --git a/ChangeLog b/ChangeLog
index e483361420b..ed75ef4b757 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+Fri Dec 5 03:29:17 2008 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * 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 <usa@ruby-lang.org>
* 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 05376df2204..048256170ea 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 a2d4fcb91ab..25ca518f8bc 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 dbca370576b..01401089626 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
@@ -198,6 +192,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 65ea8e4f83d..283db992664 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;
}
-
- /* already loaded but not defined */
- st_delete(tbl, &n, 0);
- if (!tbl->num_entries) {
- n = autoload;
- st_delete(RCLASS_IV_TBL(mod), &n, &val);
+ if (!noload && loading) {
+ return load;
}
- return Qnil;
+ return 0;
+}
+
+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);