From: "RubyMine.Org" Date: 2001-08-12T22:38:51+09:00 Subject: [ruby-talk:19602] Overriding Marshal.load version test Evolving Marshal versions have given me headaches, and today I found out from IRC that "I'm not the only". So I wrote this small modification which should be backwards compatible (in a sense older programs should continue to work, assuming people haven't overwritten their Marshal.load). I'd like to see discussion whether this patch should be incorporated. - Aleksi The method signature changes a bit, first old, and then newer: [aleksi@dogma ruby-1.6.4]$ ri Marshal.load ---------------------------------------------------------- Marshal::load load( from [, aProc] ) -> anObject ------------------------------------------------------------------------ Returns the result of converting the serialized data in from into a Ruby object (possibly with associated subordinate objects). from may be either an instance of IO or an object that responds to to_str. If proc is specified, it will be passed each object as it is deserialized. [aleksi@dogma ruby-2001-08-12]$ ri Marshal.load ---------------------------------------------------------- Marshal::load load( from [, aProc [, override]] ) -> anObject ------------------------------------------------------------------------ Returns the result of converting the serialized data in from into a Ruby object (possibly with associated subordinate objects). from may be either an instance of IO or an object that responds to to_str. If proc is specified, it will be passed each object as it is deserialized. If override is given with non-false value the test whether loader version is compatible with marshaller which produced from is skipped. Warning: skipping the test might crash the entire interpreter. An example: [aleksi@dogma ruby-2001-08-12]$ ./ruby -ve 'File.open("data.dat","wb") do |f| Marshal.dump("foo", f); end;' ruby 1.7.1 (2001-08-06) [i686-linux] [aleksi@dogma ruby-2001-08-12]$ cat data.dat foo [aleksi@dogma ruby-2001-08-12]$ ../ruby-1.6.4/ruby -ve 'File.open("data.dat") |f| p Marshal.load(f); end;' ruby 1.6.4 (2001-06-04) [i686-linux] -e:1:in `load': incompatible marshal file format (can't be read) (TypeError) format version 4.5 required; 4.6 given from -e:1 from -e:1:in `open' from -e:1 [aleksi@dogma ruby-2001-08-12]$ ../ruby-1.6.4/ruby -ve 'File.open("data.dat") do |f| p Marshal.load(f,nil,true); end;' ruby 1.6.4 (2001-06-04) [i686-linux] "foo" The patch (beware of too long lines): [aleksi@dogma ruby-2001-08-12]$ diff -u orig/ruby/marshal.c marshal.c --- orig/ruby/marshal.c Tue Jul 31 11:33:17 2001 +++ marshal.c Sun Aug 12 15:10:47 2001 @@ -1038,14 +1038,16 @@ int argc; VALUE *argv; { - VALUE port, proc; + VALUE port, proc, override; int major, minor; VALUE v; OpenFile *fptr; struct load_arg arg; volatile VALUE hash; /* protect from GC */ - rb_scan_args(argc, argv, "11", &port, &proc); + if ( rb_scan_args(argc, argv, "12", &port, &proc, &override) < 3){ + override = Qfalse; + } if (rb_obj_is_kind_of(port, rb_cIO)) { rb_io_binmode(port); GetOpenFile(port, fptr); @@ -1066,15 +1068,17 @@ major = r_byte(&arg); minor = r_byte(&arg); - if (major != MARSHAL_MAJOR || minor > MARSHAL_MINOR) { + if ( RTEST(override) ){ + if (major != MARSHAL_MAJOR || minor > MARSHAL_MINOR) { rb_raise(rb_eTypeError, "incompatible marshal file format (can't be read)\n\ \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); - } - if (RTEST(ruby_verbose) && minor != MARSHAL_MINOR) { + } + if (RTEST(ruby_verbose) && minor != MARSHAL_MINOR) { rb_warn("incompatible marshal file format (can be read)\n\ \tformat version %d.%d required; %d.%d given", MARSHAL_MAJOR, MARSHAL_MINOR, major, minor); + } } arg.symbol = st_init_numtable();