[#14922] alias $gvar — Koji Arai <JCA02266@...>

新井です。

19 messages 2001/10/14

[#15006] Re: eval.c (rb_stack_check): prohibit recursive raising error — WATANABE Hirofumi <eban@...>

わたなべです。

13 messages 2001/10/26
[#15008] Re: eval.c (rb_stack_check): prohibit recursive raising error — Shugo Maeda <shugo@...> 2001/10/26

前田です。

[ruby-dev:14971] Re: alias var and trace_var

From: "K.Kosako" <kosako@...>
Date: 2001-10-22 04:17:56 UTC
List: ruby-dev #14971
nobu.nakada@nifty.ne.jpさんの
<200110191357.f9JDv3k23792@sharui.nakada.kanuma.tochigi.jp>から
> > 個人的にはトレースに漏れがあり得るということに
> > 違和感があります。
> 
>  一応やってみました。global_entryを分割してますが、おそらくこ
> れが一番確実だと思います。1.48のようにgetter/setterをいじくる方
> 向では、これ以上は無理があるでしょう。

いいですね。
トレースのことは別にしても、こちらのほうがプログラムが
わかり易いので好きです。

仕様としては、トレース情報も共有するので、
alias $a $bを行うと、$aのトレース指定は、$bのトレース指定と
同じになるということですね。

ただ、global_variable構造体のメモリ開放漏れがあるようなので、
中田さんの修正の上に、参照カウンタを追加してみました。
(これも1.47からの差分です。)


--- variable.c.1.47	Mon Oct 22 11:13:32 2001
+++ variable.c	Mon Oct 22 12:57:04 2001
@@ -291,8 +291,8 @@
     struct trace_var *next;
 };
 
-struct global_entry {
-    ID id;
+struct global_variable {
+    int   counter;
     void *data;
     VALUE (*getter)();
     void  (*setter)();
@@ -301,6 +301,11 @@
     struct trace_var *trace;
 };
 
+struct global_entry {
+    struct global_variable *var;
+    ID id;
+};
+
 static VALUE undef_getter();
 static void  undef_setter();
 static void  undef_marker();
@@ -320,16 +325,20 @@
     struct global_entry *entry;
 
     if (!st_lookup(rb_global_tbl, id, &entry)) {
+	struct global_variable *var;
 	entry = ALLOC(struct global_entry);
 	st_add_direct(rb_global_tbl, id, entry);
+	var = ALLOC(struct global_variable);
 	entry->id = id;
-	entry->data = 0;
-	entry->getter = undef_getter;
-	entry->setter = undef_setter;
-	entry->marker = undef_marker;
+	entry->var = var;
+	var->counter = 1;
+	var->data = 0;
+	var->getter = undef_getter;
+	var->setter = undef_setter;
+	var->marker = undef_marker;
 
-	entry->block_trace = 0;
-	entry->trace = 0;
+	var->block_trace = 0;
+	var->trace = 0;
     }
     return entry;
 }
@@ -345,17 +354,17 @@
 }
 
 static void
-undef_setter(val, id, data, entry)
+undef_setter(val, id, data, var)
     VALUE val;
     ID id;
     void *data;
-    struct global_entry *entry;
+    struct global_variable *var;
 {
-    entry->getter = val_getter;
-    entry->setter = val_setter;
-    entry->marker = val_marker;
+    var->getter = val_getter;
+    var->setter = val_setter;
+    var->marker = val_marker;
 
-    entry->data = (void*)val;
+    var->data = (void*)val;
 }
 
 static void
@@ -372,13 +381,13 @@
 }
 
 static void
-val_setter(val, id, data, entry)
+val_setter(val, id, data, var)
     VALUE val;
     ID id;
     void *data;
-    struct global_entry *entry;
+    struct global_variable *var;
 {
-    entry->data = (void*)val;
+    var->data = (void*)val;
 }
 
 static void
@@ -428,9 +437,10 @@
     struct global_entry *entry;
 {
     struct trace_var *trace;
+    struct global_variable *var = entry->var;
 
-    (*entry->marker)(entry->data);
-    trace = entry->trace;
+    (*var->marker)(var->data);
+    trace = var->trace;
     while (trace) {
 	if (trace->data) rb_gc_mark_maybe(trace->data);
 	trace = trace->next;
@@ -467,14 +477,14 @@
     VALUE (*getter)();
     void  (*setter)();
 {
-    struct global_entry *entry;
+    struct global_variable *gvar;
     ID id = global_id(name);
 
-    entry = rb_global_entry(id);
-    entry->data = (void*)var;
-    entry->getter = getter?getter:var_getter;
-    entry->setter = setter?setter:var_setter;
-    entry->marker = var_marker;
+    gvar = rb_global_entry(id)->var;
+    gvar->data = (void*)var;
+    gvar->getter = getter?getter:var_getter;
+    gvar->setter = setter?setter:var_setter;
+    gvar->marker = var_marker;
 }
 
 void
@@ -532,20 +542,20 @@
 	rb_name_error(id, "undefined global variable %s", rb_id2name(id));
     }
     trace = ALLOC(struct trace_var);
-    trace->next = entry->trace;
+    trace->next = entry->var->trace;
     trace->func = rb_trace_eval;
     trace->data = cmd;
     trace->removed = 0;
-    entry->trace = trace;
+    entry->var->trace = trace;
 
     return Qnil;
 }
 
 static void
-remove_trace(entry)
-    struct global_entry *entry;
+remove_trace(var)
+    struct global_variable *var;
 {
-    struct trace_var *trace = entry->trace;
+    struct trace_var *trace = var->trace;
     struct trace_var t;
     struct trace_var *next;
 
@@ -557,9 +567,11 @@
 	    trace->next = next->next;
 	    free(next);
 	}
-	trace = next;
+	else {
+	    trace = next;
+	}
     }
-    entry->trace = t.next;
+    var->trace = t.next;
 }
 
 VALUE
@@ -578,7 +590,7 @@
 	rb_name_error(id, "undefined global variable %s", rb_id2name(id));
     }
 
-    trace = entry->trace;
+    trace = entry->var->trace;
     if (NIL_P(cmd)) {
 	VALUE ary = rb_ary_new();
 
@@ -588,16 +600,15 @@
 	    trace->removed = 1;
 	    trace = next;
 	}
-	entry->trace = 0;
 
-	if (!entry->block_trace) remove_trace(entry);
+	if (!entry->var->block_trace) remove_trace(entry->var);
 	return ary;
     }
     else {
 	while (trace) {
 	    if (trace->data == cmd) {
 		trace->removed = 1;
-		if (!entry->block_trace) remove_trace(entry);
+		if (!entry->var->block_trace) remove_trace(entry->var);
 		return rb_ary_new3(1, cmd);
 	    }
 	    trace = trace->next;
@@ -605,11 +616,13 @@
     }
     return Qnil;
 }
+
 VALUE
 rb_gvar_get(entry)
     struct global_entry *entry;
 {
-    return (*entry->getter)(entry->id, entry->data, entry);
+    struct global_variable *var = entry->var;
+    return (*var->getter)(entry->id, var->data, var);
 }
 
 struct trace_data {
@@ -631,11 +644,11 @@
 }
 
 static VALUE
-trace_en(entry)
-    struct global_entry *entry;
+trace_en(var)
+    struct global_variable *var;
 {
-    entry->block_trace = 0;
-    remove_trace(entry);
+    var->block_trace = 0;
+    remove_trace(var);
     return Qnil;		/* not reached */
 }
 
@@ -645,16 +658,17 @@
     VALUE val;
 {
     struct trace_data trace;
+    struct global_variable *var = entry->var;
 
     if (rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't change global variable value");
-    (*entry->setter)(val, entry->id, entry->data, entry);
+    (*var->setter)(val, entry->id, var->data, var);
 
-    if (entry->trace && !entry->block_trace) {
-	entry->block_trace = 1;
-	trace.trace = entry->trace;
+    if (var->trace && !var->block_trace) {
+	var->block_trace = 1;
+	trace.trace = var->trace;
 	trace.val = val;
-	rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)entry);
+	rb_ensure(trace_ev, (VALUE)&trace, trace_en, (VALUE)var);
     }
     return val;
 }
@@ -684,7 +698,7 @@
 rb_gvar_defined(entry)
     struct global_entry *entry;
 {
-    if (entry->getter == undef_getter) return Qfalse;
+    if (entry->var->getter == undef_getter) return Qfalse;
     return Qtrue;
 }
 
@@ -724,13 +738,27 @@
 
     if (rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't alias global variable");
+
     entry1 = rb_global_entry(name1);
     entry2 = rb_global_entry(name2);
-
-    entry1->data   = entry2->data;
-    entry1->getter = entry2->getter;
-    entry1->setter = entry2->setter;
-    entry1->marker = entry2->marker;
+    if (entry1->var != entry2->var) {
+	struct global_variable *var = entry1->var;
+	if (var->block_trace) {
+	    rb_raise(rb_eRuntimeError, "can't alias in tracer");
+	}
+	var->counter--;
+	if (var->counter == 0) {
+	    struct trace_var *trace = var->trace;
+	    while (trace) {
+		trace->removed = 1;
+		trace = trace->next;
+	    }
+	    remove_trace(var);
+	    free(var);
+	}
+	entry2->var->counter++;
+	entry1->var = entry2->var;
+    }
 }
 
 static int special_generic_ivar = 0;
--
小迫@ソフネック   渋谷区恵比寿1-15-1

In This Thread