Bug #15551
closedThe behavior of FIX2INT and FIX2UINT differs by platform
Description
For instance, when sizeof(int) < sizeof(long)
(such as on Linux), then
FIX2INT(nil)
raises TypeError.
But when sizeof(int) == sizeof(long)
(such as on Windows), then it returns 4
.
So the behavior changes from a call to rb_fix2int()
to a raw shift without any checks.
I think it should be consistent between platforms.
Also, the code in ruby.h defining FIX2INT is fairly complicated with conditions like #if SIZEOF_INT < SIZEOF_LONG
spanning many lines, which makes it fairly hard to follow.
See https://github.com/ruby/spec/blob/c661c0ba6a602be6e06768a319bd7d87b2a8eda6/optional/capi/fixnum_spec.rb
and https://ci.appveyor.com/project/eregon/spec-x948i/builds/21753809/job/ed8e8k97m8syp4r7 for more differences.
Files
Updated by Eregon (Benoit Daloze) over 5 years ago
FWIW, sizeof(int) == sizeof(long)
is also the case on i686 Linux:
https://travis-ci.org/ruby/ruby/jobs/482143545
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
- File fix2int-consistent.patch fix2int-consistent.patch added
I consider this an implementation detail and not a bug. I'm guessing the reason for this behavior is if sizeof(int) == sizeof(long)
, then all Fixnums are convertible to int (since all Fixnums are convertible to long). This is different than the sizeof(int) < sizeof(long)
case, where not all Fixnums are convertible to int. It is possible to add checks that a Fixnum value is passed, but doing so would hurt performance.
Note that FIX2LONG
is always a pure shift, so FIX2LONG(Qnil)
never raises. By attempting to make the FIX2INT
behavior consistent across platforms, you make FIX2LONG
inconsistent with FIX2INT
in both of the cases instead of just one.
If we still feel like this is a good idea, we could try the attached patch. I did some basic testing of this on OpenBSD-i386, where sizeof(int) == sizeof(long)
. However, I recommend we keep things as they are.
Updated by mame (Yusuke Endoh) over 4 years ago
- Status changed from Open to Rejected
It is by design. doc/extension.rdoc says:
T_FIXNUM can be converted to a C integer by using the
FIX2INT() macro or FIX2LONG(). Though you have to check that the
data is really FIXNUM before using them, they are faster.
So FIX2INT(nil)
is intentionally designed to be undefined.