[#21338] $SAFE=4 での autoload — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

21 messages 2003/09/04
[#21346] Re: $SAFE=4 での autoload — nobu.nakada@... 2003/09/04

なかだです。

[#21359] Re: $SAFE=4 での autoload — Hidetoshi NAGAI <nagai@...> 2003/09/05

永井@知能.九工大です.

[#21419] Makefile.inのlex.c — Kazuhiro NISHIYAMA <zn@...>

西山和広です。

15 messages 2003/09/28

[ruby-dev:21363] Re: $SAFE=4 でのautoload

From: nobu.nakada@...
Date: 2003-09-08 14:19:07 UTC
List: ruby-dev #21363
なかだです。

At Sat, 6 Sep 2003 22:16:02 +0900,
Yukihiro Matsumoto wrote:
> |> そうすると、requireはautoloadを呼び出したときの$SAFEで実行すべ
> |> きでしょうか。もしそうだとすれば、今はすでにautoloadされている
> |> 定数をさらにautoloadしようとしても何も変わりませんが、違う$SAFE
> |> で呼ばれたときにはどっちを優先すべきなんでしょう。
> |
> |autoload を呼んで対応付けをしたときの $SAFE とすべきではないかと
> |思うのですが,何かまずいでしょうか.
> 
> まずくないです。autoloadでもrequreと同様に実行前に$SAFEを0に
> セットする必要があるでしょうね。

0? autoloadを呼んだときの$SAFE?

とりあえず、最初にautoloadを呼んだときのを優先するようにしてみ
ました。

* rb_feature_p: 外部にアクセスしないようにする。
  拡張ライブラリとスクリプトの区別は、rb_featuresの拡張子の分類
  だけに。

* rb_require_0: $SAFEを指定できるようにする。


Index: eval.c
===================================================================
RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.531
diff -u -2 -p -r1.531 eval.c
--- eval.c	5 Sep 2003 05:07:54 -0000	1.531
+++ eval.c	8 Sep 2003 10:27:56 -0000
@@ -5839,41 +5836,56 @@ rb_feature_p(feature, wait)
 {
     VALUE v;
-    char *f;
+    char *f, *ext = strrchr(feature, '.');
     long i, len = strlen(feature);
+    int rb = 1, so = 1;
 
+    if (ext && !strchr(ext, '/')) {
+	if (strcmp(ext, ".rb") == 0) {
+	    so = 0;
+	    len = ext - feature;
+	}
+	else if (strcmp(ext, ".so") == 0 || strcmp(ext, ".o") == 0 ||
+#ifdef DLEXT2
+		 strcmp(ext, DLEXT2) == 0 ||
+#endif
+		 strcmp(ext, DLEXT) == 0) {
+	    rb = 0;
+	    len = ext - feature;
+	}
+    }
     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;
+	ext = f + len;
+	if (!*ext) {
+	    if (feature[len]) continue;
+	    return Qtrue;
 	}
-	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;
+	if (so) {
+	    if (strcmp(ext, ".so") == 0 || strcmp(ext, ".o") == 0 ||
+#ifdef DLEXT2
+		strcmp(ext, DLEXT2) == 0 ||
+#endif
+		strcmp(ext, DLEXT) == 0) {
 		return Qtrue;
 	    }
 	}
-    }
-    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;
+	if (rb) {
+	    if (strcmp(ext, ".rb") == 0) {
+		if (wait && loading_tbl) {
+		    st_data_t th;
+
+		    while (st_lookup(loading_tbl, (st_data_t)f, &th)) {
+			if ((rb_thread_t)th == curr_thread) break;
+			CHECK_INTS;
+			rb_thread_schedule();
+		    }
 		}
-		CHECK_INTS;
-		rb_thread_schedule();
+		return Qtrue;
 	    }
 	}
     }
-    return Qtrue;
+    return Qfalse;
 }
 
@@ -5890,12 +5902,5 @@ 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, Qfalse);
 }
 
@@ -5914,149 +5919,138 @@ rb_provide(feature)
 }
 
-NORETURN(static void load_failed _((VALUE)));
-static VALUE load_dyna _((VALUE, VALUE));
-static VALUE load_rb _((VALUE, VALUE));
-
-VALUE
-rb_f_require(obj, fname)
-    VALUE obj, fname;
+static VALUE
+rb_require_0(fname, safe)
+    VALUE fname;
+    int safe;
 {
-    VALUE feature, tmp;
     char *ext; /* OK */
+    int state;
+    struct {
+	NODE *node;
+	ID func;
+	int vmode, safe;
+    } volatile save;
+    char *volatile ftptr = 0;
+    volatile VALUE failed = 0;
 
-    SafeStringValue(fname);
+    StringValue(fname);
+    if (rb_feature_p(RSTRING(fname)->ptr, Qfalse))
+	return Qfalse;
     ext = strrchr(RSTRING(fname)->ptr, '.');
-    if (ext && strchr(ext, '/')) ext = 0;
-    if (ext) {
-	if (strcmp(".rb", ext) == 0) {
-	    feature = rb_str_dup(fname);
-	    tmp = rb_find_file(fname);
-	    if (tmp) {
-		return load_rb(feature, tmp);
+    save.vmode = scope_vmode;
+    save.node = ruby_current_node;
+    save.func = ruby_frame->last_func;
+    save.safe = ruby_safe_level;
+    PUSH_TAG(PROT_NONE);
+    if ((state = EXEC_TAG()) == 0) {
+	VALUE feature, tmp;
+
+	ruby_safe_level = safe;
+	if (ext && !strchr(ext, '/')) {
+	    if (strcmp(".rb", ext) == 0) {
+		feature = rb_str_dup(fname);
+		tmp = rb_find_file(fname);
+		if (tmp) {
+		    goto load_rb;
+		}
+		goto load_failed;
 	    }
-	    load_failed(fname);
-	}
-	else if (strcmp(".so", ext) == 0 || strcmp(".o", ext) == 0) {
-	    tmp = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr);
+	    else if (strcmp(".so", ext) == 0 || strcmp(".o", ext) == 0) {
+		tmp = rb_str_new(RSTRING(fname)->ptr, ext-RSTRING(fname)->ptr);
 #ifdef DLEXT2
-	    if (rb_find_file_ext(&tmp, loadable_ext+1)) {
-		return load_dyna(tmp, rb_find_file(tmp));
-	    }
+		if (rb_find_file_ext(&tmp, loadable_ext+1)) {
+		    feature = tmp;
+		    tmp = rb_find_file(tmp);
+		    goto load_dyna;
+		}
 #else
-	    feature = tmp;
-	    rb_str_cat2(tmp, DLEXT);
-	    tmp = rb_find_file(tmp);
-	    if (tmp) {
-		return load_dyna(feature, tmp);
-	    }
+		feature = tmp;
+		rb_str_cat2(tmp, DLEXT);
+		tmp = rb_find_file(tmp);
+		if (tmp) {
+		    goto load_dyna;
+		}
 #endif
-	}
-	else if (strcmp(DLEXT, ext) == 0) {
-	    tmp = rb_find_file(fname);
-	    if (tmp) {
-		return load_dyna(fname, tmp);
 	    }
-	}
+	    else if (strcmp(DLEXT, ext) == 0) {
+		tmp = rb_find_file(fname);
+		if (tmp) {
+		    feature = fname;
+		    goto load_dyna;
+		}
+	    }
 #ifdef DLEXT2
-	else if (strcmp(DLEXT2, ext) == 0) {
-	    tmp = rb_find_file(fname);
-	    if (tmp) {
-		return load_dyna(fname, tmp);
+	    else if (strcmp(DLEXT2, ext) == 0) {
+		tmp = rb_find_file(fname);
+		if (tmp) {
+		    feature = fname;
+		    goto load_dyna;
+		}
 	    }
-	}
 #endif
-    }
-    tmp = fname;
-    switch (rb_find_file_ext(&tmp, loadable_ext)) {
-      case 0:
-	break;
-
-      case 1:
-	return load_rb(tmp, tmp);
-
-      default:
-	return load_dyna(tmp, rb_find_file(tmp));
-    }
-    if (!rb_feature_p(RSTRING(fname)->ptr, Qfalse))
-	load_failed(fname);
-    return Qfalse;
-}
-
-static void
-load_failed(fname)
-    VALUE fname;
-{
-    rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr);
-}
-
-static VALUE
-load_dyna(feature, fname)
-    VALUE feature, fname;
-{
-    int state;
+	}
+	tmp = fname;
+	switch (rb_find_file_ext(&tmp, loadable_ext)) {
+	  case 0:
+	  load_failed:
+	    failed = fname;
+	    break;
 
-    if (rb_feature_p(RSTRING(feature)->ptr, Qfalse))
-	return Qfalse;
-    rb_provide_feature(feature);
-    {
-	int volatile old_vmode = scope_vmode;
-	NODE *const volatile old_node = ruby_current_node;
-	const volatile ID old_func = ruby_frame->last_func;
-
-	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;
+	  case 1:
+	    feature = tmp;
+	  load_rb:
+	    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);
+	    rb_load(tmp, 0);
+	    break;
 
+	  default:
+	    feature = tmp;
+	    tmp = rb_find_file(tmp);
+	  load_dyna:
+	    rb_provide_feature(feature);
+	    ruby_current_node = 0;
+	    ruby_sourcefile = rb_source_filename(RSTRING(tmp)->ptr);
+	    ruby_sourceline = 0;
+	    ruby_frame->last_func = 0;
 	    SCOPE_SET(SCOPE_PUBLIC);
-	    handle = dln_load(RSTRING(fname)->ptr);
-	    rb_ary_push(ruby_dln_librefs, LONG2NUM((long)handle));
+	    {
+		void *handle = dln_load(RSTRING(tmp)->ptr);
+		rb_ary_push(ruby_dln_librefs, LONG2NUM((long)handle));
+	    }
+	    break;
 	}
-	POP_TAG();
-	ruby_current_node = old_node;
-	ruby_set_current_source();
-	ruby_frame->last_func = old_func;
-	SCOPE_SET(old_vmode);
+    }
+    POP_TAG();
+    ruby_safe_level = save.safe;
+    ruby_current_node = save.node;
+    ruby_set_current_source();
+    ruby_frame->last_func = save.func;
+    SCOPE_SET(save.vmode);
+    if (ftptr) {
+	st_delete(loading_tbl, (st_data_t *)&ftptr, 0); /* loading done */
+	free(ftptr);
     }
     if (state) JUMP_TAG(state);
     ruby_errinfo = Qnil;
 
-    return Qtrue;
+    if (fname = failed) {
+	rb_raise(rb_eLoadError, "No such file to load -- %s",
+		 RSTRING(fname)->ptr);
+    }
+    return Qfalse;
 }
 
-static VALUE
-load_rb(feature, fname)
-    VALUE feature, fname;
+VALUE
+rb_f_require(obj, fname)
+    VALUE obj, 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);
-
-    PUSH_TAG(PROT_NONE);
-    if ((state = EXEC_TAG()) == 0) {
-	rb_load(fname, 0);
-    }
-    POP_TAG();
-    st_delete(loading_tbl, (st_data_t *)&ftptr, 0); /* loading done */
-    free(ftptr);
-    ruby_safe_level = safe;
-    if (state) JUMP_TAG(state);
-
-    return Qtrue;
+    return rb_require_0(fname, ruby_safe_level);
 }
 
@@ -6065,5 +6059,19 @@ rb_require(fname)
     const char *fname;
 {
-    return rb_f_require(Qnil, rb_str_new2(fname));
+    return rb_require_0(rb_str_new2(fname), ruby_safe_level);
+}
+
+void
+rb_require_autoload(file, safe, klass, id)
+    VALUE file;
+    int safe;
+    VALUE klass;
+    ID id;
+{
+    PUSH_FRAME();
+    ruby_frame->last_class = klass;
+    ruby_frame->last_func = id;
+    rb_require_0(file, safe);
+    POP_FRAME();
 }
 
Index: variable.c
===================================================================
RCS file: /cvs/ruby/src/ruby/variable.c,v
retrieving revision 1.102
diff -u -2 -p -r1.102 variable.c
--- variable.c	30 Aug 2003 00:03:57 -0000	1.102
+++ variable.c	8 Sep 2003 02:17:01 -0000
@@ -1147,5 +1147,5 @@ rb_autoload(mod, id, file)
     const char *file;
 {
-    VALUE av;
+    VALUE av, fn;
     struct st_table *tbl;
 
@@ -1171,5 +1171,8 @@ rb_autoload(mod, id, file)
 	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, rb_assoc_new(fn, INT2FIX(ruby_safe_level)));
 }
 
@@ -1205,12 +1208,12 @@ rb_autoload_load(klass, id)
     ID id;
 {
-    VALUE file;
+    VALUE av;
 
-    file = autoload_delete(klass, id);
-    if (NIL_P(file) || rb_provided(RSTRING(file)->ptr)) {
+    av = autoload_delete(klass, id);
+    if (NIL_P(av) || rb_provided(RSTRING(RARRAY(av)->ptr[0])->ptr)) {
 	const_missing(klass, id);
     }
-    FL_UNSET(file, FL_TAINT);
-    rb_f_require(Qnil, file);
+    rb_require_autoload(RARRAY(av)->ptr[0], FIX2INT(RARRAY(av)->ptr[1]),
+			klass, id);
 }
 
@@ -1220,11 +1223,13 @@ autoload_file(mod, id)
     ID id;
 {
-    VALUE val, file;
+    VALUE val, av, file;
     struct st_table *tbl;
 
     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, &av)) {
 	return Qnil;
     }
+    Check_Type(av, T_ARRAY);
+    file = RARRAY(av)->ptr[0];
     Check_Type(file, T_STRING);
     if (!RSTRING(file)->ptr) {


-- 
--- 僕の前にBugはない。
--- 僕の後ろにBugはできる。
    中田 伸悦

In This Thread