import UBI ruby-3.0.7-165.el9_5

This commit is contained in:
eabdullin 2025-05-06 02:37:40 +00:00
parent b905eb2d00
commit 87ae0a7ca0
7 changed files with 1520 additions and 1 deletions

View File

@ -0,0 +1,283 @@
From ec992161c3ca346061fb5b1b9c44402a03105b79 Mon Sep 17 00:00:00 2001
From: Jarek Prokop <jprokop@redhat.com>
Date: Wed, 22 Jun 2022 01:03:49 +0200
Subject: [PATCH] Detect compaction support during runtime.
The patch is created by backporting 3 commits from
the upstream Ruby master branch in the chronological order below.
https://github.com/ruby/ruby/commit/52d42e702375446746164a0251e1a10bce813b78
https://github.com/ruby/ruby/commit/79eaaf2d0b641710613f16525e4b4c439dfe854e
https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20
== How to create this patch ==
Download Ruby source code.
```
$ git clone https://github.com/ruby/ruby.git
$ cd ruby
```
First create a commit squashed from the 3 commits above.
Checkout the second commmit above, and create a temporary branch.
```
$ git checkout 79eaaf2d0b641710613f16525e4b4c439dfe854e
$ git checkout -b wip/detect-compaction-runtime-tmp
```
Cherry pick the third commit on the second commit.
```
$ git cherry-pick 2c190863239bee3f54cfb74b16bb6ea4cae6ed20
```
Squash the last 3 commits on the branch.
```
$ git rebase -i 2223eb082afa6d05321b69df783d4133b9aacba6
```
Then checkout Ruby 3.1.2 branch.
Create a new branch.
Merge the Fedora Ruby's
ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch.
```
$ git checkout v3_1_2
$ git checkout -b wip/detect-compaction-runtime
$ patch -p1 <
~/fed/ruby/ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch
$ git add gc.c gc.rb test/ruby/test_gc_compact.rb
$ git commit
```
Merge the squashed one commit on the
`wip/detect-compaction-runtime-tmp` branch
into the `wip/detect-compaction-runtime` branch.
```
$ git cherry-pick <the squashed commit above>
```
Fix conflicts seeing the difference by `git show <the squashed commit
above>`
on another terminal.
```
$ vi gc.c
$ git add gc.c
$ git commit
```
== Notes for the patch ==
```
+# define GC_COMPACTION_SUPPORTED (GC_CAN_COMPILE_COMPACTION && USE_MMAP_ALIGNED_ALLOC)
```
We use the USE_MMAP_ALIGNED_ALLOC instead of HEAP_PAGE_ALLOC_USE_MMAP on
the line above. Because while the Ruby on the master branch replaced the
USE_MMAP_ALIGNED_ALLOC with HEAP_PAGE_ALLOC_USE_MMAP, Ruby 3.1.2 doesn't.
See <https://github.com/ruby/ruby/commit/fe21b7794af0cdb7ebd502e2c0da38c68fd89839>.
```
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
```
We added the line in the case that GC_COMPACTION_SUPPORTED is true.
Because while the Ruby on the master branch defines the
GC.verify_compaction_references in the gc.rb in
the case that GC_COMPACTION_SUPPORTED is true, Ruby 3.1.2
doesn't define it in the gc.rb.
See <https://github.com/ruby/ruby/commit/b96a3a6fd2093e1dbea5491c002da515652dd347>.
```
+ OPT(GC_COMPACTION_SUPPORTED);
```
We added the line to expose the C macro to Ruby level.
In Ruby the macro existance can then be checked like so:
```Ruby
GC::OPTS.include?("GC_COMPACTION_SUPPORTED")
```
It will return `true` if the GC_COMPACTION_SUPPORTED evaluates to `true` on the
C level, `false` otherwise.
See <https://github.com/ruby/ruby/blob/b96a3a6fd2093e1dbea5491c002da515652dd347/gc.c#L14091>
== Original commit messages ==
This is a combination of 3 commits.
This is the 1st commit message:
~~~
Rename GC_COMPACTION_SUPPORTED
Naming this macro GC_COMPACTION_SUPPORTED is misleading because it
only checks whether compaction is supported at compile time.
[Bug #18829]
~~~
This is the commit message #2:
~~~
Include runtime checks for compaction support
Commit 0c36ba53192c5a0d245c9b626e4346a32d7d144e changed GC compaction
methods to not be implemented when not supported. However, that commit
only does compile time checks (which currently only checks for WASM),
but there are additional compaction support checks during run time.
This commit changes it so that GC compaction methods aren't defined
during run time if the platform does not support GC compaction.
[Bug #18829]
~~~
This is the commit message #3:
~~~
Suppress code unused unless GC_CAN_COMPILE_COMPACTION
~~~
---
gc.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 46 insertions(+), 12 deletions(-)
diff --git a/gc.c b/gc.c
index 6a5c739cc4..a3e40d9aac 100644
--- a/gc.c
+++ b/gc.c
@@ -4632,7 +4632,25 @@ gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap)
static void gc_update_references(rb_objspace_t * objspace, rb_heap_t *heap);
static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page);
-static void read_barrier_handler(intptr_t address)
+#ifndef GC_CAN_COMPILE_COMPACTION
+#if defined(__wasi__) /* WebAssembly doesn't support signals */
+# define GC_CAN_COMPILE_COMPACTION 0
+#else
+# define GC_CAN_COMPILE_COMPACTION 1
+#endif
+#endif
+
+#if defined(__MINGW32__) || defined(_WIN32)
+# define GC_COMPACTION_SUPPORTED 1
+#else
+/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
+ * the read barrier, so we must disable compaction. */
+# define GC_COMPACTION_SUPPORTED (GC_CAN_COMPILE_COMPACTION && USE_MMAP_ALIGNED_ALLOC)
+#endif
+
+#if GC_CAN_COMPILE_COMPACTION
+static void
+read_barrier_handler(uintptr_t address)
{
VALUE obj;
rb_objspace_t * objspace = &rb_objspace;
@@ -4651,6 +4669,7 @@ static void read_barrier_handler(intptr_t address)
}
RB_VM_LOCK_LEAVE();
}
+#endif
#if defined(_WIN32)
static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
@@ -8562,6 +8581,8 @@ gc_start_internal(rb_execution_context_t *ec, VALUE self, VALUE full_mark, VALUE
/* For now, compact implies full mark / sweep, so ignore other flags */
if (RTEST(compact)) {
+ GC_ASSERT(GC_COMPACTION_SUPPORTED);
+
/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
* the read barrier, so we must disable compaction. */
#if !defined(__MINGW32__) && !defined(_WIN32)
@@ -8732,7 +8753,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free)
return (VALUE)src;
}
-#if GC_COMPACTION_SUPPORTED
+#if GC_CAN_COMPILE_COMPACTION
static int
compare_free_slots(const void *left, const void *right, void *dummy)
{
@@ -9412,7 +9433,7 @@ gc_update_references(rb_objspace_t * objspace, rb_heap_t *heap)
static VALUE type_sym(size_t type);
-#if GC_COMPACTION_SUPPORTED
+#if GC_CAN_COMPILE_COMPACTION
/*
* call-seq:
* GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
@@ -9453,7 +9474,7 @@ gc_compact_stats(VALUE self)
# define gc_compact_stats rb_f_notimplement
#endif
-#if GC_COMPACTION_SUPPORTED
+#if GC_CAN_COMPILE_COMPACTION
static void
root_obj_check_moved_i(const char *category, VALUE obj, void *data)
{
@@ -9532,7 +9553,7 @@ gc_compact(VALUE self)
# define gc_compact rb_f_notimplement
#endif
-#if GC_COMPACTION_SUPPORTED
+#if GC_CAN_COMPILE_COMPACTION
/*
* call-seq:
* GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
@@ -10056,7 +10077,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
return rb_gc_disable();
}
-#if GC_COMPACTION_SUPPORTED
+#if GC_CAN_COMPILE_COMPACTION
/*
* call-seq:
* GC.auto_compact = flag
@@ -10077,6 +10098,7 @@ gc_set_auto_compact(VALUE _, VALUE v)
rb_raise(rb_eNotImpError, "Automatic compaction isn't available on this platform");
}
#endif
+ GC_ASSERT(GC_COMPACTION_SUPPORTED);
ruby_enable_autocompact = RTEST(v);
return v;
@@ -10085,7 +10107,8 @@ gc_set_auto_compact(VALUE _, VALUE v)
# define gc_set_auto_compact rb_f_notimplement
#endif
-#if GC_COMPACTION_SUPPORTED
+
+#if GC_CAN_COMPILE_COMPACTION
/*
* call-seq:
* GC.auto_compact -> true or false
@@ -12926,11 +12949,21 @@ Init_GC(void)
rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
#endif
- rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
- rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
- rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
- rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
- rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
+ if (GC_COMPACTION_SUPPORTED) {
+ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
+ }
+ else {
+ rb_define_singleton_method(rb_mGC, "compact", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact", rb_f_notimplement, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact=", rb_f_notimplement, 1);
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", rb_f_notimplement, 0);
+ /* When !GC_COMPACTION_SUPPORTED, this method is not defined in gc.rb */
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", rb_f_notimplement, -1);
+ }
#if GC_DEBUG_STRESS_TO_CLASS
rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
@@ -12954,6 +12987,7 @@ Init_GC(void)
OPT(MALLOC_ALLOCATED_SIZE);
OPT(MALLOC_ALLOCATED_SIZE_CHECK);
OPT(GC_PROFILE_DETAIL_MEMORY);
+ OPT(GC_COMPACTION_SUPPORTED);
#undef OPT
OBJ_FREEZE(opts);
}

View File

@ -0,0 +1,493 @@
From 2b48aa5d9d7bfcf80ea23c352ceb10f0cf4e4ee0 Mon Sep 17 00:00:00 2001
From: Mike Dalessio <mike.dalessio@gmail.com>
Date: Mon, 23 May 2022 15:40:22 -0400
Subject: [PATCH 1/2] Move compaction-related methods into gc.c
These methods are removed from gc.rb and added to gc.c:
- GC.compact
- GC.auto_compact
- GC.auto_compact=
- GC.latest_compact_info
- GC.verify_compaction_references
This is a prefactor to allow setting these methods to
`rb_f_notimplement` in a followup commit.
---
gc.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
gc.rb | 68 ---------------------------------------
2 files changed, 91 insertions(+), 78 deletions(-)
diff --git a/gc.c b/gc.c
index b821310934..ef0e66ee46 100644
--- a/gc.c
+++ b/gc.c
@@ -9410,8 +9410,20 @@ gc_update_references(rb_objspace_t * objspace, rb_heap_t *heap)
static VALUE type_sym(size_t type);
+/*
+ * call-seq:
+ * GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
+ *
+ * Returns information about object moved in the most recent GC compaction.
+ *
+ * The returned hash has two keys :considered and :moved. The hash for
+ * :considered lists the number of objects that were considered for movement
+ * by the compactor, and the :moved hash lists the number of objects that
+ * were actually moved. Some objects can't be moved (maybe they were pinned)
+ * so these numbers can be used to calculate compaction efficiency.
+ */
static VALUE
-gc_compact_stats(rb_execution_context_t *ec, VALUE self)
+gc_compact_stats(VALUE self)
{
size_t i;
rb_objspace_t *objspace = &rb_objspace;
@@ -9484,22 +9496,70 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data)
return 0;
}
+/*
+ * call-seq:
+ * GC.compact
+ *
+ * This function compacts objects together in Ruby's heap. It eliminates
+ * unused space (or fragmentation) in the heap by moving objects in to that
+ * unused space. This function returns a hash which contains statistics about
+ * which objects were moved. See `GC.latest_gc_info` for details about
+ * compaction statistics.
+ *
+ * This method is implementation specific and not expected to be implemented
+ * in any implementation besides MRI.
+ */
static VALUE
-gc_compact(rb_execution_context_t *ec, VALUE self)
+gc_compact(VALUE self)
{
/* Run GC with compaction enabled */
- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue);
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
- return gc_compact_stats(ec, self);
+ return gc_compact_stats(self);
}
+/*
+ * call-seq:
+ * GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
+ *
+ * Verify compaction reference consistency.
+ *
+ * This method is implementation specific. During compaction, objects that
+ * were moved are replaced with T_MOVED objects. No object should have a
+ * reference to a T_MOVED object after compaction.
+ *
+ * This function doubles the heap to ensure room to move all objects,
+ * compacts the heap to make sure everything moves, updates all references,
+ * then performs a full GC. If any object contains a reference to a T_MOVED
+ * object, that object should be pushed on the mark stack, and will
+ * make a SEGV.
+ */
static VALUE
-gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE double_heap, VALUE toward_empty)
+gc_verify_compaction_references(int argc, VALUE *argv, VALUE self)
{
rb_objspace_t *objspace = &rb_objspace;
+ VALUE kwargs, double_heap = Qfalse, toward_empty = Qfalse;
+ static ID id_toward, id_double_heap, id_empty;
+
+ if (!id_toward) {
+ id_toward = rb_intern("toward");
+ id_double_heap = rb_intern("double_heap");
+ id_empty = rb_intern("empty");
+ }
+
+ rb_scan_args(argc, argv, ":", &kwargs);
+ if (!NIL_P(kwargs)) {
+ if (rb_hash_has_key(kwargs, ID2SYM(id_toward))) {
+ VALUE toward = rb_hash_aref(kwargs, ID2SYM(id_toward));
+ toward_empty = (toward == ID2SYM(id_empty)) ? Qtrue : Qfalse;
+ }
+ if (rb_hash_has_key(kwargs, ID2SYM(id_double_heap))) {
+ double_heap = rb_hash_aref(kwargs, ID2SYM(id_double_heap));
+ }
+ }
/* Clear the heap. */
- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qfalse);
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qfalse);
RB_VM_LOCK_ENTER();
{
@@ -9515,12 +9575,12 @@ gc_verify_compaction_references(rb_execution_context_t *ec, VALUE self, VALUE do
}
RB_VM_LOCK_LEAVE();
- gc_start_internal(ec, self, Qtrue, Qtrue, Qtrue, Qtrue);
+ gc_start_internal(NULL, self, Qtrue, Qtrue, Qtrue, Qtrue);
objspace_reachable_objects_from_root(objspace, root_obj_check_moved_i, NULL);
objspace_each_objects(objspace, heap_check_moved_i, NULL);
- return gc_compact_stats(ec, self);
+ return gc_compact_stats(self);
}
VALUE
@@ -9978,8 +10038,18 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
return rb_gc_disable();
}
+/*
+ * call-seq:
+ * GC.auto_compact = flag
+ *
+ * Updates automatic compaction mode.
+ *
+ * When enabled, the compactor will execute on every major collection.
+ *
+ * Enabling compaction will degrade performance on major collections.
+ */
static VALUE
-gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v)
+gc_set_auto_compact(VALUE _, VALUE v)
{
/* If not MinGW, Windows, or does not have mmap, we cannot use mprotect for
* the read barrier, so we must disable automatic compaction. */
@@ -9993,8 +10063,14 @@ gc_set_auto_compact(rb_execution_context_t *ec, VALUE _, VALUE v)
return v;
}
+/*
+ * call-seq:
+ * GC.auto_compact -> true or false
+ *
+ * Returns whether or not automatic compaction has been enabled.
+ */
static VALUE
-gc_get_auto_compact(rb_execution_context_t *ec, VALUE _)
+gc_get_auto_compact(VALUE _)
{
return ruby_enable_autocompact ? Qtrue : Qfalse;
}
@@ -12824,6 +12900,11 @@ Init_GC(void)
rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0);
rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0);
#endif
+ rb_define_singleton_method(rb_mGC, "compact", gc_compact, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact", gc_get_auto_compact, 0);
+ rb_define_singleton_method(rb_mGC, "auto_compact=", gc_set_auto_compact, 1);
+ rb_define_singleton_method(rb_mGC, "latest_compact_info", gc_compact_stats, 0);
+ rb_define_singleton_method(rb_mGC, "verify_compaction_references", gc_verify_compaction_references, -1);
#if GC_DEBUG_STRESS_TO_CLASS
rb_define_singleton_method(rb_mGC, "add_stress_to_class", rb_gcdebug_add_stress_to_class, -1);
diff --git a/gc.rb b/gc.rb
index 8a00b406ce..4a80e09443 100644
--- a/gc.rb
+++ b/gc.rb
@@ -38,27 +38,6 @@ def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
end
- # call-seq:
- # GC.auto_compact -> true or false
- #
- # Returns whether or not automatic compaction has been enabled.
- #
- def self.auto_compact
- Primitive.gc_get_auto_compact
- end
-
- # call-seq:
- # GC.auto_compact = flag
- #
- # Updates automatic compaction mode.
- #
- # When enabled, the compactor will execute on every major collection.
- #
- # Enabling compaction will degrade performance on major collections.
- def self.auto_compact=(flag)
- Primitive.gc_set_auto_compact(flag)
- end
-
# call-seq:
# GC.enable -> true or false
#
@@ -183,53 +162,6 @@ def self.stat hash_or_key = nil
def self.latest_gc_info hash_or_key = nil
Primitive.gc_latest_gc_info hash_or_key
end
-
- # call-seq:
- # GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
- #
- # Returns information about object moved in the most recent GC compaction.
- #
- # The returned hash has two keys :considered and :moved. The hash for
- # :considered lists the number of objects that were considered for movement
- # by the compactor, and the :moved hash lists the number of objects that
- # were actually moved. Some objects can't be moved (maybe they were pinned)
- # so these numbers can be used to calculate compaction efficiency.
- def self.latest_compact_info
- Primitive.gc_compact_stats
- end
-
- # call-seq:
- # GC.compact
- #
- # This function compacts objects together in Ruby's heap. It eliminates
- # unused space (or fragmentation) in the heap by moving objects in to that
- # unused space. This function returns a hash which contains statistics about
- # which objects were moved. See `GC.latest_gc_info` for details about
- # compaction statistics.
- #
- # This method is implementation specific and not expected to be implemented
- # in any implementation besides MRI.
- def self.compact
- Primitive.gc_compact
- end
-
- # call-seq:
- # GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
- #
- # Verify compaction reference consistency.
- #
- # This method is implementation specific. During compaction, objects that
- # were moved are replaced with T_MOVED objects. No object should have a
- # reference to a T_MOVED object after compaction.
- #
- # This function doubles the heap to ensure room to move all objects,
- # compacts the heap to make sure everything moves, updates all references,
- # then performs a full GC. If any object contains a reference to a T_MOVED
- # object, that object should be pushed on the mark stack, and will
- # make a SEGV.
- def self.verify_compaction_references(toward: nil, double_heap: false)
- Primitive.gc_verify_compaction_references(double_heap, toward == :empty)
- end
end
module ObjectSpace
From 5c73c78da0ffca162b2dad6f217ae0ec1565ad52 Mon Sep 17 00:00:00 2001
From: Mike Dalessio <mike.dalessio@gmail.com>
Date: Mon, 23 May 2022 17:31:14 -0400
Subject: [PATCH 2/2] Define unsupported GC compaction methods as
rb_f_notimplement
Fixes [Bug #18779]
Define the following methods as `rb_f_notimplement` on unsupported
platforms:
- GC.compact
- GC.auto_compact
- GC.auto_compact=
- GC.latest_compact_info
- GC.verify_compaction_references
This change allows users to call `GC.respond_to?(:compact)` to
properly test for compaction support. Previously, it was necessary to
invoke `GC.compact` or `GC.verify_compaction_references` and check if
those methods raised `NotImplementedError` to determine if compaction
was supported.
This follows the precedent set for other platform-specific
methods. For example, in `process.c` for methods such as
`Process.fork`, `Process.setpgid`, and `Process.getpriority`.
---
gc.c | 26 ++++++++++++++++
test/ruby/test_gc_compact.rb | 58 ++++++++++++++++++++++++++----------
2 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/gc.c b/gc.c
index ef0e66ee46..6a5c739cc4 100644
--- a/gc.c
+++ b/gc.c
@@ -8732,6 +8732,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free)
return (VALUE)src;
}
+#if GC_COMPACTION_SUPPORTED
static int
compare_free_slots(const void *left, const void *right, void *dummy)
{
@@ -8775,6 +8776,7 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace)
free(page_list);
}
+#endif
static void
gc_ref_update_array(rb_objspace_t * objspace, VALUE v)
@@ -9410,6 +9412,7 @@ gc_update_references(rb_objspace_t * objspace, rb_heap_t *heap)
static VALUE type_sym(size_t type);
+#if GC_COMPACTION_SUPPORTED
/*
* call-seq:
* GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
@@ -9446,7 +9449,11 @@ gc_compact_stats(VALUE self)
return h;
}
+#else
+# define gc_compact_stats rb_f_notimplement
+#endif
+#if GC_COMPACTION_SUPPORTED
static void
root_obj_check_moved_i(const char *category, VALUE obj, void *data)
{
@@ -9508,6 +9515,10 @@ heap_check_moved_i(void *vstart, void *vend, size_t stride, void *data)
*
* This method is implementation specific and not expected to be implemented
* in any implementation besides MRI.
+ *
+ * To test whether GC compaction is supported, use the idiom:
+ *
+ * GC.respond_to?(:compact)
*/
static VALUE
gc_compact(VALUE self)
@@ -9517,7 +9528,11 @@ gc_compact(VALUE self)
return gc_compact_stats(self);
}
+#else
+# define gc_compact rb_f_notimplement
+#endif
+#if GC_COMPACTION_SUPPORTED
/*
* call-seq:
* GC.verify_compaction_references(toward: nil, double_heap: false) -> hash
@@ -9582,6 +9597,9 @@ gc_verify_compaction_references(int argc, VALUE *argv, VALUE self)
return gc_compact_stats(self);
}
+#else
+# define gc_verify_compaction_references rb_f_notimplement
+#endif
VALUE
rb_gc_start(void)
@@ -10038,6 +10056,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
return rb_gc_disable();
}
+#if GC_COMPACTION_SUPPORTED
/*
* call-seq:
* GC.auto_compact = flag
@@ -10062,7 +10081,11 @@ gc_set_auto_compact(VALUE _, VALUE v)
ruby_enable_autocompact = RTEST(v);
return v;
}
+#else
+# define gc_set_auto_compact rb_f_notimplement
+#endif
+#if GC_COMPACTION_SUPPORTED
/*
* call-seq:
* GC.auto_compact -> true or false
@@ -10074,6 +10097,9 @@ gc_get_auto_compact(VALUE _)
{
return ruby_enable_autocompact ? Qtrue : Qfalse;
}
+#else
+# define gc_get_auto_compact rb_f_notimplement
+#endif
static int
get_envparam_size(const char *name, size_t *default_value, size_t lower_bound)
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
index f5cab55ba7..c9c96a7c9c 100644
--- a/test/ruby/test_gc_compact.rb
+++ b/test/ruby/test_gc_compact.rb
@@ -4,14 +4,7 @@
require 'etc'
class TestGCCompact < Test::Unit::TestCase
- module SupportsCompact
- def setup
- skip "autocompact not supported on this platform" unless supports_auto_compact?
- super
- end
-
- private
-
+ module CompactionSupportInspector
def supports_auto_compact?
return true unless defined?(Etc::SC_PAGE_SIZE)
@@ -25,10 +18,19 @@ def supports_auto_compact?
end
end
- include SupportsCompact
+ module OmitUnlessCompactSupported
+ include CompactionSupportInspector
+
+ def setup
+ omit "autocompact not supported on this platform" unless supports_auto_compact?
+ super
+ end
+ end
+
+ include OmitUnlessCompactSupported
class AutoCompact < Test::Unit::TestCase
- include SupportsCompact
+ include OmitUnlessCompactSupported
def test_enable_autocompact
before = GC.auto_compact
@@ -81,13 +83,39 @@ def test_implicit_compaction_does_something
end
end
- def os_page_size
- return true unless defined?(Etc::SC_PAGE_SIZE)
+ class CompactMethodsNotImplemented < Test::Unit::TestCase
+ include CompactionSupportInspector
+
+ def assert_not_implemented(method, *args)
+ omit "autocompact is supported on this platform" if supports_auto_compact?
+
+ assert_raise(NotImplementedError) { GC.send(method, *args) }
+ refute(GC.respond_to?(method), "GC.#{method} should be defined as rb_f_notimplement")
+ end
+
+ def test_gc_compact_not_implemented
+ assert_not_implemented(:compact)
+ end
+
+ def test_gc_auto_compact_get_not_implemented
+ assert_not_implemented(:auto_compact)
+ end
+
+ def test_gc_auto_compact_set_not_implemented
+ assert_not_implemented(:auto_compact=, true)
+ end
+
+ def test_gc_latest_compact_info_not_implemented
+ assert_not_implemented(:latest_compact_info)
+ end
+
+ def test_gc_verify_compaction_references_not_implemented
+ assert_not_implemented(:verify_compaction_references)
+ end
end
- def setup
- skip "autocompact not supported on this platform" unless supports_auto_compact?
- super
+ def os_page_size
+ return true unless defined?(Etc::SC_PAGE_SIZE)
end
def test_gc_compact_stats

View File

@ -0,0 +1,336 @@
--- ruby-3.0.7/gc.rbinc 2024-04-23 12:23:28.000000000 +0200
+++ ruby/gc.rbinc 2025-02-27 13:20:54.803133890 +0100
@@ -26,31 +26,6 @@
}
static void
-mjit_compile_invokebuiltin_for_gc_get_auto_compact(FILE *f, long index, unsigned stack_size, bool inlinable_p)
-{
- fprintf(f, " VALUE self = GET_SELF();\n");
- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n");
- fprintf(f, " func f = (func)%"PRIdPTR"; /* == gc_get_auto_compact */\n", (intptr_t)gc_get_auto_compact);
- fprintf(f, " val = f(ec, self);\n");
-}
-
-static void
-mjit_compile_invokebuiltin_for_gc_set_auto_compact(FILE *f, long index, unsigned stack_size, bool inlinable_p)
-{
- fprintf(f, " VALUE self = GET_SELF();\n");
- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE, VALUE);\n");
- if (index == -1) {
- fprintf(f, " const VALUE *argv = &stack[%d];\n", stack_size - 1);
- }
- else {
- fprintf(f, " const unsigned int lnum = GET_ISEQ()->body->local_table_size;\n");
- fprintf(f, " const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\n", index);
- }
- fprintf(f, " func f = (func)%"PRIdPTR"; /* == gc_set_auto_compact */\n", (intptr_t)gc_set_auto_compact);
- fprintf(f, " val = f(ec, self, argv[0]);\n");
-}
-
-static void
mjit_compile_invokebuiltin_for_gc_enable(FILE *f, long index, unsigned stack_size, bool inlinable_p)
{
fprintf(f, " VALUE self = GET_SELF();\n");
@@ -134,57 +109,18 @@
fprintf(f, " val = f(ec, self, argv[0]);\n");
}
-static void
-mjit_compile_invokebuiltin_for_gc_compact_stats(FILE *f, long index, unsigned stack_size, bool inlinable_p)
-{
- fprintf(f, " VALUE self = GET_SELF();\n");
- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n");
- fprintf(f, " func f = (func)%"PRIdPTR"; /* == gc_compact_stats */\n", (intptr_t)gc_compact_stats);
- fprintf(f, " val = f(ec, self);\n");
-}
-
-static void
-mjit_compile_invokebuiltin_for_gc_compact(FILE *f, long index, unsigned stack_size, bool inlinable_p)
-{
- fprintf(f, " VALUE self = GET_SELF();\n");
- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE);\n");
- fprintf(f, " func f = (func)%"PRIdPTR"; /* == gc_compact */\n", (intptr_t)gc_compact);
- fprintf(f, " val = f(ec, self);\n");
-}
-
-static void
-mjit_compile_invokebuiltin_for_gc_verify_compaction_references(FILE *f, long index, unsigned stack_size, bool inlinable_p)
-{
- fprintf(f, " VALUE self = GET_SELF();\n");
- fprintf(f, " typedef VALUE (*func)(rb_execution_context_t *, VALUE, VALUE, VALUE);\n");
- if (index == -1) {
- fprintf(f, " const VALUE *argv = &stack[%d];\n", stack_size - 2);
- }
- else {
- fprintf(f, " const unsigned int lnum = GET_ISEQ()->body->local_table_size;\n");
- fprintf(f, " const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\n", index);
- }
- fprintf(f, " func f = (func)%"PRIdPTR"; /* == gc_verify_compaction_references */\n", (intptr_t)gc_verify_compaction_references);
- fprintf(f, " val = f(ec, self, argv[0], argv[1]);\n");
-}
-
void Init_builtin_gc(void)
{
// table definition
static const struct rb_builtin_function gc_table[] = {
RB_BUILTIN_FUNCTION(0, gc_start_internal, gc_start_internal, 4, mjit_compile_invokebuiltin_for_gc_start_internal),
- RB_BUILTIN_FUNCTION(1, gc_get_auto_compact, gc_get_auto_compact, 0, mjit_compile_invokebuiltin_for_gc_get_auto_compact),
- RB_BUILTIN_FUNCTION(2, gc_set_auto_compact, gc_set_auto_compact, 1, mjit_compile_invokebuiltin_for_gc_set_auto_compact),
- RB_BUILTIN_FUNCTION(3, gc_enable, gc_enable, 0, mjit_compile_invokebuiltin_for_gc_enable),
- RB_BUILTIN_FUNCTION(4, gc_disable, gc_disable, 0, mjit_compile_invokebuiltin_for_gc_disable),
- RB_BUILTIN_FUNCTION(5, gc_stress_get, gc_stress_get, 0, mjit_compile_invokebuiltin_for_gc_stress_get),
- RB_BUILTIN_FUNCTION(6, gc_stress_set_m, gc_stress_set_m, 1, mjit_compile_invokebuiltin_for_gc_stress_set_m),
- RB_BUILTIN_FUNCTION(7, gc_count, gc_count, 0, mjit_compile_invokebuiltin_for_gc_count),
- RB_BUILTIN_FUNCTION(8, gc_stat, gc_stat, 1, mjit_compile_invokebuiltin_for_gc_stat),
- RB_BUILTIN_FUNCTION(9, gc_latest_gc_info, gc_latest_gc_info, 1, mjit_compile_invokebuiltin_for_gc_latest_gc_info),
- RB_BUILTIN_FUNCTION(10, gc_compact_stats, gc_compact_stats, 0, mjit_compile_invokebuiltin_for_gc_compact_stats),
- RB_BUILTIN_FUNCTION(11, gc_compact, gc_compact, 0, mjit_compile_invokebuiltin_for_gc_compact),
- RB_BUILTIN_FUNCTION(12, gc_verify_compaction_references, gc_verify_compaction_references, 2, mjit_compile_invokebuiltin_for_gc_verify_compaction_references),
+ RB_BUILTIN_FUNCTION(1, gc_enable, gc_enable, 0, mjit_compile_invokebuiltin_for_gc_enable),
+ RB_BUILTIN_FUNCTION(2, gc_disable, gc_disable, 0, mjit_compile_invokebuiltin_for_gc_disable),
+ RB_BUILTIN_FUNCTION(3, gc_stress_get, gc_stress_get, 0, mjit_compile_invokebuiltin_for_gc_stress_get),
+ RB_BUILTIN_FUNCTION(4, gc_stress_set_m, gc_stress_set_m, 1, mjit_compile_invokebuiltin_for_gc_stress_set_m),
+ RB_BUILTIN_FUNCTION(5, gc_count, gc_count, 0, mjit_compile_invokebuiltin_for_gc_count),
+ RB_BUILTIN_FUNCTION(6, gc_stat, gc_stat, 1, mjit_compile_invokebuiltin_for_gc_stat),
+ RB_BUILTIN_FUNCTION(7, gc_latest_gc_info, gc_latest_gc_info, 1, mjit_compile_invokebuiltin_for_gc_latest_gc_info),
RB_BUILTIN_FUNCTION(-1, NULL, NULL, 0, 0),
};
@@ -194,8 +130,6 @@
COMPILER_WARNING_ERROR(-Wincompatible-pointer-types)
#endif
if (0) rb_builtin_function_check_arity4(gc_start_internal);
- if (0) rb_builtin_function_check_arity0(gc_get_auto_compact);
- if (0) rb_builtin_function_check_arity1(gc_set_auto_compact);
if (0) rb_builtin_function_check_arity0(gc_enable);
if (0) rb_builtin_function_check_arity0(gc_disable);
if (0) rb_builtin_function_check_arity0(gc_stress_get);
@@ -203,9 +137,6 @@
if (0) rb_builtin_function_check_arity0(gc_count);
if (0) rb_builtin_function_check_arity1(gc_stat);
if (0) rb_builtin_function_check_arity1(gc_latest_gc_info);
- if (0) rb_builtin_function_check_arity0(gc_compact_stats);
- if (0) rb_builtin_function_check_arity0(gc_compact);
- if (0) rb_builtin_function_check_arity2(gc_verify_compaction_references);
COMPILER_WARNING_POP
// load
--- ruby-3.0.7/miniprelude.c 2024-04-23 12:23:28.000000000 +0200
+++ ruby/miniprelude.c 2025-02-27 13:20:54.853135007 +0100
@@ -320,10 +320,9 @@
static const char prelude_name2[] = "<internal:gc>";
static const struct {
- char L0[489]; /* 1..58 */
- char L58[486]; /* 59..182 */
- char L182[430]; /* 183..235 */
- char L235[211]; /* 236..242 */
+ char L0[502]; /* 1..70 */
+ char L70[435]; /* 71..167 */
+ char L167[211]; /* 168..174 */
} prelude_code2 = {
#line 1 "gc.rb"
"\n"/* for gc.c */
@@ -367,29 +366,6 @@
" end\n"
"\n"
"\n"/* call-seq: */
-"\n"/* GC.auto_compact -> true or false */
-"\n"/* */
-"\n"/* Returns whether or not automatic compaction has been enabled. */
-"\n"/* */
-" def self.auto_compact\n"
-" Primitive.gc_get_auto_compact\n"
-" end\n"
-"\n"
-"\n"/* call-seq: */
-"\n"/* GC.auto_compact = flag */
-"\n"/* */
-"\n"/* Updates automatic compaction mode. */
-"\n"/* */
-"\n"/* When enabled, the compactor will execute on every major collection. */
-"\n"/* */
-"\n"/* Enabling compaction will degrade performance on major collections. */
-" def self.auto_compact=(flag)\n"
-,
-#line 59 "gc.rb"
-" Primitive.gc_set_auto_compact(flag)\n"
-" end\n"
-"\n"
-"\n"/* call-seq: */
"\n"/* GC.enable -> true or false */
"\n"/* */
"\n"/* Enables garbage collection, returning +true+ if garbage */
@@ -419,6 +395,8 @@
"\n"/* GC.stress -> integer, true or false */
"\n"/* */
"\n"/* Returns current status of GC stress mode. */
+,
+#line 71 "gc.rb"
" def self.stress\n"
" Primitive.gc_stress_get\n"
" end\n"
@@ -510,70 +488,21 @@
"\n"/* If the optional argument, hash, is given, */
"\n"/* it is overwritten and returned. */
"\n"/* This is intended to avoid probe effect. */
-,
-#line 183 "gc.rb"
" def self.latest_gc_info hash_or_key = nil\n"
" Primitive.gc_latest_gc_info hash_or_key\n"
" end\n"
-"\n"
-"\n"/* call-seq: */
-"\n"/* GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}} */
-"\n"/* */
-"\n"/* Returns information about object moved in the most recent GC compaction. */
-"\n"/* */
-"\n"/* The returned hash has two keys :considered and :moved. The hash for */
-"\n"/* :considered lists the number of objects that were considered for movement */
-"\n"/* by the compactor, and the :moved hash lists the number of objects that */
-"\n"/* were actually moved. Some objects can't be moved (maybe they were pinned) */
-"\n"/* so these numbers can be used to calculate compaction efficiency. */
-" def self.latest_compact_info\n"
-" Primitive.gc_compact_stats\n"
-" end\n"
-"\n"
-"\n"/* call-seq: */
-"\n"/* GC.compact */
-"\n"/* */
-"\n"/* This function compacts objects together in Ruby's heap. It eliminates */
-"\n"/* unused space (or fragmentation) in the heap by moving objects in to that */
-"\n"/* unused space. This function returns a hash which contains statistics about */
-"\n"/* which objects were moved. See `GC.latest_gc_info` for details about */
-"\n"/* compaction statistics. */
-"\n"/* */
-"\n"/* This method is implementation specific and not expected to be implemented */
-"\n"/* in any implementation besides MRI. */
-" def self.compact\n"
-" Primitive.gc_compact\n"
-" end\n"
-"\n"
-"\n"/* call-seq: */
-"\n"/* GC.verify_compaction_references(toward: nil, double_heap: false) -> hash */
-"\n"/* */
-"\n"/* Verify compaction reference consistency. */
-"\n"/* */
-"\n"/* This method is implementation specific. During compaction, objects that */
-"\n"/* were moved are replaced with T_MOVED objects. No object should have a */
-"\n"/* reference to a T_MOVED object after compaction. */
-"\n"/* */
-"\n"/* This function doubles the heap to ensure room to move all objects, */
-"\n"/* compacts the heap to make sure everything moves, updates all references, */
-"\n"/* then performs a full GC. If any object contains a reference to a T_MOVED */
-"\n"/* object, that object should be pushed on the mark stack, and will */
-"\n"/* make a SEGV. */
-" def self.verify_compaction_references(toward: nil, double_heap: false)\n"
-" Primitive.gc_verify_compaction_references(double_heap, toward == :empty)\n"
-" end\n"
"end\n"
"\n"
"module ObjectSpace\n"
,
-#line 236 "gc.rb"
+#line 168 "gc.rb"
" def garbage_collect full_mark: true, immediate_mark: true, immediate_sweep: true\n"
" Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false\n"
" end\n"
"\n"
" module_function :garbage_collect\n"
"end\n"
-#line 577 "miniprelude.c"
+#line 506 "miniprelude.c"
};
static const char prelude_name3[] = "<internal:integer>";
@@ -734,7 +663,7 @@
" Primitive.cexpr! 'rb_int_zero_p(self)'\n"
" end\n"
"end\n"
-#line 738 "miniprelude.c"
+#line 667 "miniprelude.c"
};
static const char prelude_name4[] = "<internal:io>";
@@ -865,7 +794,7 @@
" Primitive.io_write_nonblock(buf, exception)\n"
" end\n"
"end\n"
-#line 869 "miniprelude.c"
+#line 798 "miniprelude.c"
};
static const char prelude_name5[] = "<internal:pack>";
@@ -1156,7 +1085,7 @@
" Primitive.pack_unpack1(fmt)\n"
" end\n"
"end\n"
-#line 1160 "miniprelude.c"
+#line 1089 "miniprelude.c"
};
static const char prelude_name6[] = "<internal:trace_point>";
@@ -1521,7 +1450,7 @@
" Primitive.tracepoint_attr_instruction_sequence\n"
" end\n"
"end\n"
-#line 1525 "miniprelude.c"
+#line 1454 "miniprelude.c"
};
static const char prelude_name7[] = "<internal:warning>";
@@ -1582,7 +1511,7 @@
" Primitive.rb_warn_m(msgs, uplevel, category)\n"
" end\n"
"end\n"
-#line 1586 "miniprelude.c"
+#line 1515 "miniprelude.c"
};
static const char prelude_name8[] = "<internal:array>";
@@ -1651,7 +1580,7 @@
" Primitive.rb_ary_sample(random, n, ary)\n"
" end\n"
"end\n"
-#line 1655 "miniprelude.c"
+#line 1584 "miniprelude.c"
};
static const char prelude_name9[] = "<internal:kernel>";
@@ -1836,7 +1765,7 @@
" Primitive.rb_f_float(arg, exception)\n"
" end\n"
"end\n"
-#line 1840 "miniprelude.c"
+#line 1769 "miniprelude.c"
};
static const char prelude_name10[] = "<internal:ractor>";
@@ -2703,7 +2632,7 @@
" }\n"
" end\n"
"end\n"
-#line 2707 "miniprelude.c"
+#line 2636 "miniprelude.c"
};
static const char prelude_name11[] = "<internal:prelude>";
@@ -2733,7 +2662,7 @@
"\n"
" private :pp\n"
"end\n"
-#line 2737 "miniprelude.c"
+#line 2666 "miniprelude.c"
};
static const char prelude_name12[] = "<internal:gem_prelude>";
@@ -2752,7 +2681,7 @@
"rescue LoadError\n"
" warn \"`did_you_mean' was not loaded.\"\n"
"end if defined?(DidYouMean)\n"
-#line 2756 "miniprelude.c"
+#line 2685 "miniprelude.c"
};
COMPILER_WARNING_POP

View File

@ -0,0 +1,27 @@
From fd8162a42ff3e4004b940030cfe34ce7a44a7e23 Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Fri, 21 Feb 2025 16:01:17 +0900
Subject: [PATCH] Use String#concat instead of String#+ for reducing cpu usage
Co-authored-by: "Yusuke Endoh" <mame@ruby-lang.org>
---
lib/cgi/cookie.rb | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/cgi/cookie.rb b/lib/cgi/cookie.rb
index 1a9c1a82c1..7b8e761a94 100644
--- a/lib/cgi/cookie.rb
+++ b/lib/cgi/cookie.rb
@@ -190,9 +190,10 @@ def self.parse(raw_cookie)
values ||= ""
values = values.split('&').collect{|v| CGI.unescape(v,@@accept_charset) }
if cookies.has_key?(name)
- values = cookies[name].value + values
+ cookies[name].concat(values)
+ else
+ cookies[name] = Cookie.new(name, *values)
end
- cookies[name] = Cookie.new(name, *values)
end
cookies

View File

@ -0,0 +1,68 @@
From 725d6f699f589d9b5454e189d33292027532984d Mon Sep 17 00:00:00 2001
From: Hiroshi SHIBATA <hsbt@ruby-lang.org>
Date: Fri, 21 Feb 2025 15:53:31 +0900
Subject: [PATCH] Escape/unescape unclosed tags as well
Co-authored-by: Nobuyoshi Nakada <nobu@ruby-lang.org>
---
lib/cgi/util.rb | 4 ++--
test/cgi/test_cgi_util.rb | 18 ++++++++++++++++++
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/lib/cgi/util.rb b/lib/cgi/util.rb
index aab8b000cb..5ff8ba58eb 100644
--- a/lib/cgi/util.rb
+++ b/lib/cgi/util.rb
@@ -140,7 +140,7 @@ def unescapeHTML(string)
def escapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
- string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/i) do
+ string.gsub(/<\/?(?:#{elements.join("|")})\b[^<>]*+>?/im) do
CGI.escapeHTML($&)
end
else
@@ -160,7 +160,7 @@ def escapeElement(string, *elements)
def unescapeElement(string, *elements)
elements = elements[0] if elements[0].kind_of?(Array)
unless elements.empty?
- string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/i) do
+ string.gsub(/&lt;\/?(?:#{elements.join("|")})\b(?>[^&]+|&(?![gl]t;)\w+;)*(?:&gt;)?/im) do
unescapeHTML($&)
end
else
diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb
index b7bb7b8eae..e93be474b3 100644
--- a/test/cgi/test_cgi_util.rb
+++ b/test/cgi/test_cgi_util.rb
@@ -181,6 +181,14 @@ def test_cgi_escapeElement
assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"]))
assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', "A", "IMG"))
assert_equal("<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<BR><A HREF="url"></A>', ["A", "IMG"]))
+
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', "A", "IMG"))
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escapeElement('<A <A HREF="url"></A>', ["A", "IMG"]))
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', "A", "IMG"))
+ assert_equal("&lt;A &lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt;", escape_element('<A <A HREF="url"></A>', ["A", "IMG"]))
+
+ assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', "A", "IMG"))
+ assert_equal("&lt;A &lt;A ", escapeElement('<A <A ', ["A", "IMG"]))
end
@@ -189,5 +197,15 @@ def test_cgi_unescapeElement
assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescapeElement(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG"))
assert_equal('&lt;BR&gt;<A HREF="url"></A>', unescape_element(escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"]))
+
+ assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
+ assert_equal('<A <A HREF="url"></A>', unescapeElement(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
+ assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), "A", "IMG"))
+ assert_equal('<A <A HREF="url"></A>', unescape_element(escapeHTML('<A <A HREF="url"></A>'), ["A", "IMG"]))
+
+ assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), "A", "IMG"))
+ assert_equal('<A <A ', unescapeElement(escapeHTML('<A <A '), ["A", "IMG"]))
+ assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), "A", "IMG"))
+ assert_equal('<A <A ', unescape_element(escapeHTML('<A <A '), ["A", "IMG"]))
end
end

View File

@ -0,0 +1,255 @@
From 44dda22bf13d571067cfc5321ed72cad67256767 Mon Sep 17 00:00:00 2001
From: st0012 <stan001212@gmail.com>
Date: Sun, 16 Jan 2022 22:20:05 +0000
Subject: [PATCH 1/3] Use require_relative to require lib files
1. `require` can mislead Ruby to load system irb's files and cause
constant redefined warnings as other code loads the same module/class
from lib folder.
2. Most files already use `require_relative`.
---
lib/irb/color.rb | 2 +-
lib/irb/color_printer.rb | 2 +-
lib/irb/inspector.rb | 2 +-
libexec/irb | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/irb/color.rb b/lib/irb/color.rb
index cfbb3cc668..4f6258adf8 100644
--- a/lib/irb/color.rb
+++ b/lib/irb/color.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'reline'
require 'ripper'
-require 'irb/ruby-lex'
+require_relative 'ruby-lex'
module IRB # :nodoc:
module Color
diff --git a/lib/irb/color_printer.rb b/lib/irb/color_printer.rb
index 30c6825750..78f0b51520 100644
--- a/lib/irb/color_printer.rb
+++ b/lib/irb/color_printer.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
require 'pp'
-require 'irb/color'
+require_relative 'color'
module IRB
class ColorPrinter < ::PP
diff --git a/lib/irb/inspector.rb b/lib/irb/inspector.rb
index c2f3b605db..8c37c0f174 100644
--- a/lib/irb/inspector.rb
+++ b/lib/irb/inspector.rb
@@ -114,7 +114,7 @@ def inspect_value(v)
end
result
}
- Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require "irb/color_printer"}){|v|
+ Inspector.def_inspector([true, :pp, :pretty_inspect], proc{require_relative "color_printer"}){|v|
if IRB.conf[:MAIN_CONTEXT]&.use_colorize?
IRB::ColorPrinter.pp(v, '').chomp
else
diff --git a/libexec/irb b/libexec/irb
index c64ee85fbd..ffc97867d0 100755
--- a/libexec/irb
+++ b/libexec/irb
@@ -6,6 +6,6 @@
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-require "irb"
+require_relative '../lib/irb'
IRB.start(__FILE__)
From e885a5bf9d20b45737746c5f2ae91059c09830cc Mon Sep 17 00:00:00 2001
From: st0012 <stan001212@gmail.com>
Date: Mon, 17 Jan 2022 11:45:16 +0000
Subject: [PATCH 2/3] Use require_relative to load extensions/commands
---
lib/irb/extend-command.rb | 48 +++++++++++++++++++--------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/lib/irb/extend-command.rb b/lib/irb/extend-command.rb
index 339e9e6084..d6fb19038d 100644
--- a/lib/irb/extend-command.rb
+++ b/lib/irb/extend-command.rb
@@ -47,7 +47,7 @@ def irb_context
@EXTEND_COMMANDS = [
[
- :irb_current_working_workspace, :CurrentWorkingWorkspace, "irb/cmd/chws",
+ :irb_current_working_workspace, :CurrentWorkingWorkspace, "cmd/chws",
[:irb_print_working_workspace, OVERRIDE_ALL],
[:irb_cwws, OVERRIDE_ALL],
[:irb_pwws, OVERRIDE_ALL],
@@ -59,7 +59,7 @@ def irb_context
[:irb_pwb, OVERRIDE_ALL],
],
[
- :irb_change_workspace, :ChangeWorkspace, "irb/cmd/chws",
+ :irb_change_workspace, :ChangeWorkspace, "cmd/chws",
[:irb_chws, OVERRIDE_ALL],
[:irb_cws, OVERRIDE_ALL],
[:chws, NO_OVERRIDE],
@@ -70,13 +70,13 @@ def irb_context
],
[
- :irb_workspaces, :Workspaces, "irb/cmd/pushws",
+ :irb_workspaces, :Workspaces, "cmd/pushws",
[:workspaces, NO_OVERRIDE],
[:irb_bindings, OVERRIDE_ALL],
[:bindings, NO_OVERRIDE],
],
[
- :irb_push_workspace, :PushWorkspace, "irb/cmd/pushws",
+ :irb_push_workspace, :PushWorkspace, "cmd/pushws",
[:irb_pushws, OVERRIDE_ALL],
[:pushws, NO_OVERRIDE],
[:irb_push_binding, OVERRIDE_ALL],
@@ -84,7 +84,7 @@ def irb_context
[:pushb, NO_OVERRIDE],
],
[
- :irb_pop_workspace, :PopWorkspace, "irb/cmd/pushws",
+ :irb_pop_workspace, :PopWorkspace, "cmd/pushws",
[:irb_popws, OVERRIDE_ALL],
[:popws, NO_OVERRIDE],
[:irb_pop_binding, OVERRIDE_ALL],
@@ -93,55 +93,55 @@ def irb_context
],
[
- :irb_load, :Load, "irb/cmd/load"],
+ :irb_load, :Load, "cmd/load"],
[
- :irb_require, :Require, "irb/cmd/load"],
+ :irb_require, :Require, "cmd/load"],
[
- :irb_source, :Source, "irb/cmd/load",
+ :irb_source, :Source, "cmd/load",
[:source, NO_OVERRIDE],
],
[
- :irb, :IrbCommand, "irb/cmd/subirb"],
+ :irb, :IrbCommand, "cmd/subirb"],
[
- :irb_jobs, :Jobs, "irb/cmd/subirb",
+ :irb_jobs, :Jobs, "cmd/subirb",
[:jobs, NO_OVERRIDE],
],
[
- :irb_fg, :Foreground, "irb/cmd/subirb",
+ :irb_fg, :Foreground, "cmd/subirb",
[:fg, NO_OVERRIDE],
],
[
- :irb_kill, :Kill, "irb/cmd/subirb",
+ :irb_kill, :Kill, "cmd/subirb",
[:kill, OVERRIDE_PRIVATE_ONLY],
],
[
- :irb_help, :Help, "irb/cmd/help",
+ :irb_help, :Help, "cmd/help",
[:help, NO_OVERRIDE],
],
[
- :irb_info, :Info, "irb/cmd/info"
+ :irb_info, :Info, "cmd/info"
],
[
- :irb_ls, :Ls, "irb/cmd/ls",
+ :irb_ls, :Ls, "cmd/ls",
[:ls, NO_OVERRIDE],
],
[
- :irb_measure, :Measure, "irb/cmd/measure",
+ :irb_measure, :Measure, "cmd/measure",
[:measure, NO_OVERRIDE],
],
[
- :irb_show_source, :ShowSource, "irb/cmd/show_source",
+ :irb_show_source, :ShowSource, "cmd/show_source",
[:show_source, NO_OVERRIDE],
],
[
- :irb_whereami, :Whereami, "irb/cmd/whereami",
+ :irb_whereami, :Whereami, "cmd/whereami",
[:whereami, NO_OVERRIDE],
],
@@ -187,7 +187,7 @@ def self.def_extend_command(cmd_name, cmd_class, load_file = nil, *aliases)
kwargs = ", **kwargs" if RUBY_ENGINE == "ruby" && RUBY_VERSION >= "2.7.0"
line = __LINE__; eval %[
def #{cmd_name}(*opts#{kwargs}, &b)
- require "#{load_file}"
+ require_relative "#{load_file}"
arity = ExtendCommand::#{cmd_class}.instance_method(:execute).arity
args = (1..(arity < 0 ? ~arity : arity)).map {|i| "arg" + i.to_s }
args << "*opts#{kwargs}" if arity < 0
@@ -262,10 +262,10 @@ module ContextExtender
CE = ContextExtender # :nodoc:
@EXTEND_COMMANDS = [
- [:eval_history=, "irb/ext/history.rb"],
- [:use_tracer=, "irb/ext/tracer.rb"],
- [:use_loader=, "irb/ext/use-loader.rb"],
- [:save_history=, "irb/ext/save-history.rb"],
+ [:eval_history=, "ext/history.rb"],
+ [:use_tracer=, "ext/tracer.rb"],
+ [:use_loader=, "ext/use-loader.rb"],
+ [:save_history=, "ext/save-history.rb"],
]
# Installs the default context extensions as irb commands:
@@ -288,7 +288,7 @@ def self.def_extend_command(cmd_name, load_file, *aliases)
line = __LINE__; Context.module_eval %[
def #{cmd_name}(*opts, &b)
Context.module_eval {remove_method(:#{cmd_name})}
- require "#{load_file}"
+ require_relative "#{load_file}"
__send__ :#{cmd_name}, *opts, &b
end
for ali in aliases
From 19431c7ccc23545b9e973d5e0993c20422f42796 Mon Sep 17 00:00:00 2001
From: st0012 <stan001212@gmail.com>
Date: Mon, 17 Jan 2022 15:17:18 +0000
Subject: [PATCH 3/3] require_relative can't be used for default gems' exe
files
The `exe` folder and `lib` folder of default gems don't locate under the
same place. While `exe/irb` will be under the gem folder, `irb.rb` will be
under `lib/ruby/VERSION/`.
So `require_relative` will make `irb` unuseable when shipped with Ruby.
Related discussion in the comments: https://github.com/ruby/irb/pull/335
---
libexec/irb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libexec/irb b/libexec/irb
index ffc97867d0..c64ee85fbd 100755
--- a/libexec/irb
+++ b/libexec/irb
@@ -6,6 +6,6 @@
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
#
-require_relative '../lib/irb'
+require "irb"
IRB.start(__FILE__)

View File

@ -22,7 +22,7 @@
%endif %endif
%global release 163 %global release 165
%{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}} %{!?release_string:%define release_string %{?development_release:0.}%{release}%{?development_release:.%{development_release}}%{?dist}}
# The RubyGems library has to stay out of Ruby directory tree, since the # The RubyGems library has to stay out of Ruby directory tree, since the
@ -300,6 +300,45 @@ Patch70: ruby-3.3.1-Fix-test-session-reuse-but-expire.patch
# Tests not included, this Ruby release does not include REXML tests. # Tests not included, this Ruby release does not include REXML tests.
# https://github.com/ruby/rexml/commit/ce59f2eb1aeb371fe1643414f06618dbe031979f # https://github.com/ruby/rexml/commit/ce59f2eb1aeb371fe1643414f06618dbe031979f
Patch71: rubygem-rexml-3.3.9-Fix-ReDoS-CVE-2024-49761.patch Patch71: rubygem-rexml-3.3.9-Fix-ReDoS-CVE-2024-49761.patch
# If GC compaction is not supported on platform, define the
# corresponding GC methods as not implemented.
# https://bugs.ruby-lang.org/issues/18779
# https://github.com/ruby/ruby/pull/5934
Patch72: ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch
# tar -Jxvf ./ruby-3.0.7.tar.xz
# git clone https://github.com/ruby/ruby.git
# cd ruby && git checkout v3_0_7
# patch -p1 < ../ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch
# patch -p1 < ../ruby-3.2.0-define-unsupported-gc-compaction-methods-as-rb_f_notimplement.patch
# ./autogen.sh && ./configure
# make gc.rbinc miniprelude.c
# cd ..
# diff -u {ruby-3.0.7,ruby}/gc.rbinc > ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch
# diff -u {ruby-3.0.7,ruby}/miniprelude.c >> ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch
Patch73: ruby-3.2.0-define-unsupported-gc-compaction-methods_generated-files.patch
# Define the GC compaction support macro at run time.
# https://bugs.ruby-lang.org/issues/18829
# https://github.com/ruby/ruby/pull/6019
# https://github.com/ruby/ruby/commit/2c190863239bee3f54cfb74b16bb6ea4cae6ed20
Patch74: ruby-3.2.0-Detect-compaction-support-during-runtime.patch
# IRB, when used from within ruby code using simple `require 'irb'; binding.irb`,
# a lot of warning messages about already initialized constants, similar to:
# "/usr/share/ruby/irb/ruby-lex.rb:123: warning: already initialized constant RubyLex::ERROR_TOKENS"
# "/usr/share/gems/gems/irb-1.3.5/lib/irb/ruby-lex.rb:123: warning: previous definition of ERROR_TOKENS was here"
# are printed.
# https://github.com/ruby/irb/pull/335
# https://github.com/ruby/irb/commit/848d339f2e255f4b0dfc68568d818d4c3587b266
# https://github.com/ruby/irb/pull/336
# https://github.com/ruby/irb/commit/d5060f76687e3ff355583bfa5f073c67d558e2bd
# https://github.com/ruby/irb/pull/338
# https://github.com/ruby/irb/commit/99d3aa979dffece1fab06a7d5ebff4ae5da50aae
Patch75: rubygem-irb-1.4.2-Fix-already-initialized-constant-messages-from-require-in-scripts.patch
# Fix Denial of Service in CGI::Cookie.parse. (CVE-2025-27219)
# https://github.com/ruby/cgi/commit/2f8ec73bb3eb71c4cf13e735f2d696603de2f34b
Patch76: rubygem-cgi-0.3.5.1-Fix-DoS-in-CGI-Cookie-parse-CVE-2025-27219.patch
# Fix ReDoS in CGI::Util#escapeElement. (CVE-2025-27220)
# https://github.com/ruby/cgi/commit/bfa69e120df4e0131bb05df6c5e05c1dc982cd37
Patch77: rubygem-cgi-0.3.5.1-Fix-ReDoS-in-CGI-CVE-2025-27220.patch
Requires: %{name}-libs%{?_isa} = %{version}-%{release} Requires: %{name}-libs%{?_isa} = %{version}-%{release}
Suggests: rubypick Suggests: rubypick
@ -773,6 +812,12 @@ rm -rf ext/fiddle/libffi*
%patch68 -p1 %patch68 -p1
%patch69 -p1 %patch69 -p1
%patch70 -p1 %patch70 -p1
%patch72 -p1
%patch73 -p1
%patch74 -p1
%patch75 -p1
%patch76 -p1
%patch77 -p1
# Instead of adjusting patch's directory, use the following form where # Instead of adjusting patch's directory, use the following form where
# we first enter the correct directory, this allows more general application # we first enter the correct directory, this allows more general application
@ -1555,6 +1600,18 @@ make runruby TESTRUN_SCRIPT=" \
%changelog %changelog
* Fri Apr 11 2025 Jarek Prokop <jprokop@redhat.com> - 3.0.7-165
- Fix Denial of Service in CGI::Cookie.parse. (CVE-2025-27219)
Resolves: RHEL-87183
- Fix ReDoS in CGI::Util#escapeElement. (CVE-2025-27220)
Resolves: RHEL-87184
* Thu Mar 06 2025 Jarek Prokop <jprokop@redhat.com> - 3.0.7-164
- Undefine GC compaction methods on ppc64le.
Resolves: RHEL-83135
- Fix printing warnings when using IRB from a script.
Resolves: RHEL-83137
* Tue Nov 26 2024 Jarek Prokop <jprokop@redhat.com> - 3.0.7-163 * Tue Nov 26 2024 Jarek Prokop <jprokop@redhat.com> - 3.0.7-163
- Fix REXML ReDoS vulnerability. (CVE-2024-49761) - Fix REXML ReDoS vulnerability. (CVE-2024-49761)
Resolves: RHEL-68521 Resolves: RHEL-68521