summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Cook <tony@develop-help.com>2011-11-14 19:48:54 +1100
committerTony Cook <tony@develop-help.com>2011-11-14 19:48:54 +1100
commit691f175822a5edda9dc7ba243d6c774254b9e225 (patch)
tree5415039182fd455755d9e457f2da539bc6be36d7
parent28884311ae0933070ec776bd972da9d711a5184b (diff)
downloadperl-691f175822a5edda9dc7ba243d6c774254b9e225.tar.gz
Internals::SvREFCNT() now treats reference counts as unsigned
Previously setting a large (negative in 32-bit signed) reference count would be returned as a positive number on 64-bit builds and negative on 32-bit builds.
-rw-r--r--lib/Internals.t9
-rw-r--r--universal.c6
2 files changed, 11 insertions, 4 deletions
diff --git a/lib/Internals.t b/lib/Internals.t
index d6c2367436..d3fce9c1c8 100644
--- a/lib/Internals.t
+++ b/lib/Internals.t
@@ -7,7 +7,7 @@ BEGIN {
}
}
-use Test::More tests => 76;
+use Test::More tests => 78;
my $ro_err = qr/^Modification of a read-only value attempted/;
@@ -166,4 +166,11 @@ is( Internals::SvREFCNT($foo{foo}), 1 );
is( Internals::SvREFCNT($foo, 2), 2, "update ref count");
is( Internals::SvREFCNT($foo), 2, "check we got the stored value");
+# the reference count is a U16, but was returned as an IV resulting in
+# different values between 32 and 64-bit builds
+my $big_count = 0xFFFFFFF0; # -16 32-bit signed
+is( Internals::SvREFCNT($foo, $big_count), $big_count,
+ "set reference count unsigned");
+is( Internals::SvREFCNT($foo), $big_count, "reference count unsigned");
+
Internals::SvREFCNT($foo, 1 );
diff --git a/universal.c b/universal.c
index 0599e6795d..6ea0e29cb1 100644
--- a/universal.c
+++ b/universal.c
@@ -924,11 +924,11 @@ XS(XS_Internals_SvREFCNT) /* This is dangerous stuff. */
sv = SvRV(svz);
if (items == 1)
- XSRETURN_IV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
+ XSRETURN_UV(SvREFCNT(sv) - 1); /* Minus the ref created for us. */
else if (items == 2) {
/* I hope you really know what you are doing. */
- SvREFCNT(sv) = SvIV(ST(1)) + 1; /* we free one ref on exit */
- XSRETURN_IV(SvREFCNT(sv) - 1);
+ SvREFCNT(sv) = SvUV(ST(1)) + 1; /* we free one ref on exit */
+ XSRETURN_UV(SvREFCNT(sv) - 1);
}
XSRETURN_UNDEF; /* Can't happen. */
}