x86_64$B4D6-$G(BMarshal.dump$B$NIT6q9g(B

NTTe$B%l%>%J%s%H$N5mEg$H?=$7$^$9!#e(B

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

e$B:F8=%3!<%I$r0J2<$K<($7$^$9!#K\MhEy$7$$$O$:$Ne(Bobje$B$He(Bobj1e$B$,Ey$7$/$J$$$HH=Dje(B
e$B$5$l$F$7$^$$$^$9!#e(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!


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

e$BAG?M9M$($G$9$,!"e(Bmarshal.ce$B$Ne(Bw_object()e$B$Ne(BFIXNUMe$B$Ne(Bdumpe$B=hM}$G!"0l;~E*$K@[email protected](B
e$B$5$l$?e(BBignume$B%*%V%8%’%/%H$,e(BMarshal.dumpe$BCf$K2rJ|$5$l$F$7$^$&$N$,LdBj$N$h$&e(B
e$B$J5$$,$7$^$9!#e(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

e$B3NG’$7$?4D6-$O0J2<$NDL$j$G$9!#e(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]

e$B0J>e!"$h$m$7$/$*4j$$$7$^$9!#e(B

e$BA0ED$G$9!#e(B

2008/09/01 21:56 Kouichi U. [email protected]:

==> false!


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

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

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

e$B$I$&$d$ie(Bmarshal.ce$B$Ne(Bw_object()e$B$N0J2<$Ne(Bife$BJ8$N>r7o$,??$K$J$C$F$$$k$h$&$J$N$G$9$,!"e(B

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

dumpe$BCf$Ke(BGCe$B$,H/@8$9$k$H!“0l;~E*$K@8@.$7$?e(BBignume$B%%V%8%'%/%H$N%"%I%l%9$,e(B
e$B$?$^$?$^F1$8$K$J$C$F$7$^$&$?$a!"e(Barg->datae$B$N8!:w;~$K8m$C$F0JA0$N%
%V%8%‘%/%He(B
e$B$K%R%C%H$7$F%j%s%/$H$7$F=hM}$5$l$F$7$^$&$h$&$G$9!#e(B
e$BB>$K$be(Bdumpe$BCf$K0l;~E*$K%*%V%8%’%/%H$r@8@.$7$F$$$kItJ,$,$b$7$”$l$P!"F1$8$h$&e(B
e$B$JLdBj$,H/@8$7$=$&$G$9$M!#e(B

e$BBP1~$H$7$F$Oe(Barg->datae$B$re(BHashe$B$K$9$k$H$+$G$7$g$&$+!#e(B

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:36086] Re:
x86_64e$B4D6-$Ge(BMarshal.dumpe$B$NIT6q9ge(B”
on Tue, 2 Sep 2008 00:41:51 +0900, “Shugo M.”
[email protected] writes:

|e$B$I$&$d$ie(Bmarshal.ce$B$Ne(Bw_object()e$B$N0J2<$Ne(Bife$BJ8$N>r7o$,??$K$J$C$F$$$k$h$&$J$N$G$9$,!"e(B
|
| if (st_lookup(arg->data, obj, &num)) {
| w_byte(TYPE_LINK, arg);
| w_long((long)num, arg);
| return;
| }
|
|dumpe$BCf$Ke(BGCe$B$,H/@8$9$k$H!“0l;~E*$K@8@.$7$?e(BBignume$B%%V%8%'%/%H$N%"%I%l%9$,e(B
|e$B$?$^$?$^F1$8$K$J$C$F$7$^$&$?$a!"e(Barg->datae$B$N8!:w;~$K8m$C$F0JA0$N%
%V%8%‘%/%He(B
|e$B$K%R%C%H$7$F%j%s%/$H$7$F=hM}$5$l$F$7$^$&$h$&$G$9!#e(B
|e$BB>$K$be(Bdumpe$BCf$K0l;~E*$K%*%V%8%’%/%H$r@8@.$7$F$$$kItJ,$,$b$7$”$l$P!"F1$8$h$&e(B
|e$B$JLdBj$,H/@8$7$=$&$G$9$M!#e(B

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

|e$BBP1~$H$7$F$Oe(Barg->datae$B$re(BHashe$B$K$9$k$H$+$G$7$g$&$+!#e(B

e$B$G$O!“$=$N@~$G9T$-$^$7$g$&$+!#Ht9T5!$NCf$G%Q%C%A:n$k2K$,$”$ke(B
e$B$+$Je(B(e$B$J$5$=$&e(B)e$B!#e(B

e$BA0ED$G$9!#e(B

2008/09/02 14:06 Nobuyoshi N. [email protected]:

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

hashe$B$de(Beql?e$B$N:FDj5A$N1F6A$rHr$1$k$?$a$K$O!“e(Barg->datae$B$N%-!<$re(B
VALUEe$B$NCM<+BNe(B(INT2FIX(obj)e$B$J$Ie(B)e$B$K$7$J$/$F$O$J$j$^$;$s$,!”$=$&$9e(B
e$B$k$H%^!<%/$NBP>]$G$O$J$/$J$C$F$7$^$$$^$9!#e(B

e$B%-!<$G$O$J$/$FCM$NJ}$re(Brb_assoc_new(e$BHV9fe(B,
e$B%*%V%8%'%/%He(B)e$B$N$h$&$J7A$K$9$ke(B
e$B$3$H$r9M$($F$^$7$?!#$A$g$C$HL5BL$G$9$,!#e(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]

e$B$A$g$&$I:#D+$N0\F0Cf$Ke(Btrunke$B$G$Oe(BT_DATAe$B$Ge(Bwrape$B$7$F%^!<%/$7$F$k$3$H$K5$IU$$$?$Ne(B
e$B$G$9$,!"$3$NJ}?K$,$h$5$=$&$G$9$M!#e(B

e$B$"$H!“3:Ev2U=j$G:n$C$F$$$ke(BBignume$B%%V%8%'%/%H$OL@$i$+$K8e$G;H$o$l$k$3$H$O$J$$e(B
e$B$N$G!"e(Bw_object()e$B$Ke(Barg->datae$B$N8!:w!&DI2C$r$d$a$k%
%W%7%g%s$,$”$C$F$b$$$$$+$be(B
e$B$7$l$J$$$H;W$$$^$7$?!#e(B
e$B:#2s$_$?$$$JFC<l$J%1!<%9e(B(e$BHyL/$J%5%$%:$Ne(BFixnume$B$r$?$/$5$se(Bdumpe$B$9$ke(B)e$B$G$J$$$He(B
e$B0UL#$,$J$$$+$b$7$l$^$;$s$,!#e(B

e$B5mEg$G$9!#e(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]

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

e$B$J$+$@$G$9!#e(B

At Tue, 2 Sep 2008 00:41:51 +0900,
Shugo M. wrote in [ruby-dev:36086]:

dumpe$BCf$Ke(BGCe$B$,H/@8$9$k$H!“0l;~E*$K@8@.$7$?e(BBignume$B%%V%8%’%/%H$N%"%I%l%9$,e(B
e$B$?$^$?$^F1$8$K$J$C$F$7$^$&$?$a!"e(Barg->datae$B$N8!:w;~$K8m$C$F0JA0$N%
%V%8%’%/%He(B
e$B$K%R%C%H$7$F%j%s%/$H$7$F=hM}$5$l$F$7$^$&$h$&$G$9!#e(B
e$BB>$K$be(Bdumpe$BCf$K0l;~E*$K%*%V%8%’%/%H$r@8@.$7$F$$$kItJ,$,$b$7$”$l$P!"F1$8$h$&e(B
e$B$JLdBj$,H/@8$7$=$&$G$9$M!#e(B

e$BBP1~$H$7$F$Oe(Barg->datae$B$re(BHashe$B$K$9$k$H$+$G$7$g$&$+!#e(B

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

hashe$B$de(Beql?e$B$N:FDj5A$N1F6A$rHr$1$k$?$a$K$O!“e(Barg->datae$B$N%-!<$re(B
VALUEe$B$NCM<+BNe(B(INT2FIX(obj)e$B$J$Ie(B)e$B$K$7$J$/$F$O$J$j$^$;$s$,!”$=$&$9e(B
e$B$k$H%^!<%/$NBP>]$G$O$J$/$J$C$F$7$^$$$^$9!#e(B

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

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

marshal.ce$B$G$Oe(B r16761

e$B$b%P%C%/%]!<%H$7$?$[$&$,$$$$$H;W$$$^$9!#e(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)