mirror of
https://github.com/ruby/ruby.git
synced 2025-09-15 16:44:01 +02:00

Avoid checking interrupt when loading iseq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interrupt check will unintentionally release the VM lock when loading an iseq. And this will cause issues with the `debug` gem's [`ObjectSpace.each_iseq` method](0fcfc28aca/ext/debug/iseq_collector.c (L61-L67)
), which wraps iseqs with a wrapper and exposes their internal states when they're actually not ready to be used. And when that happens, errors like this would occur and kill the `debug` gem's thread: ``` DEBUGGER: ReaderThreadError: uninitialized InstructionSequence ┃ DEBUGGER: Disconnected. ┃ ["/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:247:in `absolute_path'", ┃ "/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:247:in `block in iterate_iseq'", ┃ "/opt/rubies/ruby-3.2.0/lib/ruby/gems/3.2.0/gems/debug-1.7.1/lib/debug/breakpoint.rb:246:in `each_iseq'", ... ``` A way to reproduce the issue is to satisfy these conditions at the same time: 1. `debug` gem calling `ObjectSpace.each_iseq` (e.g. [activating a `LineBreakpoint`](0fcfc28aca/lib/debug/breakpoint.rb (L246)
)). 2. A large amount of iseq being loaded from another thread (possibly through the `bootsnap` gem). 3. 1 and 2 iterating through the same iseq(s) at the same time. Because this issue requires external dependencies and a rather complicated timing setup to reproduce, I wasn't able to write a test case for it. But here's some pseudo code to help reproduce it: ```rb require "debug/session" Thread.new do 100.times do ObjectSpace.each_iseq do |iseq| iseq.absolute_path end end end sleep 0.1 load_a_bunch_of_iseq possibly_through_bootsnap ``` [Bug #19348] Co-authored-by: Peter Zhu <peter@peterzhu.ca> --- compile.c | 2 +- vm_core.h | 1 + vm_insnhelper.c | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-)
65 lines
2.3 KiB
C
65 lines
2.3 KiB
C
#ifndef RUBY_TOPLEVEL_VERSION_H /*-*-C-*-vi:se ft=c:*/
|
|
#define RUBY_TOPLEVEL_VERSION_H
|
|
/**
|
|
* @author Ruby developers <ruby-core@ruby-lang.org>
|
|
* @copyright This file is a part of the programming language Ruby.
|
|
* Permission is hereby granted, to either redistribute and/or
|
|
* modify this file, provided that the conditions mentioned in the
|
|
* file COPYING are met. Consult the file for details.
|
|
*/
|
|
# define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR
|
|
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
|
#define RUBY_VERSION_TEENY 0
|
|
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
|
#define RUBY_PATCHLEVEL 19
|
|
|
|
#include "ruby/version.h"
|
|
#include "ruby/internal/abi.h"
|
|
|
|
#ifndef RUBY_REVISION
|
|
#include "revision.h"
|
|
|
|
#ifndef TOKEN_PASTE
|
|
#define TOKEN_PASTE(x,y) x##y
|
|
#endif
|
|
#define ONLY_ONE_DIGIT(x) TOKEN_PASTE(10,x) < 1000
|
|
#define WITH_ZERO_PADDING(x) TOKEN_PASTE(0,x)
|
|
#define RUBY_BIRTH_YEAR_STR STRINGIZE(RUBY_BIRTH_YEAR)
|
|
#define RUBY_RELEASE_YEAR_STR STRINGIZE(RUBY_RELEASE_YEAR)
|
|
#if ONLY_ONE_DIGIT(RUBY_RELEASE_MONTH)
|
|
#define RUBY_RELEASE_MONTH_STR STRINGIZE(WITH_ZERO_PADDING(RUBY_RELEASE_MONTH))
|
|
#else
|
|
#define RUBY_RELEASE_MONTH_STR STRINGIZE(RUBY_RELEASE_MONTH)
|
|
#endif
|
|
#if ONLY_ONE_DIGIT(RUBY_RELEASE_DAY)
|
|
#define RUBY_RELEASE_DAY_STR STRINGIZE(WITH_ZERO_PADDING(RUBY_RELEASE_DAY))
|
|
#else
|
|
#define RUBY_RELEASE_DAY_STR STRINGIZE(RUBY_RELEASE_DAY)
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifdef RUBY_ABI_VERSION
|
|
# define RUBY_ABI_VERSION_SUFFIX "+"STRINGIZE(RUBY_ABI_VERSION)
|
|
#else
|
|
# define RUBY_ABI_VERSION_SUFFIX ""
|
|
#endif
|
|
#if !defined RUBY_LIB_VERSION && defined RUBY_LIB_VERSION_STYLE
|
|
# if RUBY_LIB_VERSION_STYLE == 3
|
|
# define RUBY_LIB_VERSION STRINGIZE(RUBY_API_VERSION_MAJOR)"."STRINGIZE(RUBY_API_VERSION_MINOR) \
|
|
"."STRINGIZE(RUBY_API_VERSION_TEENY) RUBY_ABI_VERSION_SUFFIX
|
|
# elif RUBY_LIB_VERSION_STYLE == 2
|
|
# define RUBY_LIB_VERSION STRINGIZE(RUBY_API_VERSION_MAJOR)"."STRINGIZE(RUBY_API_VERSION_MINOR) \
|
|
RUBY_ABI_VERSION_SUFFIX
|
|
# endif
|
|
#endif
|
|
|
|
#if RUBY_PATCHLEVEL == -1
|
|
#define RUBY_PATCHLEVEL_STR "dev"
|
|
#elif defined RUBY_ABI_VERSION
|
|
#error RUBY_ABI_VERSION is defined in non-development branch
|
|
#else
|
|
#define RUBY_PATCHLEVEL_STR ""
|
|
#endif
|
|
|
|
#endif /* RUBY_TOPLEVEL_VERSION_H */
|