Bug #20614
openInteger#size returns incorrect values on 64-bit Windows
Description
According to the ruby/spec, 0.size
should return size of the machine word in bytes, but on x64-mswin64_140 (both release 3.3.3 and git revision 02c4f0c89d) it doesn't. Following example:
a, b = 0.size, [0].pack('J').length
puts a, b
should print two 8
s, but on x64-mswin64_140, a is 4
.
Issue is most likely caused by use of long
instead of SIGNED_VALUE
in internal/fixnum.h and fix_size
function in numeric.c, because on Windows, long
is always a 32-bit number.
Updated by akr (Akira Tanaka) 9 days ago
You can use RbConfig::SIZEOF to query the size of a C type.
% ruby -v -rrbconfig/sizeof -e 'pp RbConfig::SIZEOF'
ruby 3.4.0dev (2024-05-16T19:35:22Z master 854cbbd5a9) [x86_64-linux]
{"int"=>4,
"short"=>2,
"long"=>8,
"long long"=>8,
"__int128"=>16,
"off_t"=>8,
"void*"=>8,
"float"=>4,
"double"=>8,
"time_t"=>8,
"clock_t"=>8,
"size_t"=>8,
"ptrdiff_t"=>8,
"dev_t"=>8,
"int8_t"=>1,
"uint8_t"=>1,
"int16_t"=>2,
"uint16_t"=>2,
"int32_t"=>4,
"uint32_t"=>4,
"int64_t"=>8,
"uint64_t"=>8,
"int128_t"=>16,
"uint128_t"=>16,
"intptr_t"=>8,
"uintptr_t"=>8,
"ssize_t"=>8,
"int_least8_t"=>1,
"int_least16_t"=>2,
"int_least32_t"=>4,
"int_least64_t"=>8,
"int_fast8_t"=>1,
"int_fast16_t"=>8,
"int_fast32_t"=>8,
"int_fast64_t"=>8,
"intmax_t"=>8,
"sig_atomic_t"=>4,
"wchar_t"=>4,
"wint_t"=>4,
"wctrans_t"=>8,
"wctype_t"=>8,
"_Bool"=>1,
"long double"=>16,
"float _Complex"=>8,
"double _Complex"=>16,
"long double _Complex"=>32,
"__float128"=>16,
"_Decimal32"=>4,
"_Decimal64"=>8,
"_Decimal128"=>16,
"__float80"=>16}
Updated by alanwu (Alan Wu) 9 days ago · Edited
IMO based on the current wording of the documentation it should always return sizeof(VALUE)
for fixnums, because VALUE holds the machine representation for fixnums.
By the way, ruby/spec is not a specification for how things ought to behave; it's descriptive not prescriptive. Check out the README of the project: https://github.com/ruby/spec?tab=readme-ov-file#description-and-motivation
Updated by Eregon (Benoit Daloze) 8 days ago
Agreed with @alanwu (Alan Wu), the docs seems clear, and one would expect this method returns how many bytes are used to represent the Integer (not counting object header overhead for bignums, fair enough):
int.size -> int
Document-method: Integer#size
Returns the number of bytes in the machine representation of int
(machine dependent).
1.size #=> 8
-1.size #=> 8
2147483647.size #=> 8
(256**10 - 1).size #=> 10
(256**20 - 1).size #=> 20
(256**40 - 1).size #=> 40
So it should be pointer-size bytes for any Fixnum on any platform (since Fixnum are tagged pointers).