ruby/ruby-3.2.0-Detect-compaction-support-during-runtime.patch
Jun Aruga 578b78b080 Upgrade to Ruby 3.1.5.
* Upgrade to Ruby 3.1.5.
  Resolves: RHEL-35748
* Fix buffer overread vulnerability in StringIO.
  Resolves: RHEL-35749
* Fix RCE vulnerability with .rdoc_options in RDoc.
  Resolves: RHEL-35750
* Fix arbitrary memory address read vulnerability with Regex search.
  Resolves: RHEL-35751

Fix fiddle build with libffi versions 3.1 or older.
2024-05-09 17:00:36 +02:00

292 lines
9.7 KiB
Diff

From 4d9cc9afa47981520d991d19fd78b322f1ba9f2a 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 | 63 +++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 43 insertions(+), 20 deletions(-)
diff --git a/gc.c b/gc.c
index 1c35856c44..bff0666a17 100644
--- a/gc.c
+++ b/gc.c
@@ -4985,6 +4985,23 @@ gc_unprotect_pages(rb_objspace_t *objspace, rb_heap_t *heap)
static void gc_update_references(rb_objspace_t * objspace);
static void invalidate_moved_page(rb_objspace_t *objspace, struct heap_page *page);
+#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)
{
@@ -5005,6 +5022,7 @@ read_barrier_handler(uintptr_t address)
}
RB_VM_LOCK_LEAVE();
}
+#endif
#if defined(_WIN32)
static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
@@ -9271,13 +9289,7 @@ 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)) {
- /* 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)
- if (!USE_MMAP_ALIGNED_ALLOC) {
- rb_raise(rb_eNotImpError, "Compaction isn't available on this platform");
- }
-#endif
+ GC_ASSERT(GC_COMPACTION_SUPPORTED);
reason |= GPR_FLAG_COMPACT;
}
@@ -9442,7 +9454,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t slot_size)
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)
{
@@ -10197,7 +10209,7 @@ gc_update_references(rb_objspace_t *objspace)
gc_update_table_refs(objspace, finalizer_table);
}
-#if GC_COMPACTION_SUPPORTED
+#if GC_CAN_COMPILE_COMPACTION
/*
* call-seq:
* GC.latest_compact_info -> {:considered=>{:T_CLASS=>11}, :moved=>{:T_CLASS=>11}}
@@ -10238,7 +10250,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)
{
@@ -10317,7 +10329,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
@@ -10848,7 +10860,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
@@ -10862,8 +10874,7 @@ gc_disable(rb_execution_context_t *ec, VALUE _)
static VALUE
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. */
+ GC_ASSERT(GC_COMPACTION_SUPPORTED);
ruby_enable_autocompact = RTEST(v);
return v;
@@ -10872,7 +10883,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
@@ -13791,11 +13803,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);
@@ -13819,6 +13841,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);
}
--
2.36.1