Make rb_len_t 64 bits on mswin

long is 32 bits on mswin while pointers are 64 bits, so String, Array and MatchData could not reach 2GiB there. config.h now sets SIZEOF_RB_LEN_T to 8 on mswin64, and value.h then defines rb_len_t as int64_t. mingw still uses long.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hiroshi SHIBATAandClaude Opus 5.5 committed 2026-10-19 16:07:39 +09:00
1 parent d60c0505be
commit 4e746b14fd
11 files changed
+67 -35
Notes: git 2026-10-19 07:09:01 +00:00

No files matched your search

+10 -3
View File
@@ -22,6 +22,7 @@
*/
#include "ruby/internal/config.h"
#include "ruby/internal/arithmetic/long.h"
#include "ruby/internal/arithmetic/long_long.h"
#include "ruby/internal/assume.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/value.h"
@@ -32,14 +33,20 @@
#define rb_len2int rb_len2int_inline /**< @alias{rb_len2int_inline} */
#define rb_len2long rb_len2long_inline /**< @alias{rb_len2long_inline} */
#if SIZEOF_RB_LEN_T > SIZEOF_LONG
# define RB_LEN2NUM RB_LL2NUM
# define RB_NUM2LEN RB_NUM2LL
# define RB_ULEN2NUM RB_ULL2NUM
#else
/** Converts a ::rb_len_t into an instance of ::rb_cInteger. */
#define RB_LEN2NUM RB_LONG2NUM
# define RB_LEN2NUM RB_LONG2NUM
/** Converts an instance of ::rb_cNumeric into ::rb_len_t. */
#define RB_NUM2LEN RB_NUM2LONG
# define RB_NUM2LEN RB_NUM2LONG
/** Converts a ::rb_ulen_t into an instance of ::rb_cInteger. */
#define RB_ULEN2NUM RB_ULONG2NUM
# define RB_ULEN2NUM RB_ULONG2NUM
#endif
/**
* Checks if `int` can hold the given integer.
+25 -13
View File
@@ -124,34 +124,46 @@ typedef unsigned LONG_LONG ID;
# error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
#endif
#if defined(SIZEOF_RB_LEN_T) && SIZEOF_RB_LEN_T > SIZEOF_LONG
/* mswin, where long is narrower than a pointer and config.h asks for more. */
# include <stdint.h>
typedef int64_t rb_len_t;
typedef uint64_t rb_ulen_t;
# define PRI_LEN_PREFIX PRI_64_PREFIX
# define RB_LEN_MAX INT64_MAX
# define RB_LEN_MIN INT64_MIN
# define RB_ULEN_MAX UINT64_MAX
#else
/**
* A signed integer type for lengths and indices of objects such as String and
* Array. It is `long` for now, on every platform.
* Array. It is `long`, except on mswin, where it is `int64_t`.
*/
typedef long rb_len_t;
/** An unsigned integer type that has the same width with ::rb_len_t. */
typedef unsigned long rb_ulen_t;
/** Indicates that ::rb_len_t and ::rb_ulen_t are available. */
#define HAVE_RB_LEN_T 1
#ifndef SIZEOF_RB_LEN_T
# ifndef SIZEOF_RB_LEN_T
/** Size of ::rb_len_t, in bytes. */
# define SIZEOF_RB_LEN_T SIZEOF_LONG
#endif
# define SIZEOF_RB_LEN_T SIZEOF_LONG
# endif
/** Printf prefix for ::rb_len_t. */
#define PRI_LEN_PREFIX "l"
# define PRI_LEN_PREFIX "l"
/** Maximum possible value that a ::rb_len_t can take. */
#define RB_LEN_MAX LONG_MAX
# define RB_LEN_MAX LONG_MAX
/** Minimum possible value that a ::rb_len_t can take. */
#define RB_LEN_MIN LONG_MIN
# define RB_LEN_MIN LONG_MIN
/** Maximum possible value that a ::rb_ulen_t can take. */
#define RB_ULEN_MAX ULONG_MAX
# define RB_ULEN_MAX ULONG_MAX
#endif
/** Indicates that ::rb_len_t and ::rb_ulen_t are available. */
#define HAVE_RB_LEN_T 1
/** @cond INTERNAL_MACRO */
RBIMPL_STATIC_ASSERT(sizeof_int, SIZEOF_INT == sizeof(int));
@@ -159,7 +171,7 @@ RBIMPL_STATIC_ASSERT(sizeof_long, SIZEOF_LONG == sizeof(long));
RBIMPL_STATIC_ASSERT(sizeof_long_long, SIZEOF_LONG_LONG == sizeof(LONG_LONG));
RBIMPL_STATIC_ASSERT(sizeof_voidp, SIZEOF_VOIDP == sizeof(void *));
RBIMPL_STATIC_ASSERT(sizeof_rb_len_t_macro, SIZEOF_RB_LEN_T == sizeof(rb_len_t));
RBIMPL_STATIC_ASSERT(sizeof_rb_len_t, sizeof(rb_len_t) == sizeof(long));
RBIMPL_STATIC_ASSERT(sizeof_rb_ulen_t, sizeof(rb_ulen_t) == sizeof(unsigned long));
RBIMPL_STATIC_ASSERT(sizeof_rb_len_t, sizeof(rb_len_t) <= SIZEOF_VALUE);
RBIMPL_STATIC_ASSERT(sizeof_rb_ulen_t, sizeof(rb_ulen_t) == sizeof(rb_len_t));
/** @endcond */
#endif /* RBIMPL_VALUE_H */
+16 -6
View File
@@ -103,14 +103,24 @@ typedef unsigned LONG_LONG ID;
# error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<----
#endif
#if defined(SIZEOF_RB_LEN_T) && SIZEOF_RB_LEN_T > SIZEOF_LONG
# include <stdint.h>
typedef int64_t rb_len_t;
typedef uint64_t rb_ulen_t;
# define PRI_LEN_PREFIX PRI_64_PREFIX
# define RB_LEN_MAX INT64_MAX
# define RB_LEN_MIN INT64_MIN
# define RB_ULEN_MAX UINT64_MAX
#else
typedef long rb_len_t;
typedef unsigned long rb_ulen_t;
#ifndef SIZEOF_RB_LEN_T
# define SIZEOF_RB_LEN_T SIZEOF_LONG
# ifndef SIZEOF_RB_LEN_T
# define SIZEOF_RB_LEN_T SIZEOF_LONG
# endif
# define PRI_LEN_PREFIX "l"
# define RB_LEN_MAX LONG_MAX
# define RB_LEN_MIN LONG_MIN
# define RB_ULEN_MAX ULONG_MAX
#endif
#define PRI_LEN_PREFIX "l"
#define RB_LEN_MAX LONG_MAX
#define RB_LEN_MIN LONG_MIN
#define RB_ULEN_MAX ULONG_MAX
#endif /* EXTERNAL_VALUE_H */
+1 -1
View File
@@ -6833,7 +6833,7 @@ str_bit_offset_out_of_range(rb_len_t byte_len, uint64_t bit_offset)
* Keep both the full bit offset and its rb_len_t representation. Most calls
* use a Fixnum-sized offset and can stay on the rb_len_t fast path; only large
* Bignum offsets need the uint64_t path below. This matters on platforms where
* rb_len_t is narrower than the address space, such as 32-bit and LLP64.
* rb_len_t is 32 bits.
*/
struct str_bit_offset {
uint64_t value;
+2 -2
View File
@@ -16,11 +16,11 @@ class Test_StringModifyExpand < Test::Unit::TestCase
end
def test_integer_overflow
return if RbConfig::SIZEOF['size_t'] > RbConfig::SIZEOF['long']
return if RbConfig::SIZEOF['size_t'] > RbConfig::SIZEOF['rb_len_t']
bug12390 = '[ruby-core:75592] [Bug #12390]'
s = Bug::String.new
assert_raise(ArgumentError, bug12390) {
s.modify_expand!(RbConfig::LIMITS["LONG_MAX"])
s.modify_expand!(2 ** (RbConfig::SIZEOF['rb_len_t'] * 8 - 1) - 1)
}
end
end
+3 -3
View File
@@ -3778,10 +3778,10 @@ class TestArray < Test::Unit::TestCase
assert_include([1, 2], a.bsearch_index {|x| (2**100).coerce((1 - x / 4) * (2**100)).first })
end
sizeof_long = [0].pack("l!").size
sizeof_len = RbConfig::SIZEOF["rb_len_t"]
sizeof_voidp = [""].pack("p").size
if sizeof_long < sizeof_voidp
ARY_MAX = (1<<(8*sizeof_long-1)) / sizeof_voidp - 1
if sizeof_len < sizeof_voidp
ARY_MAX = (1<<(8*sizeof_len-1)) / sizeof_voidp - 1
Bug11235 = '[ruby-dev:49043] [Bug #11235]'
def test_push_over_ary_max
+3 -3
View File
@@ -425,12 +425,12 @@ class TestRand < Test::Unit::TestCase
end
def test_urandom_size_errors
beyond_long = 2 ** (RbConfig::SIZEOF['long'] * 8 - 1)
beyond_len = 2 ** (RbConfig::SIZEOF['rb_len_t'] * 8 - 1)
assert_raise(ArgumentError) { Random.urandom(-1) }
assert_raise(RangeError) { Random.urandom(beyond_long) }
assert_raise(RangeError) { Random.urandom(beyond_len) }
# Random#bytes converts its size the same way, so the classes have to agree
assert_raise(ArgumentError) { Random.new.bytes(-1) }
assert_raise(RangeError) { Random.new.bytes(beyond_long) }
assert_raise(RangeError) { Random.new.bytes(beyond_len) }
end
def test_new_seed
+1
View File
@@ -791,6 +791,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define SIZEOF_OFF_T 8
!if "$(TARGET_OS)" == "mswin64"
#define SIZEOF_VOIDP 8
#define SIZEOF_RB_LEN_T 8
!else
#define SIZEOF_VOIDP 4
!endif
+3 -3
View File
@@ -50,9 +50,9 @@ STATIC_ASSERT(size_t_no_padding_bits, sizeof(size_t) == sizeof(uint64_t));
// support one scheme for simplicity.
STATIC_ASSERT(pointer_tagging_scheme, USE_FLONUM);
// The bindings declare rb_len_t as c_long, and codegen reads String and Array
// lengths at that width. Widening rb_len_t needs TYPE_REPLACEMENTS updated too.
STATIC_ASSERT(rb_len_t_matches_bindings, sizeof(rb_len_t) == sizeof(long));
// The bindings declare rb_len_t as i64, and codegen reads String and Array
// lengths at that width.
STATIC_ASSERT(rb_len_t_matches_bindings, sizeof(rb_len_t) == sizeof(int64_t));
enum yjit_bindgen_constants {
// ISEQ_TRANSLATED expands to an enum value through a chain of macros,
+2
View File
@@ -422,6 +422,8 @@ fn main() {
// These are unsigned long on LP64 but unsigned long long on LLP64 (Windows)
("pub type ID = ::std::os::raw::c_ulong;", "pub type ID = u64;"),
("pub type st_data_t = ::std::os::raw::c_ulong;", "pub type st_data_t = u64;"),
// long on LP64 but int64_t on mswin
("pub type rb_len_t = ::std::os::raw::c_long;", "pub type rb_len_t = i64;"),
];
// Each needle is a whole line of the output, so plain replacement is unambiguous.
// Yes, this search-and-replace could be faster, but it's a small file.
+1 -1
View File
@@ -173,7 +173,7 @@ pub const VM_ENV_DATA_INDEX_SPECVAL: i32 = -1;
pub const VM_ENV_DATA_INDEX_FLAGS: u32 = 0;
pub const VM_BLOCK_HANDLER_NONE: u32 = 0;
pub type ID = u64;
pub type rb_len_t = ::std::os::raw::c_long;
pub type rb_len_t = i64;
pub type rb_alloc_func_t = ::std::option::Option<unsafe extern "C" fn(klass: VALUE) -> VALUE>;
pub const RUBY_Qfalse: ruby_special_consts = 0;
pub const RUBY_Qnil: ruby_special_consts = 4;