Ruby/DL: bignum->long

Using Ruby/DL, it seems as though a 32-bit integer with the MSB set cannot be converted to a long integer:

   require 'dl'

   DL::dlopen("libc.so.5") do |libc|
     isdigit = libc['isdigit', 'CH']
     p 0x40000000.class
     print(isdigit.call(0x40000000), "\n")
     p 0x80000000.class
     print(isdigit.call(0x80000000), "\n")
   end

The above will print the first one successfully, even though 0x40000000 is a Bignum. The second one results in an error:

   in `call': bignum too big to convert into `long' (RangeError)

Is this a bug, or a feature? Is there a workaround? Any advice would be appreciated.

Thanks,

Jamis

···

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis

I think the call is failing because of some code in bignum.c:

lines 765-776:

long
rb_big2long(x)
    VALUE x;
{
    unsigned long num = big2ulong(x, "long");

    if ((long)num < 0 && (RBIGNUM(x)->sign || (long)num != LONG_MIN)) {
  rb_raise(rb_eRangeError, "bignum too big to convert into `long'");
    }
    if (!RBIGNUM(x)->sign) return -(long)num;
    return num;
}

It checks to see if the number goes negative when trying to convert it
to a long, and if so, raises an exception. In this case you are using
a hex value to set an integer that you intend to be negative, but Ruby
treats this as a positive integer. Perhaps you could get around it by
putting the number in as a negative:

#!/usr/bin/env ruby

require 'dl'

DL::dlopen("libc.dylib") do |libc|
  isdigit = libc['isdigit', 'CH']
  p 0x40000000.class
  print(isdigit.call(0x40000000), "\n")
  p -2147483648.class
  print(isdigit.call(-2147483648), "\n")
end

Here is the output:

Bignum
01073741824
Bignum
0-2147483648

···

On Sat, 23 Oct 2004 13:23:22 +0900, Jamis Buck <jgb3@email.byu.edu> wrote:

Using Ruby/DL, it seems as though a 32-bit integer with the MSB set
cannot be converted to a long integer:

   require 'dl'

   DL::dlopen("libc.so.5") do |libc|
     isdigit = libc['isdigit', 'CH']
     p 0x40000000.class
     print(isdigit.call(0x40000000), "\n")
     p 0x80000000.class
     print(isdigit.call(0x80000000), "\n")
   end

The above will print the first one successfully, even though 0x40000000
is a Bignum. The second one results in an error:

   in `call': bignum too big to convert into `long' (RangeError)

Is this a bug, or a feature? Is there a workaround? Any advice would be
   appreciated.

Thanks,

Jamis

--
Jamis Buck
jgb3@email.byu.edu
http://www.jamisbuck.org/jamis