Subject: | Make the module not truncate large integers on perls with 32-bit ints |
Currently, if the stream is fed a large integer (or a large uint), the module silently truncates the integer to fit in 32 bits (of course, this only happens on perls with 32-bit integeres).
Of many ways of solving this issue, the current behavior is probably the worst.
The attached patch creates a Math::BigInt object in such instances. I am not sure that this is the best possible solution, but it certainly better than the current behavior.
This only affects the unpacker.
I hope you can find time to make a new release incorporating the fix. If you do not have time, but in principle do not object to the fix, I'd like to offer to become a co-maintainer of the module so that the release can be made.
Thanks,
\Anton.
Subject: | dms.patch |
diff -ruN ../Data-MessagePack-Stream-0.07/lib/Data/MessagePack/Stream.pm ./lib/Data/MessagePack/Stream.pm
--- lib/Data/MessagePack/Stream.pm 2012-07-25 03:22:13.000000000 +0200
+++ lib/Data/MessagePack/Stream.pm 2014-08-13 15:43:35.000000000 +0200
@@ -2,6 +2,7 @@
use strict;
use warnings;
use XSLoader;
+use Math::BigInt;
our $VERSION = '0.07';
diff -ruN ../Data-MessagePack-Stream-0.07/src/Data-MessagePack-Stream.xs ./src/Data-MessagePack-Stream.xs
--- src/Data-MessagePack-Stream.xs 2012-07-25 03:14:01.000000000 +0200
+++ src/Data-MessagePack-Stream.xs 2014-08-18 12:48:30.000000000 +0200
@@ -16,6 +16,21 @@
msgpack_unpacked result;
};
+static SV* bigint_object_from_string(const char *s)
+{
+ dSP;
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv("Math::BigInt", 0)));
+ XPUSHs(sv_2mortal(newSVpv(s, 0)));
+ PUTBACK;
+
+ call_method("new", G_SCALAR);
+
+ SPAGAIN;
+ return SvREFCNT_inc(POPs);
+}
+
static SV* decode_msgpack_object(msgpack_object* obj) {
SV* res = NULL;
AV* av;
@@ -33,10 +48,24 @@
res = newSViv(obj->via.boolean);
break;
case MSGPACK_OBJECT_POSITIVE_INTEGER:
- res = newSVuv(obj->via.u64);
+ if (sizeof(UV) < 8 && obj->via.u64 > 4294967295ull) {
+ char s[40];
+
+ snprintf(s, 40, "%"PRIu64, obj->via.u64);
+ res = bigint_object_from_string(s);
+ } else {
+ res = newSVuv(obj->via.u64);
+ }
break;
case MSGPACK_OBJECT_NEGATIVE_INTEGER:
- res = newSViv(obj->via.i64);
+ if (sizeof(IV) < 8 && (obj->via.i64 > 2147483647ll || obj->via.i64 < -2147483648ll)) {
+ char s[40];
+
+ snprintf(s, 40, "%"PRId64, obj->via.i64);
+ res = bigint_object_from_string(s);
+ } else {
+ res = newSViv(obj->via.i64);
+ }
break;
case MSGPACK_OBJECT_DOUBLE:
res = newSVnv(obj->via.dec);
diff -ruN ../Data-MessagePack-Stream-0.07/t/bug-bigint.t ./t/bug-bigint.t
--- t/bug-bigint.t 1970-01-01 01:00:00.000000000 +0100
+++ t/bug-bigint.t 2014-08-18 12:48:40.000000000 +0200
@@ -0,0 +1,18 @@
+use Test::More;
+
+plan tests => 2;
+use Data::MessagePack::Stream;
+
+my $stream = Data::MessagePack::Stream->new;
+$stream->feed("\xCF\x00\x01\x56\x7C\xC1\xD6\xE4\xE2");
+while ($stream->next) {
+ my $data = $stream->data;
+ ok("376568804730082" eq $data, "bigint unsigned works");
+}
+
+$stream = Data::MessagePack::Stream->new;
+$stream->feed("\xd3\xff\xfe\x7a\xd5\x18\x52\x6f\xfb");
+while ($stream->next) {
+ my $data = $stream->data;
+ ok("-427894298742789" eq $data, "bigint signed works");
+}