[ruby-dev:31844] Re: SEGV by attr

From: Nobuyoshi Nakada <nobu@...>
Date: 2007-09-24 15:04:11 UTC
List: ruby-dev #31844
なかだです。

At Sun, 23 Sep 2007 00:52:42 +0900,
Tanaka Akira wrote in [ruby-dev:31818]:
> Program terminated with signal 11, Segmentation fault.
> #0  0x08058f4b in rb_attr (klass=3084222700, id=8776, read=2, write=0, ex=2) at eval_method.ci:441
> 441         snprintf(buf, len, "@%s", name);

ふと、ID_ATTRSETのようにID_INSTANCEなどもID_LOCALと対応関係があ
れば、わざわざあらためて文字列を作る必要もないんじゃないか、と思
いました。


Index: parse.y
===================================================================
--- parse.y	(revision 13508)
+++ parse.y	(working copy)
@@ -7375,4 +7375,28 @@ rb_id_attrset(ID id)
 }
 
+ID
+rb_id_ivar(ID id)
+{
+    id &= ~ID_SCOPE_MASK;
+    id |= ID_INSTANCE;
+    return id;
+}
+
+ID
+rb_id_cvar(ID id)
+{
+    id &= ~ID_SCOPE_MASK;
+    id |= ID_CLASS;
+    return id;
+}
+
+ID
+rb_id_gvar(ID id)
+{
+    id &= ~ID_SCOPE_MASK;
+    id |= ID_GLOBAL;
+    return id;
+}
+
 static NODE *
 attrset_gen(struct parser_params *parser, NODE *recv, ID id)
@@ -8504,8 +8528,20 @@ rb_intern3(const char *name, long len, r
     }
     if (m - name < len) id = ID_JUNK;
+    m = name;
+    switch (id) {
+      case ID_CLASS:
+	m++;
+      case ID_GLOBAL:
+      case ID_INSTANCE:
+	m++;
+	id |= rb_intern3(m, len-(m-name), enc) & ~ID_SCOPE_MASK;
+	goto id_register;
+      default:
+	break;
+    }
   new_id:
     id |= ++global_symbols.last_id << ID_SCOPE_SHIFT;
@@ -8534,4 +8570,17 @@ rb_intern_str(VALUE str)
 }
 
+static VALUE
+id2string(ID id)
+{
+    ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL;
+    VALUE str;
+
+    while (!(str = rb_id2str(id2))) {
+	if ((id2 & ID_SCOPE_MASK) == ID_CONST) return 0;
+	id2 = (id & ~ID_SCOPE_MASK) | ID_CONST;
+    }
+    return str;
+}
+
 VALUE
 rb_id2str(ID id)
@@ -8558,19 +8607,27 @@ rb_id2str(ID id)
 	return (VALUE)data;
 
-    if (is_attrset_id(id)) {
-	ID id2 = (id & ~ID_SCOPE_MASK) | ID_LOCAL;
-	VALUE str;
-
-	while (!(str = rb_id2str(id2))) {
-	    if (!is_local_id(id2)) return 0;
-	    id2 = (id & ~ID_SCOPE_MASK) | ID_CONST;
-	}
+    switch (id & ID_SCOPE_MASK) {
+      case ID_CLASS:
+	if (!(str = id2string(id))) return 0;
+	str = rb_str_append(rb_str_new2("@@"), str);
+	break;
+      case ID_GLOBAL:
+	if (!(str = id2string(id))) return 0;
+	str = rb_str_append(rb_str_new2("$"), str);
+	break;
+      case ID_INSTANCE:
+	if (!(str = id2string(id))) return 0;
+	str = rb_str_append(rb_str_new2("@"), str);
+	break;
+      case ID_ATTRSET:
+	if (!(str = id2string(id))) return 0;
 	str = rb_str_dup(str);
 	rb_str_cat(str, "=", 1);
-	rb_intern_str(str);
-	if (st_lookup(global_symbols.id_str, id, &data))
-	    return (VALUE)data;
+	break;
     }
-    return 0;
+    OBJ_FREEZE(str);
+    st_add_direct(global_symbols.sym_id, (st_data_t)str, id);
+    st_add_direct(global_symbols.id_str, id, (st_data_t)str);
+    return str;
 }
 
Index: eval_method.ci
===================================================================
--- eval_method.ci	(revision 13508)
+++ eval_method.ci	(working copy)
@@ -406,4 +406,5 @@ rb_method_boundp(VALUE klass, ID id, int
 }
 
+extern ID rb_id_ivar(ID);
 void
 rb_attr(VALUE klass, ID id, int read, int write, int ex)
@@ -438,5 +439,5 @@ rb_attr(VALUE klass, ID id, int read, in
 	rb_raise(rb_eArgError, "argument needs to be symbol or string");
     }
-    attriv = rb_intern_str(rb_sprintf("@%s", name));
+    attriv = rb_id_ivar(id);
     if (read) {
 	rb_add_method(klass, id, NEW_IVAR(attriv), noex);


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

In This Thread