f77e9e6b4e
1 Commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
|
7993206359 |
Undefine GC compaction and related methods for ppc64le.
The following falcon source: <https://github.com/socketry/falcon/blob/v0.42.3/lib/falcon/command/serve.rb#L153-L155> contains the following snippet: ~~~ if GC.respond_to?(:compact) GC.compact end ~~~ The `if` guard for this feature is recommended from documentation since Ruby >= 3.2: <https://docs.ruby-lang.org/en/3.2/GC.html#method-c-compact>: ``` To test whether GC compaction is supported, use the idiom: ~~~ GC.respond_to?(:compact) ~~~ ``` Gems make use of this idiom in various situations. However on Ruby 3.0 without this patch the `GC.respond_to?` method will return true for `GC.compact` and compaction related methods even though an attempt to call them will raise "NotImplementedError" exception. We observe this behavior due to the methods being implemented and the NotImplementedError is not returned because methods are not implemented, but because it is a runtime behavior from inside the called methods. The applied patchset undefines the methods in C code to ensure even the `GC.respond_to?` will return false and accomodate libraries that call `GC.compact` like falcon does: <https://github.com/socketry/falcon/blob/v0.42.3/lib/falcon/command/serve.rb#L153-L155> The methods are undefined on build time on affected platforms that do not support compaction. Currently this is only affecting ppc64le. The important portion of the patch undefines the `GC.compact` and other methods, so we can expect the following on ppc64le architecture: Before: ~~~ $ ruby -e 'p GC.respond_to? :compact' true ~~~ After: ~~~ $ ruby -e 'p GC.respond_to? :compact' false ~~~ As long as Ruby gems guard the call to `GC.compact` correctly, there should no longer be a situation where GC reports compaction methods as implemented even though it will throw an exception when trying to use the methods. Most importantly, this is only an issue with ppc64le. The other architectures such as x86_64, aarch64, s390x should continue to be able to compact. This is guarded on compile-time. However the patches touch the source for pre-generated files. Mainly meaning the file `gc.rb` that is the source for the `gc.rbinc` and `miniprelude.c` need to be re-generated. The files use Ruby to generate the C counterparts. To prevent cyclic dependency, they are re-generated and patches are created against the old version. The approach to regenerate the files for 3.0 is the same as for 3.1 with the exception of also having to first patch with the file `ruby-3.1.0-Use-mmap-for-allocating-heap-pages-in-the-GC.patch`, since the subsequent patches are made on top of that patch. The mmap patch changes parts of gc.c, that the required patch also changes, so it had to be backported on top of that patch. The sequence of actions is as follows: ~~~ 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 ~~~ Firstly we unpact the upstream tar archive, which creates `ruby-3.0.7` directory. Then we clone the upstream git repository and check out the Ruby version tag that is source for the tar archive which creates `ruby` repository. The `ruby-3.0.7` directory contains the pre-generated files we will use as the original for the patch. In the `ruby` repository we apply the patches mentioned in the code snippet. Then, generate configure script with autogen.sh, and we create the gc.rbinc and miniprelude.c files that are generated. Then create the patch for the generated files. `diff` is used as the generated files are not tracked via git in upstream, and the diff is executed against the expanded upstream tar archive that does not ship a git repository with it. While it would be possible to `git add` the files before patching them, this ensures that the files are applicable without a problem on top of the archive. This commit is partially backported from Ruby 3.1's Fedora counterparts: |