Ruby Forum Ruby-dev > x86_64$B4D6-$G(BMarshal.dump$B$NIT6q9g(B

Posted by Kouichi Ushijima (Guest)
on 01.09.2008 15:02
(Received via mailing list)
NTT$B%l%>%J%s%H$N5mEg$H?=$7$^$9!#(B

x86_64$B4D6-$G(BMarshal.dump/load$B$,$&$^$/F/$+$J$$8=>]$KAx6x$7$^$7$?$N$G!"Js(B
$B9p$5$;$F$$$?$@$-$^$9!#(B

$B:F8=%3!<%I$r0J2<$K<($7$^$9!#K\MhEy$7$$$O$:$N(Bobj$B$H(Bobj1$B$,Ey$7$/$J$$$HH=Dj(B
$B$5$l$F$7$^$$$^$9!#(B

---------
obj = Array.new(10000) do
  Time.now.to_i + (rand * 10).to_i
end

obj1 = Marshal.load(Marshal.dump(obj))
p obj1 == obj
# ==> false!
---------

$B8D!9$NMWAG$rHf3S$7$F$_$k$H!";d$N4D6-$G$O(Bobj1[6449]$B0J9_$NCM$,68$C$F$7$^$C(B
$B$F$$$^$9!#(BArray$B$ND9$5$,C;$$$H$-$K$OH/@8$7$J$$$H$3$m$r8+$k$H!"$I$&$d$i(BGC
$B$,0-$5$r$7$F$$$k$h$&$G$9!#(B

$BAG?M9M$($G$9$,!"(Bmarshal.c$B$N(Bw_object()$B$N(BFIXNUM$B$N(Bdump$B=hM}$G!"0l;~E*$K@8@.(B
$B$5$l$?(BBignum$B%*%V%8%'%/%H$,(BMarshal.dump$BCf$K2rJ|$5$l$F$7$^$&$N$,LdBj$N$h$&(B
$B$J5$$,$7$^$9!#(B

--------
    else if (FIXNUM_P(obj)) {
#if SIZEOF_LONG <= 4
        w_byte(TYPE_FIXNUM, arg);
        w_long(FIX2INT(obj), arg);
#else
        if (RSHIFT((long)obj, 31) == 0 || RSHIFT((long)obj, 31) == -1) {
            w_byte(TYPE_FIXNUM, arg);
            w_long(FIX2LONG(obj), arg);
        }
        else {
            w_object(rb_int2big(FIX2LONG(obj)), arg, limit);
                     ^^^^^^^^^^^^^^^^^^^^^^^^^
        }
#endif
--------

$B3NG'$7$?4D6-$O0J2<$NDL$j$G$9!#(B
- Red Hat Enterprise Linux Server release 5.2 (Tikanga)
  Linux host 2.6.18-92.1.6.el5 #1 SMP Fri Jun 20 02:36:06 EDT 2008
x86_64 x86_64 x86_64 GNU/Linux
- ruby 1.8.6 (2008-08-11 patchlevel 287) [x86_64-linux]

$B0J>e!"$h$m$7$/$*4j$$$7$^$9!#(B
Posted by Shugo Maeda (Guest)
on 01.09.2008 17:47
(Received via mailing list)
$BA0ED$G$9!#(B

2008/09/01 21:56 Kouichi Ushijima <ushijima@nttr.co.jp>:
> # ==> false!
> ---------

Solaris/x86_64$B$G$b:F8=$7$^$7$?!#(B
$B0J2<$N%3!<%I$G$b:F8=$9$k$h$&$G$9!#(B

obj = [1220278665, 1220278662, 1220278661, 1220278661, 1220278656]

GC.stress = true
s = Marshal.dump(obj)
obj1 = Marshal.load(s)
p obj1 == obj

$B$I$&$d$i(Bmarshal.c$B$N(Bw_object()$B$N0J2<$N(Bif$BJ8$N>r7o$,??$K$J$C$F$$$k$h$&$J$N$G$9$,!"(B

    if (st_lookup(arg->data, obj, &num)) {
        w_byte(TYPE_LINK, arg);
        w_long((long)num, arg);
        return;
    }

dump$BCf$K(BGC$B$,H/@8$9$k$H!"0l;~E*$K@8@.$7$?(BBignum$B%*%V%8%'%/%H$N%"%I%l%9$,(B
$B$?$^$?$^F1$8$K$J$C$F$7$^$&$?$a!"(Barg->data$B$N8!:w;~$K8m$C$F0JA0$N%*%V%8%'%/%H(B
$B$K%R%C%H$7$F%j%s%/$H$7$F=hM}$5$l$F$7$^$&$h$&$G$9!#(B
$BB>$K$b(Bdump$BCf$K0l;~E*$K%*%V%8%'%/%H$r@8@.$7$F$$$kItJ,$,$b$7$"$l$P!"F1$8$h$&(B
$B$JLdBj$,H/@8$7$=$&$G$9$M!#(B

$BBP1~$H$7$F$O(Barg->data$B$r(BHash$B$K$9$k$H$+$G$7$g$&$+!#(B
Posted by Yukihiro Matsumoto (Guest)
on 01.09.2008 17:59
(Received via mailing list)
$B$^$D$b$H(B $B$f$-$R$m$G$9(B

In message "Re: [ruby-dev:36086] Re: 
x86_64$B4D6-$G(BMarshal.dump$B$NIT6q9g(B"
    on Tue, 2 Sep 2008 00:41:51 +0900, "Shugo Maeda" 
<shugo@ruby-lang.org> writes:

|$B$I$&$d$i(Bmarshal.c$B$N(Bw_object()$B$N0J2<$N(Bif$BJ8$N>r7o$,??$K$J$C$F$$$k$h$&$J$N$G$9$,!"(B
|
|    if (st_lookup(arg->data, obj, &num)) {
|        w_byte(TYPE_LINK, arg);
|        w_long((long)num, arg);
|        return;
|    }
|
|dump$BCf$K(BGC$B$,H/@8$9$k$H!"0l;~E*$K@8@.$7$?(BBignum$B%*%V%8%'%/%H$N%"%I%l%9$,(B
|$B$?$^$?$^F1$8$K$J$C$F$7$^$&$?$a!"(Barg->data$B$N8!:w;~$K8m$C$F0JA0$N%*%V%8%'%/%H(B
|$B$K%R%C%H$7$F%j%s%/$H$7$F=hM}$5$l$F$7$^$&$h$&$G$9!#(B
|$BB>$K$b(Bdump$BCf$K0l;~E*$K%*%V%8%'%/%H$r@8@.$7$F$$$kItJ,$,$b$7$"$l$P!"F1$8$h$&(B
|$B$JLdBj$,H/@8$7$=$&$G$9$M!#(B

$B$J$k$[$I!#(B

|$BBP1~$H$7$F$O(Barg->data$B$r(BHash$B$K$9$k$H$+$G$7$g$&$+!#(B

$B$G$O!"$=$N@~$G9T$-$^$7$g$&$+!#Ht9T5!$NCf$G%Q%C%A:n$k2K$,$"$k(B
$B$+$J(B($B$J$5$=$&(B)$B!#(B
Posted by Nobuyoshi Nakada (nobu)
on 02.09.2008 07:12
(Received via mailing list)
$B$J$+$@$G$9!#(B

At Tue, 2 Sep 2008 00:41:51 +0900,
Shugo Maeda wrote in [ruby-dev:36086]:
> dump$BCf$K(BGC$B$,H/@8$9$k$H!"0l;~E*$K@8@.$7$?(BBignum$B%*%V%8%'%/%H$N%"%I%l%9$,(B
> $B$?$^$?$^F1$8$K$J$C$F$7$^$&$?$a!"(Barg->data$B$N8!:w;~$K8m$C$F0JA0$N%*%V%8%'%/%H(B
> $B$K%R%C%H$7$F%j%s%/$H$7$F=hM}$5$l$F$7$^$&$h$&$G$9!#(B
> $BB>$K$b(Bdump$BCf$K0l;~E*$K%*%V%8%'%/%H$r@8@.$7$F$$$kItJ,$,$b$7$"$l$P!"F1$8$h$&(B
> $B$JLdBj$,H/@8$7$=$&$G$9$M!#(B
> 
> $BBP1~$H$7$F$O(Barg->data$B$r(BHash$B$K$9$k$H$+$G$7$g$&$+!#(B

$B$=$l$G$O2r7h$7$^$;$s$G$7$?!#(B

hash$B$d(Beql?$B$N:FDj5A$N1F6A$rHr$1$k$?$a$K$O!"(Barg->data$B$N%-!<$r(B
VALUE$B$NCM<+BN(B(INT2FIX(obj)$B$J$I(B)$B$K$7$J$/$F$O$J$j$^$;$s$,!"$=$&$9(B
$B$k$H%^!<%/$NBP>]$G$O$J$/$J$C$F$7$^$$$^$9!#(B

$B6qBNE*$K$O!"(Btest/ruby/marshaltest.rb:test_range_cyclic$B$HN>N)$5$;(B
$B$k$3$H$OIT2DG=$G$9!#(B

$B$b$7$+$7$?$i!"(B[ruby-dev:34312]$B$b$3$l$,860x$+$bCN$l$^$;$s$M$'!#(B

# marshal.c$B$G$O(B r16761 
$B$b%P%C%/%]!<%H$7$?$[$&$,$$$$$H;W$$$^$9!#(B


* gc.c (rb_mark_set): new function to mark keys.

* marshal.c (struct dump_arg, struct load_arg): added wrappers to mark
  data entries.  backport from trunk r13527,r13528,r13961,r16533.
  [ruby-dev:36082]


Index: intern.h
===================================================================
--- intern.h  (revision 19063)
+++ intern.h  (working copy)
@@ -258,4 +258,5 @@ char *rb_source_filename _((const char*)
 void rb_gc_mark_locations _((VALUE*, VALUE*));
 void rb_mark_tbl _((struct st_table*));
+void rb_mark_set _((struct st_table*));
 void rb_mark_hash _((struct st_table*));
 void rb_gc_mark_maybe _((VALUE));
Index: gc.c
===================================================================
--- gc.c  (revision 19063)
+++ gc.c  (working copy)
@@ -735,4 +735,29 @@ rb_mark_tbl(tbl)

 static int
+mark_key(key, value, lev)
+    VALUE key, value;
+    int lev;
+{
+    gc_mark(key, lev);
+    return ST_CONTINUE;
+}
+
+static void
+mark_set(tbl, lev)
+    st_table *tbl;
+    int lev;
+{
+    if (!tbl) return;
+    st_foreach(tbl, mark_key, lev);
+}
+
+void
+rb_mark_set(tbl)
+    st_table *tbl;
+{
+    mark_set(tbl, 0);
+}
+
+static int
 mark_keyvalue(key, value, lev)
     VALUE key;
Index: marshal.c
===================================================================
--- marshal.c  (revision 19063)
+++ marshal.c  (working copy)
@@ -85,14 +85,4 @@ static ID s_dump_data, s_load_data, s_al
 static ID s_getc, s_read, s_write, s_binmode;

-static void
-reentrant_check(obj, sym)
-    VALUE obj;
-    ID sym;
-{
-    if (obj && RBASIC(obj)->klass) {
-        rb_raise(rb_eRuntimeError, "%s reentered", rb_id2name(sym));
-    }
-}
-
 struct dump_arg {
     VALUE obj;
@@ -101,4 +91,5 @@ struct dump_arg {
     st_table *data;
     int taint;
+    VALUE wrapper;
 };

@@ -109,4 +100,25 @@ struct dump_call_arg {
 };

+static void
+check_dump_arg(arg, sym)
+    struct dump_arg *arg;
+    ID sym;
+{
+    if (!DATA_PTR(arg->wrapper)) {
+        rb_raise(rb_eRuntimeError, "Marshal.dump reentered at %s",
+     rb_id2name(sym));
+    }
+}
+
+static void
+mark_dump_arg(ptr)
+    void *ptr;
+{
+    struct dump_arg *p = ptr;
+    if (!ptr)
+        return;
+    rb_mark_set(p->data);
+}
+
 static VALUE
 class2path(klass)
@@ -516,5 +528,5 @@ w_object(obj, arg, limit)

       v = rb_funcall(obj, s_mdump, 0, 0);
-      reentrant_check(arg->str, s_mdump);
+      check_dump_arg(arg, s_mdump);
       w_class(TYPE_USRMARSHAL, obj, arg, Qfalse);
       w_object(v, arg, limit);
@@ -526,5 +538,5 @@ w_object(obj, arg, limit)

       v = rb_funcall(obj, s_dump, 1, INT2NUM(limit));
-      reentrant_check(arg->str, s_dump);
+      check_dump_arg(arg, s_dump);
       if (TYPE(v) != T_STRING) {
     rb_raise(rb_eTypeError, "_dump() must return string");
@@ -671,5 +683,5 @@ w_object(obj, arg, limit)
     }
     v = rb_funcall(obj, s_dump_data, 0);
-    reentrant_check(arg->str, s_dump_data);
+    check_dump_arg(arg, s_dump_data);
     w_class(TYPE_DATA, obj, arg, Qtrue);
     w_object(v, arg, limit);
@@ -704,7 +716,9 @@ dump_ensure(arg)
     struct dump_arg *arg;
 {
-    if (RBASIC(arg->str)->klass) return 0; /* ignore reentrant */
+    if (!DATA_PTR(arg->wrapper)) return 0;
     st_free_table(arg->symbols);
     st_free_table(arg->data);
+    DATA_PTR(arg->wrapper) = 0;
+    arg->wrapper = 0;
     if (arg->taint) {
   OBJ_TAINT(arg->str);
@@ -773,5 +787,5 @@ marshal_dump(argc, argv)
   if (rb_respond_to(port, s_binmode)) {
       rb_funcall2(port, s_binmode, 0, 0);
-      reentrant_check(arg.str, s_dump_data);
+      check_dump_arg(&arg, s_dump_data);
   }
     }
@@ -783,4 +797,5 @@ marshal_dump(argc, argv)
     arg.data    = st_init_numtable();
     arg.taint   = Qfalse;
+    arg.wrapper = Data_Wrap_Struct(rb_cData, mark_dump_arg, 0, &arg);
     c_arg.obj   = obj;
     c_arg.arg   = &arg;
@@ -800,9 +815,31 @@ struct load_arg {
     long offset;
     st_table *symbols;
-    VALUE data;
+    st_table *data;
     VALUE proc;
     int taint;
+    VALUE wrapper;
 };

+static void
+check_load_arg(arg, sym)
+    struct load_arg *arg;
+    ID sym;
+{
+    if (!DATA_PTR(arg->wrapper)) {
+        rb_raise(rb_eRuntimeError, "Marshal.load reentered at %s",
+     rb_id2name(sym));
+    }
+}
+
+static void
+mark_load_arg(ptr)
+    void *ptr;
+{
+    struct load_arg *p = ptr;
+    if (!ptr)
+        return;
+    rb_mark_tbl(p->data);
+}
+
 static VALUE r_object _((struct load_arg *arg));

@@ -824,5 +861,5 @@ r_byte(arg)
   VALUE src = arg->src;
   VALUE v = rb_funcall2(src, s_getc, 0, 0);
-  reentrant_check(arg->data, s_getc);
+  check_load_arg(arg, s_getc);
   if (NIL_P(v)) rb_eof_error();
   c = (unsigned char)FIX2INT(v);
@@ -905,5 +942,5 @@ r_bytes0(len, arg)
   VALUE n = LONG2NUM(len);
   str = rb_funcall2(src, s_read, 1, &n);
-  reentrant_check(arg->data, s_read);
+  check_load_arg(arg, s_read);
   if (NIL_P(str)) goto too_short;
   StringValue(str);
@@ -968,5 +1005,5 @@ r_entry(v, arg)
     struct load_arg *arg;
 {
-    rb_hash_aset(arg->data, 
INT2FIX(RHASH(arg->data)->tbl->num_entries), v);
+    st_insert(arg->data, arg->data->num_entries, (st_data_t)v);
     if (arg->taint) OBJ_TAINT(v);
     return v;
@@ -1024,12 +1061,13 @@ r_object0(arg, proc, ivp, extmod)
     int type = r_byte(arg);
     long id;
+    st_data_t link;

     switch (type) {
       case TYPE_LINK:
   id = r_long(arg);
-  v = rb_hash_aref(arg->data, LONG2FIX(id));
-  if (NIL_P(v)) {
+   if (!st_lookup(arg->data, (st_data_t)id, &link)) {
       rb_raise(rb_eArgError, "dump format error (unlinked)");
   }
+  v = (st_data_t)link;
   return v;

@@ -1256,5 +1294,5 @@ r_object0(arg, proc, ivp, extmod)
       }
       v = rb_funcall(klass, s_load, 1, data);
-      reentrant_check(arg->data, s_load);
+      check_load_arg(arg, s_load);
       r_entry(v, arg);
   }
@@ -1280,5 +1318,5 @@ r_object0(arg, proc, ivp, extmod)
       data = r_object(arg);
       rb_funcall(v, s_mload, 1, data);
-      reentrant_check(arg->data, s_mload);
+      check_load_arg(arg, s_mload);
   }
         break;
@@ -1307,5 +1345,5 @@ r_object0(arg, proc, ivp, extmod)
          }
          v = rb_funcall(klass, s_alloc, 0);
-         reentrant_check(arg->data, s_alloc);
+         check_load_arg(arg, s_alloc);
            }
      else {
@@ -1322,5 +1360,5 @@ r_object0(arg, proc, ivp, extmod)
            }
            rb_funcall(v, s_load_data, 1, r_object0(arg, 0, 0, extmod));
-     reentrant_check(arg->data, s_load_data);
+     check_load_arg(arg, s_load_data);
        }
        break;
@@ -1366,5 +1404,5 @@ r_object0(arg, proc, ivp, extmod)
     if (proc) {
   rb_funcall(proc, s_call, 1, v);
-  reentrant_check(arg->data, s_call);
+  check_load_arg(arg, s_call);
     }
     return v;
@@ -1389,6 +1427,9 @@ load_ensure(arg)
     struct load_arg *arg;
 {
-    if (RBASIC(arg->data)->klass) return 0; /* ignore reentrant */
+    if (!DATA_PTR(arg->wrapper)) return 0;
     st_free_table(arg->symbols);
+    st_free_table(arg->data);
+    DATA_PTR(arg->wrapper) = 0;
+    arg->wrapper = 0;
     return 0;
 }
@@ -1432,5 +1473,8 @@ marshal_load(argc, argv)
     arg.src = port;
     arg.offset = 0;
-    arg.data = 0;
+    arg.symbols = st_init_numtable();
+    arg.data    = st_init_numtable();
+    arg.proc = 0;
+    arg.wrapper = Data_Wrap_Struct(rb_cData, mark_load_arg, 0, &arg);

     major = r_byte(&arg);
@@ -1447,9 +1491,5 @@ marshal_load(argc, argv)
     }

-    arg.symbols = st_init_numtable();
-    arg.data   = rb_hash_new();
-    RBASIC(arg.data)->klass = 0;
-    if (NIL_P(proc)) arg.proc = 0;
-    else             arg.proc = proc;
+    if (!NIL_P(proc)) arg.proc = proc;
     v = rb_ensure(load, (VALUE)&arg, load_ensure, (VALUE)&arg);
     RBASIC(arg.data)->klass = rb_cHash;
Index: test/ruby/test_marshal.rb
===================================================================
--- test/ruby/test_marshal.rb  (revision 19063)
+++ test/ruby/test_marshal.rb  (working copy)
@@ -13,9 +13,15 @@ class TestMarshal < Test::Unit::TestCase

   def encode(o)
+    stress, GC.stress = GC.stress, true
     Marshal.dump(o)
+  ensure
+    GC.stress = stress
   end

   def decode(s)
+    stress, GC.stress = GC.stress, true
     Marshal.load(s)
+  ensure
+    GC.stress = stress
   end

Index: test/ruby/marshaltestlib.rb
===================================================================
--- test/ruby/marshaltestlib.rb  (revision 19063)
+++ test/ruby/marshaltestlib.rb  (working copy)
@@ -194,4 +194,10 @@ module MarshalTestLib
   end

+  def test_fixnum_64bit
+    obj = [1220278665, 1220278662, 1220278661, 1220278661, 1220278656]
+
+    marshal_equal(obj)
+  end
+
   def test_float
     marshal_equal(-1.0)
Posted by Shugo Maeda (Guest)
on 02.09.2008 09:18
(Received via mailing list)
$BA0ED$G$9!#(B

2008/09/02 14:06 Nobuyoshi Nakada <nobu@ruby-lang.org>:
> $B$=$l$G$O2r7h$7$^$;$s$G$7$?!#(B
>
> hash$B$d(Beql?$B$N:FDj5A$N1F6A$rHr$1$k$?$a$K$O!"(Barg->data$B$N%-!<$r(B
> VALUE$B$NCM<+BN(B(INT2FIX(obj)$B$J$I(B)$B$K$7$J$/$F$O$J$j$^$;$s$,!"$=$&$9(B
> $B$k$H%^!<%/$NBP>]$G$O$J$/$J$C$F$7$^$$$^$9!#(B

$B%-!<$G$O$J$/$FCM$NJ}$r(Brb_assoc_new($BHV9f(B, 
$B%*%V%8%'%/%H(B)$B$N$h$&$J7A$K$9$k(B
$B$3$H$r9M$($F$^$7$?!#$A$g$C$HL5BL$G$9$,!#(B

> * gc.c (rb_mark_set): new function to mark keys.
>
> * marshal.c (struct dump_arg, struct load_arg): added wrappers to mark
>  data entries.  backport from trunk r13527,r13528,r13961,r16533.
>  [ruby-dev:36082]

$B$A$g$&$I:#D+$N0\F0Cf$K(Btrunk$B$G$O(BT_DATA$B$G(Bwrap$B$7$F%^!<%/$7$F$k$3$H$K5$IU$$$?$N(B
$B$G$9$,!"$3$NJ}?K$,$h$5$=$&$G$9$M!#(B

$B$"$H!"3:Ev2U=j$G:n$C$F$$$k(BBignum$B%*%V%8%'%/%H$OL@$i$+$K8e$G;H$o$l$k$3$H$O$J$$(B
$B$N$G!"(Bw_object()$B$K(Barg->data$B$N8!:w!&DI2C$r$d$a$k%*%W%7%g%s$,$"$C$F$b$$$$$+$b(B
$B$7$l$J$$$H;W$$$^$7$?!#(B
$B:#2s$_$?$$$JFC<l$J%1!<%9(B($BHyL/$J%5%$%:$N(BFixnum$B$r$?$/$5$s(Bdump$B$9$k(B)$B$G$J$$$H(B
$B0UL#$,$J$$$+$b$7$l$^$;$s$,!#(B
Posted by Kouichi Ushijima (Guest)
on 02.09.2008 15:09
(Received via mailing list)
$B5mEg$G$9!#(B

> * gc.c (rb_mark_set): new function to mark keys.
> 
> * marshal.c (struct dump_arg, struct load_arg): added wrappers to mark
>   data entries.  backport from trunk r13527,r13528,r13961,r16533.
>   [ruby-dev:36082]

$B$"$j$,$H$&$4$6$$$^$9!#2r7h$5$l$F$$$k$3$H$r3NG'$7$^$7$?!#(B