[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#579450: libdevice-cdio-perl: FTBFS with perl 5.12.0-1: 64-bit integers



tags 579450 +patch
reassign 579450 swig1.3
found 579450 1.3.40-3
thanks

On Sun, May 01, 2011 at 08:10:32PM +0100, Chris Butler wrote:
> Having a quick look at this, I don't think this problem is specific to
> libdevice-cdio-perl, I think it may be an issue with SWIG. From the looks of
> it, SWIG doesn't handle -Duse64bitint correctly when presented with
> integer arguments > 2^31. The value from perl is a 64-bit IV; this confuses
> SWIG's argument handling code, which seems to be expecting that
> sizeof(perl IV) == sizeof(C int).
> 
> Basically, the SWIG wrapper code that errors is:
> 
> ecode1 = SWIG_AsVal_unsigned_SS_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
> if (!SWIG_IsOK(ecode1)) {
>     SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "get_devices_with_cap" "', argument " "1"" of type '" "unsigned int""'");
> } 
> 
> The test that fails is passing in CDIO_FS_MATCH_ALL, which is 0xfffffff0.
> 
> SWIG_AsVal_unsigned_SS_int calls SWIG_AsVal_unsigned_SS_long, which contains
> this code:
> 
> if (SvUOK(obj)) {
>     if (val) *val = SvUV(obj);
>     return SWIG_OK;
> } else  if (SvIOK(obj)) {
>     long v = SvIV(obj);
>     if (v >= 0) {
>         if (val) *val = v;
>         return SWIG_OK;
>     } else {
>         return SWIG_OverflowError;
>     }
> }
> 
> Running this in gdb, I can see that SvUOK returns false (as obj is an IV),
> and SvIOK returns true. SvIV correctly returns 0xffffffff0, which is -16
> when put into a signed variable. This obviously makes the (v >= 0) test
> fail, causing the OverflowError.
> 
> Anyway, I'd say this is a SWIG bug and not a bug in libdevice-cdio-perl.
> FWIW, I tested it with the version of swig2.0 in unstable and it has the
> same problem. Think this upstream SWIG bug is relevant:

I'm now pretty sure this is a bug in swig, and not libdevice-cdio-perl, so
reassigning.

The problem is that SWIG's type conversion code assumes that an IV is the
same size as a "long", and with the new perl5.12 package that's no longer
then case on 32-bit architectures (they're now a 64-bit "long long").

I've attached a patch that fixes the problem for me (a patched swig fixes
the FTBFS that triggered this bug). Rather than making any assumptions on
the size of an IV, it uses the "IV" type defined by the perl headers, then
explicitly checks the value is within the range it is trying to convert to.
I've been through and changed all of the IV conversions I could find; even
though it was only the unsigned int conversion that failed for this package,
others may have similar issues.

The same patch applies to both swig1.3 and swig2.0, I guess both will need
updating. Once the fixed package is available, we may also want to
reschedule binNMUs for the perl modules that build-depend on swig just to
be sure they're working correctly.

-- 
Chris Butler <chrisb@debian.org>
  GnuPG Key ID: 4096R/49E3ACD3
Description: Fix overflow errors with 64-bit IVs
 The perl 5.12 packages are compiled with -Duse64bitint, which means that IVs
 are 64-bits even on 32-bit architectures. When converting IVs, SWIG assumes
 that an IV is the same size as a long, which causes OverflowErrors with
 unsigned longs when the value is greater than 2^31.
 .
 This patch should remove those assumptions by using the "IV" type defined by
 the perl headers, and explicitly checking the values are within the correct
 range for the type being converted.
Author: Chris Butler <chrisb@debian.org>
Bug-Debian: http://bugs.debian.org/579540
Forwarded: no

--- a/Lib/perl5/perlprimtypes.swg
+++ b/Lib/perl5/perlprimtypes.swg
@@ -56,8 +56,13 @@
 SWIG_AsVal_dec(long)(SV *obj, long* val)
 {
   if (SvIOK(obj)) {
-    if (val) *val = SvIV(obj);
-    return SWIG_OK;
+    IV v = SvIV(obj);
+    if (v >= LONG_MIN && v <= LONG_MAX) {
+      if (val) *val = v;
+      return SWIG_OK;
+    } else {
+      return SWIG_OverflowError;
+    }
   } else {
     int dispatch = 0;
     const char *nptr = SvPV_nolen(obj);
@@ -108,11 +113,16 @@
 SWIG_AsVal_dec(unsigned long)(SV *obj, unsigned long *val) 
 {
   if (SvUOK(obj)) {
-    if (val) *val = SvUV(obj);
-    return SWIG_OK;
+    UV v = SvUV(obj);
+    if (v >= 0 && v <= ULONG_MAX) {
+      if (val) *val = v;
+      return SWIG_OK;
+    } else {
+      return SWIG_OverflowError;
+    }
   } else  if (SvIOK(obj)) {
-    long v = SvIV(obj);
-    if (v >= 0) {
+    IV v = SvIV(obj);
+    if (v >= 0 && v <= ULONG_MAX) {
       if (val) *val = v;
       return SWIG_OK;
     } else {
@@ -179,8 +189,13 @@
 SWIG_AsVal_dec(long long)(SV *obj, long long *val)
 {
   if (SvIOK(obj)) {
-    if (val) *val = SvIV(obj);
-    return SWIG_OK;
+    IV v = SvIV(obj);
+    if (v >= LLONG_MIN && v <= LLONG_MAX) {
+      if (val) *val = v;
+      return SWIG_OK;
+    } else {
+      return SWIG_OverflowError;
+    }
   } else {
     int dispatch = 0;
     const char *nptr = SvPV_nolen(obj);
@@ -246,8 +261,8 @@
     if (val) *val = SvUV(obj);
     return SWIG_OK;
   } else  if (SvIOK(obj)) {
-    long v = SvIV(obj);
-    if (v >= 0) {
+    IV v = SvIV(obj);
+    if (v >= 0 && v <= ULLONG_MAX) {
       if (val) *val = v;
       return SWIG_OK;
     } else {

Reply to: