# By default restricted hashes are downgraded on earlier perls.
$Storable::downgrade_restricted = 1;
+$Storable::accept_future_minor = 1;
bootstrap Storable;
1;
__END__
Storable C<croak()> instead, set C<$Storable::downgrade_restricted> to
a false value. To restore the default set it back to some C<TRUE> value.
+=item files from future versions of Storable
+
+Earlier versions of Storable would immediately croak if they encountered
+a file with a higher internal version number than the reading Storable
+knew about. Internal version numbers are increased each time new data
+types (such as restricted hashes) are added to the vocabulary of the file
+format. This meant that a newer Storable module had no way of writing a
+file readable by an older Storable, even if writer didn't store newer
+data types.
+
+This version of Storable will defer croaking until it encounters a data
+type in the file that it does not recognize. This means that it will
+continue to read files generated by newer Storable modules which are careful
+in what they write out, making it easier to upgrade Storable modules in a
+mixed environment.
+
+The old behaviour of immediate croaking can be re-instated by setting
+C<$Storable::accept_future_minor> to false.
+
=back
Both these variables have no effect on a newer Perl which supports the
#include <XSUB.h>
#ifndef NETWARE
-#if 1
+#if 0
#define DEBUGME /* Debug mode, turns assertions on as well */
#define DASSERT /* Assertion mode */
#endif
#ifndef HAS_UTF8_ALL
int use_bytes; /* whether to bytes-ify utf8 */
#endif
+ int accept_future_minor; /* croak immediately on future minor versions? */
int s_dirty; /* context is dirty due to CROAK() -- can be cleaned */
int membuf_ro; /* true means membuf is read-only and msaved is rw */
struct extendable keybuf; /* for hash key retrieval */
sv_free((SV *) hook_seen);
}
+ cxt->forgive_me = -1; /* Fetched from perl if needed */
+ cxt->canonical = -1; /* Idem */
+
reset_context(cxt);
}
#ifndef HAS_UTF8_ALL
cxt->use_bytes = -1; /* Fetched from perl if needed */
#endif
+ cxt->accept_future_minor = -1; /* Fetched from perl if needed */
}
/*
sv_free((SV *) hseen); /* optional HV, for backward compat. */
}
+#ifndef HAS_RESTRICTED_HASHES
+ cxt->derestrict = -1; /* Fetched from perl if needed */
+#endif
+#ifndef HAS_UTF8_ALL
+ cxt->use_bytes = -1; /* Fetched from perl if needed */
+#endif
+ cxt->accept_future_minor = -1; /* Fetched from perl if needed */
+
reset_context(cxt);
}
(version_major == STORABLE_BIN_MAJOR &&
version_minor > STORABLE_BIN_MINOR)
) {
- TRACEME(("but I am version is %d.%d", STORABLE_BIN_MAJOR,
- STORABLE_BIN_MINOR));
-
+ int croak_now = 1;
+ TRACEME(("but I am version is %d.%d", STORABLE_BIN_MAJOR,
+ STORABLE_BIN_MINOR));
+
+ if (version_major == STORABLE_BIN_MAJOR) {
+ TRACEME(("cxt->accept_future_minor is %d",
+ cxt->accept_future_minor));
+ if (cxt->accept_future_minor < 0)
+ cxt->accept_future_minor
+ = (SvTRUE(perl_get_sv("Storable::accept_future_minor",
+ TRUE))
+ ? 1 : 0);
+ if (cxt->accept_future_minor == 1)
+ croak_now = 0; /* Don't croak yet. */
+ }
+ if (croak_now) {
CROAK(("Storable binary image v%d.%d more recent than I am (v%d.%d)",
- version_major, version_minor,
- STORABLE_BIN_MAJOR, STORABLE_BIN_MINOR));
+ version_major, version_minor,
+ STORABLE_BIN_MAJOR, STORABLE_BIN_MINOR));
+ }
}
/*
TRACEME(("had retrieved #%d at 0x%"UVxf, tag, PTR2UV(sv)));
SvREFCNT_inc(sv); /* One more reference to this same sv */
return sv; /* The SV pointer where object was retrieved */
- }
+ } else if (type >= SX_ERROR && cxt->ver_minor > STORABLE_BIN_MINOR) {
+ if (cxt->accept_future_minor < 0)
+ cxt->accept_future_minor
+ = (SvTRUE(perl_get_sv("Storable::accept_future_minor",
+ TRUE))
+ ? 1 : 0);
+ if (cxt->accept_future_minor == 1) {
+ CROAK(("Storable binary image v%d.%d contains data of type %d. "
+ "This Storable is v%d.%d and can only handle data types up to %d",
+ cxt->ver_major, cxt->ver_minor, type,
+ STORABLE_BIN_MAJOR, STORABLE_BIN_MINOR, SX_ERROR - 1));
+ }
+ }
first_time: /* Will disappear when support for old format is dropped */
# for network order, and 2 tests per byte on the 'pst0' "magic number" only
# present in files, but not in things store()ed to memory
$fancy = ($] > 5.007 ? 2 : 0);
- plan tests => 334 + length($Config{byteorder}) * 4 + $fancy * 8;
+ plan tests => 378 + length($Config{byteorder}) * 4 + $fancy * 8;
}
use Storable qw (store retrieve freeze thaw nstore nfreeze);
# )
my $minor4 = $header->{minor} + 4;
substr ($copy, $file_magic + 1, 1) = chr $minor4;
- test_corrupt ($copy, $sub,
- "/^Storable binary image v$header->{major}\.$minor4 more recent than I am \\(v$header->{major}\.$minor\\)/",
- "higher minor");
+ {
+ # Now by default newer minor version numbers are not a pain.
+ $clone = &$sub($copy);
+ ok ($@, "", "by default no error on higher minor");
+ test_hash ($clone);
+
+ local $Storable::accept_future_minor = 0;
+ test_corrupt ($copy, $sub,
+ "/^Storable binary image v$header->{major}\.$minor4 more recent than I am \\(v$header->{major}\.$minor\\)/",
+ "higher minor");
+ }
$copy = $contents;
my $major1 = $header->{major} + 1;
test_corrupt ($copy, $sub,
"/^Corrupted storable $what \\(binary v$header->{major}.$header->{minor}\\)/",
"bogus tag");
+
+ # Now drop the minor version number
+ substr ($copy, $file_magic + 1, 1) = chr $minor1;
+
+ test_corrupt ($copy, $sub,
+ "/^Corrupted storable $what \\(binary v$header->{major}.$minor1\\)/",
+ "bogus tag, minor less 1");
+ # Now increase the minor version number
+ substr ($copy, $file_magic + 1, 1) = chr $minor4;
+
+ # local $Storable::DEBUGME = 1;
+ # This is the delayed croak
+ test_corrupt ($copy, $sub,
+ "/^Storable binary image v$header->{major}.$minor4 contains data of type 255. This Storable is v$header->{major}.$header->{minor} and can only handle data types up to 25/",
+ "bogus tag, minor plus 4");
+ # And check again that this croak is not delayed:
+ {
+ # local $Storable::DEBUGME = 1;
+ local $Storable::accept_future_minor = 0;
+ test_corrupt ($copy, $sub,
+ "/^Storable binary image v$header->{major}\.$minor4 more recent than I am \\(v$header->{major}\.$minor\\)/",
+ "higher minor");
+ }
}
sub slurp {