Closed kimyu92 closed 2 years ago
@Watson1978 please let me know if you have any insight especially this is most likely involve C extension 🤷
Seems like it's suggesting this line https://github.com/carrierwaveuploader/carrierwave/blob/v2.2.2/lib/carrierwave/processing/rmagick.rb#L352
and taking closer look Magick::Image.read
is defined in https://github.com/rmagick/rmagick/blob/main/ext/RMagick/rmmain.c#L294
@dlemstra Since you're very familiar with C code, any potential issue that you can share regarding how rbtree could interfere read?
https://gist.github.com/Watson1978/0ec37694a363c64414b944ed47dd8373
$ docker build -t rmagick .
$ docker run -v $(pwd):/opt/rmagick --rm -it rmagick bash
bash-5.1# gdb --args ruby ./crash.rb
GNU gdb (GDB) 11.1
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-alpine-linux-musl".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ruby...
(gdb) r
Starting program: /usr/local/bin/ruby ./crash.rb
...
-- drop_table(:users, {:if_exists=>true})
-> 0.0081s
-- create_table(:users, {:force=>true})
-> 0.0009s
Run options:
include {:focus=>true}
exclude {:skip=>true}
All examples were filtered out; ignoring {:focus=>true}
Thread 1 "ruby" received signal SIGSEGV, Segmentation fault.
0x00007f2e6a2dc9d9 in dict_first () from /usr/local/lib/ruby/gems/3.0.0/gems/rbtree-0.4.5/lib/rbtree.so
(gdb) bt 20
#0 0x00007f2e6a2dc9d9 in dict_first () from /usr/local/lib/ruby/gems/3.0.0/gems/rbtree-0.4.5/lib/rbtree.so
#1 0x00007f2e67ade974 in ?? () from /usr/lib/libgs.so.9
#2 0x00007f2e67adebb6 in dict_resize () from /usr/lib/libgs.so.9
#3 0x00007f2e67aec4ae in ?? () from /usr/lib/libgs.so.9
#4 0x00007f2e67ae20d5 in ?? () from /usr/lib/libgs.so.9
#5 0x00007f2e67ae356b in gs_interpret () from /usr/lib/libgs.so.9
#6 0x00007f2e67ad7f2b in ?? () from /usr/lib/libgs.so.9
#7 0x00007f2e67ad834a in gs_main_init2aux () from /usr/lib/libgs.so.9
#8 0x00007f2e67ad8ce1 in gs_main_init2 () from /usr/lib/libgs.so.9
#9 0x00007f2e67ada10b in ?? () from /usr/lib/libgs.so.9
#10 0x00007f2e67ada3c5 in ?? () from /usr/lib/libgs.so.9
#11 0x00007f2e67adaaed in ?? () from /usr/lib/libgs.so.9
#12 0x00007f2e67adba50 in gs_main_init_with_args01 () from /usr/lib/libgs.so.9
#13 0x00007f2e67adbbb5 in gs_main_init_with_args () from /usr/lib/libgs.so.9
#14 0x00007f2e6b1072e0 in ?? () from /usr/lib/ImageMagick-7.1.0/modules-Q16HDRI/coders/pdf.so
#15 0x00007f2e6a7c45cc in ReadImage () from /usr/lib/libMagickCore-7.Q16HDRI.so.10
#16 0x00007f2e6a9c8687 in rd_image () from /usr/local/lib/ruby/gems/3.0.0/gems/rmagick-4.2.5/lib/RMagick2.so
#17 0x00007f2e6a9c84c8 in Image_read () from /usr/local/lib/ruby/gems/3.0.0/gems/rmagick-4.2.5/lib/RMagick2.so
#18 0x0000564a86cf5482 in call_cfunc_1 ()
#19 0x0000564a86cf6a45 in vm_call_cfunc_with_frame ()
(More stack frames follow...)
hmm, I confirmed that your code causes SEGV within rbtree. I will investigate this deeply at weekend
If possible, it would be better to use something other than PDF, since processing JPEG instead of PDF does not seem to cause SEGV.
/usr/lib/libgs.so.9
is related to GhostScript.
I don't know why it calls rbtree
...
hmm, I confirmed that your code causes SEGV within rbtree. I will investigate this deeply at weekend
Thank you
I don't know why it calls rbtree
💯 Shouldn't rmagick
and rbtree
be isolated unless c extension clashed with each other via include
? 😅
A simpler reproduction code would look like below.
require 'bundler/inline'
gemfile(true) do
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rmagick', '~> 4.2.5'
gem 'sorted_set'
end
require 'rmagick'
require 'sorted_set'
Magick::Image.read('sample.pdf')
I'm guessing there is something wrong with the alpine configuration or something, and the loaded C symbols are conflicting....
I'm guessing there is something wrong with the alpine configuration or something, and the loaded C symbols are conflicting....
I'm curious would it be due to dict_first() from ghostscript vs dict_first() defined by rbtree
At least, there is no way that can be solved with RMagick.
(It stop using PDF or create a docker image with another OS instead of alpine)
@Watson1978 I highly appreciated the gist above and I agreed with you that this is not related to rmagick. musl
is usually stricter than glibc
, I still lean towards the issue might come from rbtree
because without including it, the rmagick works fine.
I think the rbtree and ghostscript libraries are not linked, so it is curious that the symbols conflict. And because your reproduction code works on ubuntu image.
Description
As soon as, I installed both
rmagick
andrbtree
orrmagick
withsorted_set
, segmentation fault would happen immediately with the single file rails setup below.Steps to Reproduce
docker pull ruby:2.7.6-alpine3.15
ordocker pull ruby:3.0.4-alpine3.15
ordocker pull ruby:3.1.2-alpine3.15
repro.rb
in containerapk add pkgconfig imagemagick imagemagick-dev imagemagick-libs
apk add sqlite sqlite-dev
apk add build-base gcc autoconf libffi-dev openssl-dev
ruby repro.rb
inside docker containerrequire 'bundler/inline'
gemfile(true) do source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 7.0.2.3' gem 'rspec-rails', '~> 5.1.1'
gem 'carrierwave' gem 'rmagick', '~> 4.2.5'
either gem would make interpreter blows up
adding , require: false on either gem would make it work but not ideal
gem 'rbtree'
gem 'sorted_set' gem 'sqlite3' end
require 'rmagick'
require 'active_support' require 'active_support/core_ext/object/blank' require 'active_record'
require 'action_controller/railtie' require 'action_view/railtie'
require 'rspec/autorun' require 'rspec/rails' require 'carrierwave/orm/activerecord'
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Schema.define do drop_table :users, if_exists: true
create_table :users, force: true do |t| t.timestamps null: false t.string :avatar end end
class AvatarUploader < CarrierWave::Uploader::Base include CarrierWave::RMagick storage :file
process resize_to_fit: [777, 777] end
class User < ActiveRecord::Base mount_uploader :avatar, AvatarUploader end
RSpec.configure do |config| config.filter_run_excluding skip: true config.run_all_when_everything_filtered = true config.filter_run focus: true end
RSpec.describe 'Segfault error' do let(:user) { User.new } let(:file) { Tempfile.new } let(:avatar) { Rack::Test::UploadedFile.new(file, 'application/pdf', true, original_filename: 'sample.pdf') } let(:avatar_key) { sample_key(User.new.uploader, extension: 'pdf') }
before do user.avatar = avatar end
it { expect(user.avatar).to eq(avatar) } end