Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/workflows/check_sast.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,14 @@ jobs:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
languages: ${{ matrix.language }}
build-mode: none
config-file: .github/codeql/codeql-config.yml

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
category: '/language:${{ matrix.language }}'
upload: False
Expand Down Expand Up @@ -127,7 +127,7 @@ jobs:
continue-on-error: true

- name: Upload SARIF
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
sarif_file: sarif-results/${{ matrix.language }}.sarif
continue-on-error: true
11 changes: 4 additions & 7 deletions .github/workflows/compilers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ jobs:
with:
name: compilation-source
path: ${{ runner.temp }}/compilation-source.tar
compression-level: 0
compression-level: 5
overwrite: true
retention-days: 1

compile:
Expand Down Expand Up @@ -183,18 +184,15 @@ jobs:

- { uses: *compilers, name: 'NDEBUG', with: { cppflags: '-DNDEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" }
- { uses: *compilers, name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" }
- { uses: *compilers, name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" }
- { uses: *compilers, name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" }
- { uses: *compilers, name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" }
- { uses: *compilers, name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" }
- { uses: *compilers, name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" }
- { uses: *compilers, name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" }

- { uses: *compilers, name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '17' }}" }
- { uses: *compilers, name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 8, if: "${{ matrix.shard == '17' }}" }
- { uses: *compilers, name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '17' }}" }
- { uses: *compilers, name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" }
- { uses: *compilers, name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" }
- { uses: *compilers, name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" }
- { uses: *compilers, name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" }

Expand All @@ -206,7 +204,6 @@ jobs:
- { uses: *compilers, name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' }, timeout-minutes: 8, if: "${{ matrix.shard == '16' }}" }
- { uses: *compilers, name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 8, if: "${{ matrix.shard == '16' }}" }

- { uses: *compilers, name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" }
- { uses: *compilers, name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" }
- { uses: *compilers, name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" }
- { uses: *compilers, name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" }
Expand Down Expand Up @@ -245,15 +242,15 @@ jobs:
- name: Create empty source artifact
run: touch compilation-source.empty
working-directory: ${{ runner.temp }}
if: ${{ always() }}
if: ${{ needs.compile.result == 'success' }}
- name: Shrink source artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: compilation-source
path: ${{ runner.temp }}/compilation-source.empty
overwrite: true
retention-days: 1
if: ${{ always() }}
if: ${{ needs.compile.result == 'success' }}

- run: false
working-directory:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
sarif_file: results.sarif
2 changes: 1 addition & 1 deletion .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
rustup install ${{ matrix.rust_version }} --profile minimal
rustup default ${{ matrix.rust_version }}

- uses: taiki-e/install-action@5b4d68e2e660441203ab128a23676f1e4faf1532 # v2.86.3
- uses: taiki-e/install-action@ba47c86ac325773530516bb756137ac718732518 # v2.86.5
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 @@ -152,7 +152,7 @@ jobs:
ruby-version: '3.1'
bundler: none

- uses: taiki-e/install-action@5b4d68e2e660441203ab128a23676f1e4faf1532 # v2.86.3
- uses: taiki-e/install-action@ba47c86ac325773530516bb756137ac718732518 # v2.86.5
with:
tool: nextest@0.9
if: ${{ matrix.test_task == 'zjit-check' }}
Expand Down
85 changes: 56 additions & 29 deletions file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1794,19 +1794,27 @@ rb_access(VALUE fname, int mode)

/*
* call-seq:
* File.directory?(path) -> true or false
* File.directory?(object) -> true or false
*
* With string +object+ given, returns +true+ if +path+ is a string path
* leading to a directory, or to a symbolic link to a directory; +false+ otherwise:
* Returns whether the given +object+ represents a directory;
* +object+ may be a string path or an IO object:
*
* File.directory?('.') # => true
* File.directory?('foo') # => false
* File.symlink('.', 'dirlink') # => 0
* File.directory?('dirlink') # => true
* File.symlink('t,txt', 'filelink') # => 0
* File.directory?('filelink') # => false
* File.directory?('/etc') # => true
* File.directory?('lib') # => true
* File.directory?('README.md') # => false
* File.directory?('nosuch') # => false
* File.directory?($stdin) # => false
*
* Argument +path+ can be an IO object.
* Follows symbolic links:
*
* dirpath = 'doc/dirname'
* File.symlink('.', dirpath)
* File.directory?(dirpath) # => true
* File.unlink(dirpath)
* filepath = 't.tmp'
* File.symlink('README.md', filepath)
* File.directory?(filepath) # => false
* File.unlink(filepath)
*
*/

Expand Down Expand Up @@ -2691,17 +2699,36 @@ rb_file_mtime(VALUE obj)

/*
* call-seq:
* File.ctime(file_name) -> time
* File.ctime(object) -> time
*
* Returns the change time for the named file (the time at which
* directory information about the file was changed, not the file
* itself).
* Returns a Time object, based on the given +object+,
* which is a string path or an IO object.
*
* _file_name_ can be an IO object.
* On Windows, returns the #birthtime for +object+.
*
* Note that on Windows (NTFS), returns creation time (birth time).
* On other systems,
* returns a new Time object containing the time of the most recent
* metadata change to the entry represented by +object+;
* see {File System Timestamps}[rdoc-ref:file/timestamps.md]:
*
* File.ctime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003
* # Create directory; directory ctime established.
* dirpath = 'doc/foo'
* Dir.mkdir(dirpath)
* File.ctime(dirpath) # => 2026-08-23 10:43:05.473815913 -0500
* # Create file therein; file ctime established; directory ctime updated.
* filepath = File.join(dirpath, 't.tmp') # => "doc/foo/t.tmp"
* File.write(filepath, 'foo')
* File.ctime(filepath) # => 2026-08-23 10:43:37.560429379 -0500
* File.ctime(dirpath) # => 2026-08-23 10:43:37.560429379 -0500
* # Write file; file ctime updated; directory ctime not updated.
* File.write(filepath, 'bar')
* File.ctime(filepath) # => 2026-08-23 10:46:49.299180833 -0500
* File.ctime(dirpath) # => 2026-08-23 10:43:37.560429379 -0500
* # Read file; neither ctime updated.
* File.read(filepath)
* File.ctime(filepath) # => 2026-08-23 10:46:49.299180833 -0500
* File.ctime(dirpath) # => 2026-08-23 10:43:37.560429379 -0500
* FileUtils.rm_rf(dirpath) # Clean up.
*
*/

Expand Down Expand Up @@ -3752,18 +3779,18 @@ unlink_internal(const char *path, void *arg)

/*
* call-seq:
* File.delete(file_name, ...) -> integer
* File.unlink(file_name, ...) -> integer
*
* Deletes the named files, returning the number of names
* passed as arguments. Raises an exception on any error.
* Since the underlying implementation relies on the
* <code>unlink(2)</code> system call, the type of
* exception raised depends on its error type (see
* https://man7.org/linux/man-pages/man2/unlink.2.html) and has the form of
* e.g. Errno::ENOENT.
*
* See also Dir::rmdir.
* File.delete(*filepaths) -> integer
* File.unlink(*filepaths) -> integer
*
* Removes the file entry at each path in +filepaths+;
* returns the number of removed files.
*
* File.write('t.tmp', 'foo')
* File.write('u.tmp', 'bar')
* File.delete('t.tmp', 'u.tmp') # => 2
*
* Raises an exception on any error;
* some files may have been deleted before the path causing the error.
*/

static VALUE
Expand Down
50 changes: 33 additions & 17 deletions io_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1007,17 +1007,19 @@ io_buffer_validate_slice(VALUE source, void *base, size_t size)
rb_io_buffer_get_bytes(source, &source_base, &source_size);
}

// Source is invalid:
if (source_base == NULL) return 0;
uintptr_t source_address = (uintptr_t)source_base;
uintptr_t address = (uintptr_t)base;

// Base is out of range:
if (base < source_base) return 0;
if (address < source_address) return 0;

const void *source_end = (char*)source_base + source_size;
const void *end = (char*)base + size;
uintptr_t offset = address - source_address;

// End is out of range:
if (end > source_end) return 0;
// Base is beyond the end of the source:
if (offset > source_size) return 0;

// End is beyond the end of the source:
if (size > source_size - (size_t)offset) return 0;

// It seems okay:
return 1;
Expand Down Expand Up @@ -1316,10 +1318,17 @@ rb_io_buffer_size(VALUE self)
/*
* call-seq: valid? -> true or false
*
* Returns whether the buffer buffer is accessible.
* Returns whether the buffer's recorded memory range currently exists within
* its source. A buffer which is not a slice is always valid, including a null
* buffer.
*
* A slice can become invalid if its source is freed, transferred, shrunk past
* the slice, or reallocated at a different address. Validity is dynamic: if
* the source later contains the same address range again, the slice becomes
* valid again.
*
* A buffer becomes invalid if it is a slice of another buffer (or string)
* which has been freed or re-allocated at a different address.
* #valid?, #null? and #empty? describe independent properties. For example,
* an invalid slice can still have a non-null address and a non-zero size.
*/
static VALUE
rb_io_buffer_valid_p(VALUE self)
Expand All @@ -1332,8 +1341,11 @@ rb_io_buffer_valid_p(VALUE self)
/*
* call-seq: null? -> true or false
*
* If the buffer was freed with #free, transferred with #transfer, or was
* never allocated in the first place.
* Returns whether the buffer has no recorded base address.
*
* A buffer is null if it was freed with #free, transferred with #transfer, or
* was never allocated in the first place. A zero-sized buffer or slice may
* have a non-null address, so #null? and #empty? are distinct properties.
*
* buffer = IO::Buffer.new(0)
* buffer.null? #=> true
Expand All @@ -1354,9 +1366,11 @@ rb_io_buffer_null_p(VALUE self)
/*
* call-seq: empty? -> true or false
*
* If the buffer has 0 size: it is created by ::new with size 0, or with ::for
* from an empty string. (Note that empty files can't be mapped, so the buffer
* created with ::map will never be empty.)
* Returns whether the buffer has zero size.
*
* A buffer can be empty but have a non-null address, for example a zero-sized
* slice or a buffer created with ::for from an empty string. Therefore
* #empty? does not imply #null?.
*/
static VALUE
rb_io_buffer_empty_p(VALUE self)
Expand Down Expand Up @@ -1776,7 +1790,7 @@ rb_io_buffer_slice(struct rb_io_buffer *buffer, VALUE self, size_t offset, size_
struct rb_io_buffer *slice = get_io_buffer(instance);

slice->flags |= (buffer->flags & RB_IO_BUFFER_READONLY);
slice->base = (char*)buffer->base + offset;
slice->base = buffer->base ? (char*)buffer->base + offset : NULL;
slice->size = length;

// Slices retain their root buffer. If this buffer is already a slice,
Expand Down Expand Up @@ -3002,7 +3016,9 @@ io_buffer_get_string(int argc, VALUE *argv, VALUE self)

io_buffer_validate_range(buffer, offset, length);

return rb_enc_str_new((const char*)base + offset, length, encoding);
const char *data = base ? (const char*)base + offset : NULL;

return rb_enc_str_new(data, length, encoding);
}

/*
Expand Down
7 changes: 7 additions & 0 deletions lib/bundler/fetcher/connection_pools.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def proxy_for(uri)
env_proxy_for(uri)
end
return unless proxy
# NO_PROXY="*" bypasses the proxy for every host, which
# Gem::URI::Generic.use_proxy? does not understand.
return if no_proxy_env.strip == "*"
return unless Gem::URI::Generic.use_proxy?(uri.hostname, nil, uri.port, no_proxy_env)
proxy
end
Expand All @@ -90,6 +93,10 @@ def build_connection(uri, proxy_uri) # :nodoc:
configure_ssl(connection) if uri.scheme == "https"
connection.open_timeout = @timeout
connection.read_timeout = @timeout
# Stale connections are already resent by Gem::Request#perform_request,
# and Bundler::Retry retries whole requests, so the Gem::Net::HTTP
# level retry would only multiply the time spent on a timing out host.
connection.max_retries = 0
connection.start
connection
end
Expand Down
8 changes: 7 additions & 1 deletion lib/bundler/man/bundle-config.1
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ Cooldown filtering depends on the gem server providing a per\-version \fBcreated
.IP "\(bu" 4
\fBsystem_bindir\fR (\fBBUNDLE_SYSTEM_BINDIR\fR): The location where RubyGems installs binstubs\. Defaults to \fBGem\.bindir\fR\.
.IP "\(bu" 4
\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests\. Defaults to \fB10\fR\.
\fBtimeout\fR (\fBBUNDLE_TIMEOUT\fR): The seconds allowed before timing out for network requests, applied to each request individually\. A network operation retried by Bundler may wait a multiple of this value in total\. Defaults to \fB10\fR\.
.IP "\(bu" 4
\fBupdate_requires_all_flag\fR (\fBBUNDLE_UPDATE_REQUIRES_ALL_FLAG\fR): Require passing \fB\-\-all\fR to \fBbundle update\fR when everything should be updated, and disallow passing no options to \fBbundle update\fR\.
.IP "\(bu" 4
Expand Down Expand Up @@ -330,6 +330,12 @@ Any \fB\.\fR characters in a host name are mapped to a double underscore (\fB__\
.IP "" 0
.P
This means that if you have a gem server named \fBmy\.gem\-host\.com\fR, you'll need to use the \fBBUNDLE_MY__GEM___HOST__COM\fR variable to configure credentials for it through ENV\.
.SH "PROXY SUPPORT"
Bundler reads the proxy for a gem source from the \fB:http_proxy\fR key in the RubyGems configuration file (\fB~/\.gemrc\fR), falling back to the environment\. For an \fBhttps\fR source, \fBhttps_proxy\fR (or \fBHTTPS_PROXY\fR) takes precedence over \fBhttp_proxy\fR (or \fBHTTP_PROXY\fR), which is only used when no https\-specific proxy is set\. Proxy credentials that are not embedded in the proxy URL are read from \fBHTTP_PROXY_USER\fR and \fBHTTP_PROXY_PASS\fR, or from \fBHTTPS_PROXY_USER\fR and \fBHTTPS_PROXY_PASS\fR when the https proxy is used\.
.P
Setting \fB:http_proxy: :no_proxy\fR in the RubyGems configuration file disables proxies entirely, including any proxy environment variables\. To keep using a proxy from the environment, remove that line\. To configure a proxy in the file, replace \fB:no_proxy\fR with an explicit proxy URL\.
.P
The \fBNO_PROXY\fR (or \fBno_proxy\fR) environment variable lists hosts that are reached directly, bypassing the proxy\. An entry matches the host itself and its subdomains, so \fBNO_PROXY=example\.com\fR bypasses both \fBexample\.com\fR and \fBsub\.example\.com\fR, but not \fBmyexample\.com\fR\. An entry starting with a dot matches only subdomains\. A value of \fB*\fR bypasses the proxy for every host\.
.SH "CONFIGURE BUNDLER DIRECTORIES"
Bundler's home, cache and plugin directories and config file can be configured through environment variables\. The default location for Bundler's home directory is \fB~/\.bundle\fR, which all directories inherit from by default\. The following outlines the available environment variables and their default values
.IP "" 4
Expand Down
Loading