Skip to content

Commit 03e7513

Browse files
nobuhsbtjeremyevansjunarugaznz
authored
Merge from ruby master (#32)
* Revert "[ruby/fiddle] Use ffi_closure_free by default. (#20)" This reverts commit ce6caade7c57a505f73086ccd7b33c14f7715f22. * Revert "[ruby/fiddle] test: use env Hash" This reverts commit 4d844cbaed518743776594fa5ae33b86fe176ad1. * Deprecate taint/trust and related methods, and make the methods no-ops This removes the related tests, and puts the related specs behind version guards. This affects all code in lib, including some libraries that may want to support older versions of Ruby. * More fixes for $SAFE/taint post merging * Fix "cannot find the function: strcpy()" error on arm32 on Travis CI. (#2686) This issue happened when `libc.so` and `libm.so` path were not found and `ldd ruby` command also failed to print the shared dependencies in `test/fiddle/helper.rb`. See https://travis-ci.org/ruby/ruby/jobs/611483288#L3018 /home/travis/build/ruby/ruby/build/.ext/common/fiddle/import.rb:299:in `import_function': cannot find the function: strcpy() (Fiddle::DLError) * Set libc6:armhf as a installing dependency explicitly. * Remove arm32 from allow_failures. * Drop executable bit of *.{yml,h,mk.tmpl} * pass appropriate libc path The same as ruby/ruby#2686, but for musl libc. Musl is not named as libc.so.6 so the `ldd` hack implemented some lines below does not work. * Use ffi_closure_free if available * ffi_closure_free is available in the bundled libffi * Fixed never-defined symbol name * use ffi_closure_alloc only with 3.2 or later * always use ffi_closure_alloc on Windows * Fixed a typo * Switch to download libffi source package to github releases from sourceware.org * Use osuosl instead of GitHub releases Because the package provided by GitHub releases is different from sourceware. * Do not set USE_FFI_CLOSURE_ALLOC=1 in fiddle on OpenBSD On OpenBSD, USE_FFI_CLOSURE_ALLOC was always set to 0 previously. In 633a1f15d8228236094ddee12e4e169d655ec49e, the code was modified in a way that it ended up being set to 1 on OpenBSD. However, that results in SIGABRT when running make test-all, inside ffi_closure_free. Setting USE_FFI_CLOSURE_ALLOC back to 0 fixes the issue. * Show libffi version only if set * Fix helper to not assume glibc * `Dir.glob` always returns an array It is not needed to test itself, but the element should be tested instead. Co-authored-by: Hiroshi SHIBATA <hsbt@ruby-lang.org> Co-authored-by: Jeremy Evans <code@jeremyevans.net> Co-authored-by: Jun Aruga <junaruga@users.noreply.github.com> Co-authored-by: Kazuhiro NISHIYAMA <zn@mbf.nifty.com> Co-authored-by: 卜部昌平 <shyouhei@ruby-lang.org> Co-authored-by: Paul Jordan <paullj1@gmail.com>
1 parent 1b93a2d commit 03e7513

File tree

8 files changed

+90
-26
lines changed

8 files changed

+90
-26
lines changed

ext/fiddle/closure.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,26 @@ typedef struct {
1313
ffi_type **argv;
1414
} fiddle_closure;
1515

16+
#if defined(__OpenBSD__)
17+
# define USE_FFI_CLOSURE_ALLOC 0
18+
#endif
19+
20+
#if defined(USE_FFI_CLOSURE_ALLOC)
21+
#elif !defined(HAVE_FFI_CLOSURE_ALLOC)
22+
# define USE_FFI_CLOSURE_ALLOC 0
23+
#else
24+
# define USE_FFI_CLOSURE_ALLOC 1
25+
#endif
26+
1627
static void
1728
dealloc(void * ptr)
1829
{
1930
fiddle_closure * cls = (fiddle_closure *)ptr;
31+
#if USE_FFI_CLOSURE_ALLOC
2032
ffi_closure_free(cls->pcl);
33+
#else
34+
munmap(cls->pcl, sizeof(*cls->pcl));
35+
#endif
2136
if (cls->argv) xfree(cls->argv);
2237
xfree(cls);
2338
}
@@ -191,7 +206,12 @@ allocate(VALUE klass)
191206
VALUE i = TypedData_Make_Struct(klass, fiddle_closure,
192207
&closure_data_type, closure);
193208

209+
#if USE_FFI_CLOSURE_ALLOC
194210
closure->pcl = ffi_closure_alloc(sizeof(ffi_closure), &closure->code);
211+
#else
212+
closure->pcl = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
213+
MAP_ANON | MAP_PRIVATE, -1, 0);
214+
#endif
195215

196216
return i;
197217
}
@@ -238,8 +258,17 @@ initialize(int rbargc, VALUE argv[], VALUE self)
238258
if (FFI_OK != result)
239259
rb_raise(rb_eRuntimeError, "error prepping CIF %d", result);
240260

261+
#if USE_FFI_CLOSURE_ALLOC
241262
result = ffi_prep_closure_loc(pcl, cif, callback,
242263
(void *)self, cl->code);
264+
#else
265+
result = ffi_prep_closure(pcl, cif, callback, (void *)self);
266+
cl->code = (void *)pcl;
267+
i = mprotect(pcl, sizeof(*pcl), PROT_READ | PROT_EXEC);
268+
if (i) {
269+
rb_sys_fail("mprotect");
270+
}
271+
#endif
243272

244273
if (FFI_OK != result)
245274
rb_raise(rb_eRuntimeError, "error prepping closure %d", result);

ext/fiddle/extconf.rb

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
if ! bundle
88
dir_config 'libffi'
99

10-
pkg_config("libffi")
10+
pkg_config("libffi") and
11+
ver = pkg_config("libffi", "modversion")
1112

1213
if have_header(ffi_header = 'ffi.h')
1314
true
1415
elsif have_header(ffi_header = 'ffi/ffi.h')
15-
$defs.push(format('-DUSE_HEADER_HACKS'))
16+
$defs.push('-DUSE_HEADER_HACKS')
1617
true
1718
end and (have_library('ffi') || have_library('libffi'))
1819
end or
@@ -27,20 +28,20 @@
2728
Dir.glob("#{$srcdir}/libffi-*/").each{|dir| FileUtils.rm_rf(dir)}
2829
extlibs.run(["--cache=#{cache_dir}", ext_dir])
2930
end
30-
libffi_dir = bundle != false &&
31+
ver = bundle != false &&
3132
Dir.glob("#{$srcdir}/libffi-*/")
3233
.map {|n| File.basename(n)}
3334
.max_by {|n| n.scan(/\d+/).map(&:to_i)}
34-
unless libffi_dir
35+
unless ver
3536
raise "missing libffi. Please install libffi."
3637
end
3738

38-
srcdir = "#{$srcdir}/#{libffi_dir}"
39+
srcdir = "#{$srcdir}/#{ver}"
3940
ffi_header = 'ffi.h'
4041
libffi = Struct.new(*%I[dir srcdir builddir include lib a cflags ldflags opt arch]).new
41-
libffi.dir = libffi_dir
42+
libffi.dir = ver
4243
if $srcdir == "."
43-
libffi.builddir = "#{libffi_dir}/#{RUBY_PLATFORM}"
44+
libffi.builddir = "#{ver}/#{RUBY_PLATFORM}"
4445
libffi.srcdir = "."
4546
else
4647
libffi.builddir = libffi.dir
@@ -51,6 +52,7 @@
5152
libffi.a = "#{libffi.lib}/libffi_convenience.#{$LIBEXT}"
5253
nowarn = CONFIG.merge("warnflags"=>"")
5354
libffi.cflags = RbConfig.expand("$(CFLAGS)".dup, nowarn)
55+
ver = ver[/libffi-(.*)/, 1]
5456

5557
FileUtils.mkdir_p(libffi.dir)
5658
libffi.opt = CONFIG['configure_args'][/'(-C)'/, 1]
@@ -110,6 +112,18 @@
110112
$INCFLAGS << " -I" << libffi.include
111113
end
112114

115+
if ver
116+
ver = ver.gsub(/-rc\d+/, '') # If ver contains rc version, just ignored.
117+
ver = (ver.split('.').map(&:to_i) + [0,0])[0,3]
118+
$defs.push(%{-DRUBY_LIBFFI_MODVERSION=#{ '%d%03d%03d' % ver }})
119+
warn "libffi_version: #{ver.join('.')}"
120+
end
121+
122+
case
123+
when $mswin, $mingw, (ver && (ver <=> [3, 2]) >= 0)
124+
$defs << "-DUSE_FFI_CLOSURE_ALLOC=1"
125+
end
126+
113127
have_header 'sys/mman.h'
114128

115129
if have_header "dlfcn.h"
@@ -134,7 +148,7 @@
134148
if /^\#define\s+SIZEOF_#{type}\s+(SIZEOF_(.+)|\d+)/ =~ config
135149
if size = $2 and size != 'VOIDP'
136150
size = types.fetch(size) {size}
137-
$defs << format("-DTYPE_%s=TYPE_%s", signed||type, size)
151+
$defs << "-DTYPE_#{signed||type}=TYPE_#{size}"
138152
end
139153
if signed
140154
check_signedness(type.downcase, "stddef.h")

ext/fiddle/extlibs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
http://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz \
1+
https://ftp.osuosl.org/pub/blfs/conglomeration/libffi/libffi-3.2.1.tar.gz \
22
md5:83b89587607e3eb65c70d361f13bab43 \
33
sha512:980ca30a8d76f963fca722432b1fe5af77d7a4e4d2eac5144fbc5374d4c596609a293440573f4294207e1bdd9fda80ad1e1cafb2ffb543df5a275bc3bd546483 \
44
#

ext/fiddle/win32/fficonfig.h

100755100644
File mode changed.

ext/fiddle/win32/libffi.mk.tmpl

100755100644
File mode changed.

test/fiddle/helper.rb

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,39 @@
1717
end
1818
libc_so = File.join(libdir, "libc.so")
1919
libm_so = File.join(libdir, "libm.so")
20+
when /linux-musl/
21+
Dir.glob('/lib/ld-musl-*.so.1') do |ld|
22+
libc_so = libm_so = ld
23+
end
2024
when /linux/
2125
libdir = '/lib'
2226
case RbConfig::SIZEOF['void*']
2327
when 4
2428
# 32-bit ruby
25-
libdir = '/lib32' if File.directory? '/lib32'
29+
case RUBY_PLATFORM
30+
when /armv\w+-linux/
31+
# In the ARM 32-bit libc package such as libc6:armhf libc6:armel,
32+
# libc.so and libm.so are installed to /lib/arm-linux-gnu*.
33+
# It's not installed to /lib32.
34+
dir, = Dir.glob('/lib/arm-linux-gnu*')
35+
libdir = dir if dir && File.directory?(dir)
36+
else
37+
libdir = '/lib32' if File.directory? '/lib32'
38+
end
2639
when 8
2740
# 64-bit ruby
2841
libdir = '/lib64' if File.directory? '/lib64'
2942
end
30-
libc_so = File.join(libdir, "libc.so.6")
31-
libm_so = File.join(libdir, "libm.so.6")
43+
44+
# Handle musl libc
45+
libc_so, = Dir.glob(File.join(libdir, "libc.musl*.so*"))
46+
if libc_so
47+
libm_so = libc_so
48+
else
49+
# glibc
50+
libc_so = File.join(libdir, "libc.so.6")
51+
libm_so = File.join(libdir, "libm.so.6")
52+
end
3253
when /mingw/, /mswin/
3354
require "rbconfig"
3455
crtname = RbConfig::CONFIG["RUBY_SO_NAME"][/msvc\w+/] || 'ucrtbase'
@@ -104,6 +125,9 @@
104125

105126
if !libc_so || !libm_so
106127
ruby = EnvUtil.rubybin
128+
# When the ruby binary is 32-bit and the host is 64-bit,
129+
# `ldd ruby` outputs "not a dynamic executable" message.
130+
# libc_so and libm_so are not set.
107131
ldd = `ldd #{ruby}`
108132
#puts ldd
109133
libc_so = $& if !libc_so && %r{/\S*/libc\.so\S*} =~ ldd

test/fiddle/test_function.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_nogvl_poll
9898
end
9999

100100
def test_no_memory_leak
101-
prep = 'r = Fiddle::Function.new(Fiddle.dlopen(nil)["rb_obj_frozen"], [Fiddle::TYPE_UINTPTR_T], Fiddle::TYPE_UINTPTR_T); a = "a"'
101+
prep = 'r = Fiddle::Function.new(Fiddle.dlopen(nil)["rb_obj_frozen_p"], [Fiddle::TYPE_UINTPTR_T], Fiddle::TYPE_UINTPTR_T); a = "a"'
102102
code = 'begin r.call(a); rescue TypeError; end'
103103
assert_no_memory_leak(%w[-W0 -rfiddle], "#{prep}\n1000.times{#{code}}", "10_000.times {#{code}}", limit: 1.2)
104104
end

test/fiddle/test_import.rb

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -185,21 +185,18 @@ def test_atof
185185
end
186186

187187
def test_no_message_with_debug
188+
# disable all Ruby environment variables
189+
orig_RUBYOPT, ENV['RUBYOPT'] = ENV['RUBYOPT'], nil
190+
orig_RUBYLIB, ENV['RUBYLIB'] = ENV['RUBYLIB'], nil
191+
188192
# load development fiddle instead of bundled one
189193
libdir = File.expand_path('../../../lib', __FILE__)
190-
libdir = nil unless File.file?(File.join(libdir, "fiddle/import.rb"))
191-
assert_in_out_err([
192-
# disable all Ruby environment variables
193-
{
194-
"RUBYOPT" => nil,
195-
"RUBYLIB" => libdir,
196-
},
197-
"--debug",
198-
"--disable=gems",
199-
"-rfiddle/import",
200-
],
201-
'p Fiddle::Importer',
202-
['Fiddle::Importer'])
194+
ENV['RUBYLIB'] = libdir if File.file?(File.join(libdir, "fiddle/import.rb"))
195+
196+
assert_in_out_err(%w[--debug --disable=gems -rfiddle/import], 'p Fiddle::Importer', ['Fiddle::Importer'])
197+
ensure
198+
ENV['RUBYLIB'] = orig_RUBYLIB
199+
ENV['RUBYOPT'] = orig_RUBYOPT
203200
end
204201
end
205202
end if defined?(Fiddle)

0 commit comments

Comments
 (0)