Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3e299ba
Bump taiki-e/install-action
dependabot[bot] Apr 8, 2026
9232d14
[DOC] Fill missing stars
nobu Apr 8, 2026
76eb974
[ruby/rubygems] Fix inconsistent indentation at line 481 in git_spec.rb
Copilot Apr 8, 2026
6d4e006
[ruby/rubygems] Fix lockfile DEPENDENCIES section to use 'rubocop' in…
Copilot Apr 8, 2026
a0092d2
[ruby/rubygems] Fix test_execute_allowed_push_host response message t…
Copilot Apr 8, 2026
3f85071
[ruby/rubygems] Fix typo in test description: 'to' -> 'do'
Copilot Apr 8, 2026
fdc2a61
[ruby/rubygems] Fix gemspec filename inconsistencies in stub_with_ver…
Copilot Apr 8, 2026
b11091c
[ruby/rubygems] Use distinct gemspec filenames in stub_with_version a…
Copilot Apr 8, 2026
42b74bd
[ruby/rubygems] Fix typos in comments and documentation
hsbt Apr 8, 2026
f5ad01e
[ruby/rubygems] Fix wrong expected value in Rust extension test templ…
hsbt Apr 8, 2026
539cb5e
[ruby/rubygems] Use eq matcher instead of be for string comparison in…
hsbt Apr 8, 2026
c8c0af3
[ruby/rubygems] Fix grammar in gem installer cache comment
hsbt Apr 8, 2026
0cebedd
Fix the order of `assert_equal` arguments
nobu Apr 8, 2026
24a2ba0
[Bug #21985] Include the `-` in the negative numbers location
nobu Apr 8, 2026
1fb0aca
imemo.h: Extract rb_imemo_needs_cleanup_p
byroot Apr 8, 2026
ad82b72
Skip `imemo_tmpbuf` sweeping when the buffer was eagerly freed.
byroot Apr 8, 2026
5c7e3c2
[ruby/openssl] kdf: release GVL in OpenSSL::KDF.pbkdf2_hmac
rhenium Aug 5, 2025
a5c9e84
[ruby/openssl] kdf: release GVL in OpenSSL::KDF.scrypt
rhenium Nov 3, 2025
7209523
[ruby/openssl] kdf: fix wrong OPENSSL_cleanse() calls
rhenium Apr 8, 2026
8886990
ZJIT: Add polymorphic support for getblockparamproxy (#16636)
nozomemein Apr 8, 2026
d3f7d2c
ZJIT: Pull load out of IsBlockParamModified (#16673)
tekknolagi Apr 8, 2026
6d6f927
ZJIT: Merge reduce_send_without_block_to_ccall and reduce_send_to_cca…
tekknolagi Apr 8, 2026
30e3148
ZJIT: Fix land race (#16686)
tekknolagi Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}

- uses: taiki-e/install-action@94cb46f8d6e437890146ffbd78a778b78e623fb2 # v2.74.0
- uses: taiki-e/install-action@cf39a74df4a72510be4e5b63348d61067f11e64a # v2.75.0
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ jobs:
ruby-version: '3.1'
bundler: none

- uses: taiki-e/install-action@94cb46f8d6e437890146ffbd78a778b78e623fb2 # v2.74.0
- uses: taiki-e/install-action@cf39a74df4a72510be4e5b63348d61067f11e64a # v2.75.0
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
116 changes: 92 additions & 24 deletions ext/openssl/ossl_kdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,27 @@

static VALUE mKDF, eKDF;

struct pbkdf2_hmac_args {
char *pass;
int passlen;
unsigned char *salt;
int saltlen;
int iters;
const EVP_MD *md;
int len;
unsigned char *out;
};

static void *
pbkdf2_hmac_nogvl(void *args_)
{
struct pbkdf2_hmac_args *args = (struct pbkdf2_hmac_args *)args_;
int ret = PKCS5_PBKDF2_HMAC(args->pass, args->passlen, args->salt,
args->saltlen, args->iters, args->md,
args->len, args->out);
return (void *)(uintptr_t)ret;
}

/*
* call-seq:
* KDF.pbkdf2_hmac(pass, salt:, iterations:, length:, hash:) -> aString
Expand Down Expand Up @@ -35,9 +56,9 @@ static VALUE mKDF, eKDF;
static VALUE
kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
{
VALUE pass, salt, opts, kwargs[4], str, md_holder;
VALUE pass, salt, opts, kwargs[4], str, md_holder, pass_tmp, salt_tmp;
static ID kwargs_ids[4];
int iters, len;
int passlen, saltlen, iters, len;
const EVP_MD *md;

if (!kwargs_ids[0]) {
Expand All @@ -54,18 +75,56 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
iters = NUM2INT(kwargs[1]);
len = NUM2INT(kwargs[2]);
md = ossl_evp_md_fetch(kwargs[3], &md_holder);

str = rb_str_new(0, len);
if (!PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LENINT(pass),
(unsigned char *)RSTRING_PTR(salt),
RSTRING_LENINT(salt), iters, md, len,
(unsigned char *)RSTRING_PTR(str)))
passlen = RSTRING_LENINT(pass);
saltlen = RSTRING_LENINT(salt);
str = rb_str_new(NULL, len);
struct pbkdf2_hmac_args args = {
.pass = ALLOCV(pass_tmp, passlen),
.passlen = passlen,
.salt = ALLOCV(salt_tmp, saltlen),
.saltlen = saltlen,
.iters = iters,
.md = md,
.len = len,
.out = (unsigned char *)RSTRING_PTR(str),
};
memcpy(args.pass, RSTRING_PTR(pass), passlen);
memcpy(args.salt, RSTRING_PTR(salt), saltlen);
if (!rb_thread_call_without_gvl(pbkdf2_hmac_nogvl, &args, NULL, NULL))
ossl_raise(eKDF, "PKCS5_PBKDF2_HMAC");

OPENSSL_cleanse(args.pass, passlen);
ALLOCV_END(pass_tmp);
ALLOCV_END(salt_tmp);
return str;
}

#if defined(HAVE_EVP_PBE_SCRYPT)
struct scrypt_args {
char *pass;
size_t passlen;
unsigned char *salt;
size_t saltlen;
uint64_t N, r, p;
size_t len;
unsigned char *out;
};

static void *
scrypt_nogvl(void *args_)
{
struct scrypt_args *args = (struct scrypt_args *)args_;
/*
* OpenSSL uses 32MB by default (if zero is specified), which is too
* small. Let's not limit memory consumption but just let malloc() fail
* inside OpenSSL. The amount is controllable by other parameters.
*/
uint64_t maxmem = UINT64_MAX;
int ret = EVP_PBE_scrypt(args->pass, args->passlen,
args->salt, args->saltlen, args->N, args->r,
args->p, maxmem, args->out, args->len);
return (void *)(uintptr_t)ret;
}

/*
* call-seq:
* KDF.scrypt(pass, salt:, N:, r:, p:, length:) -> aString
Expand Down Expand Up @@ -101,10 +160,11 @@ kdf_pbkdf2_hmac(int argc, VALUE *argv, VALUE self)
static VALUE
kdf_scrypt(int argc, VALUE *argv, VALUE self)
{
VALUE pass, salt, opts, kwargs[5], str;
VALUE pass, salt, opts, kwargs[5], str, pass_tmp, salt_tmp;
static ID kwargs_ids[5];
size_t len;
uint64_t N, r, p, maxmem;
size_t passlen, saltlen;
long len;
uint64_t N, r, p;

if (!kwargs_ids[0]) {
kwargs_ids[0] = rb_intern_const("salt");
Expand All @@ -122,19 +182,27 @@ kdf_scrypt(int argc, VALUE *argv, VALUE self)
r = NUM2UINT64T(kwargs[2]);
p = NUM2UINT64T(kwargs[3]);
len = NUM2LONG(kwargs[4]);
/*
* OpenSSL uses 32MB by default (if zero is specified), which is too small.
* Let's not limit memory consumption but just let malloc() fail inside
* OpenSSL. The amount is controllable by other parameters.
*/
maxmem = SIZE_MAX;

str = rb_str_new(0, len);
if (!EVP_PBE_scrypt(RSTRING_PTR(pass), RSTRING_LEN(pass),
(unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
N, r, p, maxmem, (unsigned char *)RSTRING_PTR(str), len))
passlen = RSTRING_LEN(pass);
saltlen = RSTRING_LEN(salt);
str = rb_str_new(NULL, len);
struct scrypt_args args = {
.pass = ALLOCV(pass_tmp, passlen),
.passlen = passlen,
.salt = ALLOCV(salt_tmp, saltlen),
.saltlen = saltlen,
.N = N,
.r = r,
.p = p,
.len = len,
.out = (unsigned char *)RSTRING_PTR(str),
};
memcpy(args.pass, RSTRING_PTR(pass), passlen);
memcpy(args.salt, RSTRING_PTR(salt), saltlen);
if (!rb_thread_call_without_gvl(scrypt_nogvl, &args, NULL, NULL))
ossl_raise(eKDF, "EVP_PBE_scrypt");

OPENSSL_cleanse(args.pass, passlen);
ALLOCV_END(pass_tmp);
ALLOCV_END(salt_tmp);
return str;
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion file.c
Original file line number Diff line number Diff line change
Expand Up @@ -5977,7 +5977,7 @@ rb_f_test(int argc, VALUE *argv, VALUE _)
* File.atime(filepath) # => 2026-04-01 11:58:11.922614 -0500
* stat.atime # => 2026-04-01 11:51:38.0014518 -0500
* File.delete(filepath)
stat.atime # => 2026-04-01 11:51:38.0014518 -0500
* stat.atime # => 2026-04-01 11:51:38.0014518 -0500
*
* === OS-Dependencies
*
Expand Down
13 changes: 1 addition & 12 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1313,18 +1313,7 @@ rb_gc_obj_needs_cleanup_p(VALUE obj)

switch (flags & RUBY_T_MASK) {
case T_IMEMO:
switch (imemo_type(obj)) {
case imemo_constcache:
case imemo_cref:
case imemo_ifunc:
case imemo_memo:
case imemo_svar:
case imemo_callcache:
case imemo_throw_data:
return false;
default:
return true;
}
return rb_imemo_needs_cleanup_p(obj);

case T_DATA:
case T_OBJECT:
Expand Down
28 changes: 27 additions & 1 deletion internal/imemo.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ enum imemo_type {
imemo_callinfo = 10,
imemo_callcache = 11,
imemo_constcache = 12,
imemo_fields = 13,
imemo_fields = 13,
};

/* CREF (Class REFerence) is defined in method.h */
Expand Down Expand Up @@ -292,4 +292,30 @@ rb_imemo_fields_complex_tbl(VALUE fields_obj)
return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table;
}

static inline bool
rb_imemo_needs_cleanup_p(VALUE obj)
{
switch (imemo_type(obj)) {
case imemo_constcache:
case imemo_cref:
case imemo_ifunc:
case imemo_memo:
case imemo_svar:
case imemo_callcache:
case imemo_throw_data:
return false;

case imemo_env:
case imemo_ment:
case imemo_iseq:
case imemo_callinfo:
case imemo_fields:
return true;

case imemo_tmpbuf:
return ((rb_imemo_tmpbuf_t *)obj)->ptr != NULL;
}
UNREACHABLE_RETURN(true);
}

#endif /* INTERNAL_IMEMO_H */
2 changes: 1 addition & 1 deletion lib/bundler/man/bundle-config.1
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Any periods in the configuration keys must be replaced with two underscores when
The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\.
.TP
\fBapi_request_size\fR (\fBBUNDLE_API_REQUEST_SIZE\fR)
Configure how many dependencies to fetch when resolving the specifications\. This configuration is only used when fetchig specifications from RubyGems servers that didn't implement the Compact Index API\. Defaults to 100\.
Configure how many dependencies to fetch when resolving the specifications\. This configuration is only used when fetching specifications from RubyGems servers that didn't implement the Compact Index API\. Defaults to 100\.
.TP
\fBauto_install\fR (\fBBUNDLE_AUTO_INSTALL\fR)
Automatically run \fBbundle install\fR when gems are missing\.
Expand Down
2 changes: 1 addition & 1 deletion lib/bundler/man/bundle-config.1.ronn
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).

* `api_request_size` (`BUNDLE_API_REQUEST_SIZE`):
Configure how many dependencies to fetch when resolving the specifications.
This configuration is only used when fetchig specifications from RubyGems
This configuration is only used when fetching specifications from RubyGems
servers that didn't implement the Compact Index API.
Defaults to 100.
* `auto_install` (`BUNDLE_AUTO_INSTALL`):
Expand Down
6 changes: 3 additions & 3 deletions lib/bundler/source/rubygems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -511,11 +511,11 @@ def extension_cache_slug(spec)
remote.cache_slug
end

# We are using a mutex to reaed and write from/to the hash.
# We are using a mutex to read and write from/to the hash.
# The reason this double synchronization was added is for performance
# and lock the mutex for the shortest possible amount of time. Otherwise,
# and to lock the mutex for the shortest possible amount of time. Otherwise,
# all threads are fighting over this mutex and when it gets acquired it gets locked
# until a threads finishes downloading a gem, leaving the other threads waiting
# until a thread finishes downloading a gem, leaving the other threads waiting
# doing nothing.
def rubygems_gem_installer(spec, options)
@gem_installers_mutex.synchronize { @gem_installers[spec.name] } || begin
Expand Down
2 changes: 1 addition & 1 deletion lib/bundler/templates/newgem/spec/newgem_spec.rb.tt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RSpec.describe <%= config[:constant_name] %> do
it "can call into Rust" do
result = <%= config[:constant_name] %>.hello("world")

expect(result).to be("Hello earth, from Rust!")
expect(result).to eq("Hello world, from Rust!")
end
<%- else -%>
it "does something useful" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class <%= config[:minitest_constant_name] %> < Minitest::Test

<%- if config[:ext] == 'rust' -%>
def test_hello_world
assert_equal "Hello earth, from Rust!", <%= config[:constant_name] %>.hello("world")
assert_equal "Hello world, from Rust!", <%= config[:constant_name] %>.hello("world")
end
<%- else -%>
def test_it_does_something_useful
Expand Down
7 changes: 4 additions & 3 deletions parse.y
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw
static rb_node_kw_arg_t *new_kw_arg(struct parser_params *p, NODE *k, const YYLTYPE *loc);
static rb_node_args_t *args_with_numbered(struct parser_params*,rb_node_args_t*,int,ID);

static NODE* negate_lit(struct parser_params*, NODE*);
static NODE* negate_lit(struct parser_params*, NODE*,const YYLTYPE*);
static void no_blockarg(struct parser_params*,NODE*);
static NODE *ret_args(struct parser_params*,NODE*);
static NODE *arg_blk_pass(NODE*,rb_node_block_pass_t*);
Expand Down Expand Up @@ -6133,7 +6133,7 @@ numeric : simple_numeric
| tUMINUS_NUM simple_numeric %prec tLOWEST
{
$$ = $2;
negate_lit(p, $$);
negate_lit(p, $$, &@$);
/*% ripper: unary!(ID2VAL(idUMinus), $:2) %*/
}
;
Expand Down Expand Up @@ -14358,7 +14358,7 @@ ret_args(struct parser_params *p, NODE *node)
}

static NODE*
negate_lit(struct parser_params *p, NODE* node)
negate_lit(struct parser_params *p, NODE* node, const YYLTYPE *loc)
{
switch (nd_type(node)) {
case NODE_INTEGER:
Expand All @@ -14374,6 +14374,7 @@ negate_lit(struct parser_params *p, NODE* node)
RNODE_IMAGINARY(node)->minus = TRUE;
break;
}
node->nd_loc = *loc;
return node;
}

Expand Down
4 changes: 2 additions & 2 deletions spec/bundler/install/gemfile/git_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@
update_git("foo", path: repo, tag: tag)

install_gemfile <<-G
source "https://gem.repo1"
source "https://gem.repo1"
git "#{repo}", :tag => #{tag.dump} do
gem "foo"
end
Expand Down Expand Up @@ -1078,7 +1078,7 @@
expect(out).to eq("WIN")
end

it "does not to a remote fetch if the revision is cached locally" do
it "does not do a remote fetch if the revision is cached locally" do
build_git "foo"

install_gemfile <<-G
Expand Down
2 changes: 1 addition & 1 deletion spec/bundler/install/gems/resolving_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@
#{lockfile_platforms}
DEPENDENCIES
parallel_tests
rubocop
#{checksums}
BUNDLED WITH
#{Bundler::VERSION}
Expand Down
7 changes: 6 additions & 1 deletion test/ruby/test_ast.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,11 @@ def test_yield_locations
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 20], [1, 9, 1, 14], [1, 14, 1, 15], [1, 19, 1, 20]])
end

def test_negative_numeric_locations
node = ast_parse("-1")
assert_locations(node.children.last.locations, [[1, 0, 1, 2]])
end

private
def ast_parse(src, **options)
begin
Expand All @@ -1759,7 +1764,7 @@ def ast_parse(src, **options)
def assert_locations(locations, expected)
ary = locations.map {|loc| loc && [loc.first_lineno, loc.first_column, loc.last_lineno, loc.last_column] }

assert_equal(ary, expected)
assert_equal(expected, ary)
end
end
end
2 changes: 1 addition & 1 deletion test/rubygems/test_gem_commands_push_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ def test_execute_allowed_push_host
spec.metadata["allowed_push_host"] = "https://privategemserver.example"
end

@response = "Successfully registered gem: freewill (1.0.0)"
@response = "Successfully registered gem: freebird (1.0.1)"
@fetcher.data["#{@spec.metadata["allowed_push_host"]}/api/v1/gems"] = HTTPResponseFactory.create(body: @response, code: 200, msg: "OK")
@fetcher.data["#{Gem.host}/api/v1/gems"] =
["fail", 500, "Internal Server Error"]
Expand Down
Loading