diff options
-rw-r--r-- | .github/workflows/ci.yml | 4 | ||||
-rw-r--r-- | .gitignore | 13 | ||||
-rw-r--r-- | ext/ffi_c/AbstractMemory.c | 2 | ||||
-rw-r--r-- | ext/ffi_c/DynamicLibrary.c | 15 | ||||
-rw-r--r-- | ext/ffi_c/Struct.c | 12 | ||||
-rw-r--r-- | ext/ffi_c/Struct.h | 3 | ||||
-rw-r--r-- | ext/ffi_c/compat.h | 23 | ||||
-rwxr-xr-x | ext/ffi_c/extconf.rb | 1 | ||||
-rw-r--r-- | lib/ffi/autopointer.rb | 24 | ||||
-rw-r--r-- | lib/ffi/managedstruct.rb | 2 | ||||
-rw-r--r-- | lib/ffi/platform/hppa1.1-linux/types.conf | 178 | ||||
-rw-r--r-- | lib/ffi/platform/hppa2.0-linux/types.conf | 178 | ||||
-rw-r--r-- | spec/ffi/fixtures/ClosureTest.c | 12 | ||||
-rw-r--r-- | spec/ffi/fixtures/PipeHelperWindows.c | 4 | ||||
-rw-r--r-- | spec/ffi/fixtures/PointerTest.c | 2 | ||||
-rw-r--r-- | spec/ffi/gc_compact_spec.rb | 66 | ||||
-rw-r--r-- | spec/ffi/managed_struct_spec.rb | 2 | ||||
-rw-r--r-- | spec/ffi/pointer_spec.rb | 11 | ||||
-rw-r--r-- | spec/ffi/spec_helper.rb | 2 |
19 files changed, 476 insertions, 78 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b9e87d6..fc48721 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: env: # work around misconfiguration of libffi on MacOS with homebrew PKG_CONFIG_PATH: ${{ env.PKG_CONFIG_PATH }}:/usr/local/opt/libffi/lib/pkgconfig - - run: bundle exec rake test + - run: bundle exec rake test FFI_TEST_GC=true - run: bundle exec rake types_conf && git --no-pager diff specs: @@ -60,7 +60,7 @@ jobs: - run: bundle exec rake libffi - run: bundle exec rake compile - - run: bundle exec rake test + - run: bundle exec rake test FFI_TEST_GC=true - run: bundle exec rake bench:all if: ${{ matrix.ruby != 'truffleruby-head' && matrix.ruby != 'jruby-head' }} @@ -12,14 +12,17 @@ build *.so *.[oa] core -lib/ffi/types.conf -lib/ffi_c.bundle -lib/ffi_c.so +/lib/ffi/types.conf +/lib/ffi_c.bundle +/lib/ffi_c.so vendor .bundle Gemfile.lock types_log *.gem embed-test.rb.log -spec/ffi/embed-test/ext/Makefile -spec/ffi/embed-test/ext/embed_test.bundle +/spec/ffi/embed-test/ext/Makefile +/spec/ffi/embed-test/ext/embed_test.bundle +/ext/ffi_c/Makefile +/ext/ffi_c/extconf.h +/ext/ffi_c/mkmf.log diff --git a/ext/ffi_c/AbstractMemory.c b/ext/ffi_c/AbstractMemory.c index 3b076bb..49da32e 100644 --- a/ext/ffi_c/AbstractMemory.c +++ b/ext/ffi_c/AbstractMemory.c @@ -150,7 +150,7 @@ memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary) \ if (likely(count > 0)) checkWrite(memory); \ checkBounds(memory, off, count * sizeof(type)); \ for (i = 0; i < count; i++) { \ - type tmp = (type) VAL(toNative(RARRAY_PTR(ary)[i]), swap); \ + type tmp = (type) VAL(toNative(RARRAY_AREF(ary, i)), swap); \ memcpy(memory->address + off + (i * sizeof(type)), &tmp, sizeof(tmp)); \ } \ return self; \ diff --git a/ext/ffi_c/DynamicLibrary.c b/ext/ffi_c/DynamicLibrary.c index 1d83940..9096e74 100644 --- a/ext/ffi_c/DynamicLibrary.c +++ b/ext/ffi_c/DynamicLibrary.c @@ -227,8 +227,19 @@ dl_open(const char* name, int flags) static void dl_error(char* buf, int size) { - FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), - 0, buf, size, NULL); + // Get the last error code + DWORD error = GetLastError(); + + // Get the associated message + LPSTR message = NULL; + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, error, 0, (LPSTR)&message, 0, NULL); + + // Update the passed in buffer + snprintf(buf, size, "Failed with error %d: %s", error, message); + + // Free the allocated message + LocalFree(message); } #endif diff --git a/ext/ffi_c/Struct.c b/ext/ffi_c/Struct.c index 99b164d..0fdba71 100644 --- a/ext/ffi_c/Struct.c +++ b/ext/ffi_c/Struct.c @@ -132,7 +132,7 @@ struct_initialize(int argc, VALUE* argv, VALUE self) /* Call up into ruby code to adjust the layout */ if (nargs > 1) { - VALUE rbLayout = rb_funcall2(CLASS_OF(self), id_layout, (int) RARRAY_LEN(rest), RARRAY_PTR(rest)); + VALUE rbLayout = rb_apply(CLASS_OF(self), id_layout, rest); RB_OBJ_WRITE(self, &s->rbLayout, rbLayout); } else { RB_OBJ_WRITE(self, &s->rbLayout, struct_class_layout(klass)); @@ -356,10 +356,7 @@ struct_aref(VALUE self, VALUE fieldName) s = struct_validate(self); f = struct_field(s, fieldName); - if (f->get != NULL) { - return (*f->get)(f, s); - - } else if (f->memoryOp != NULL) { + if (f->memoryOp != NULL) { return (*f->memoryOp->get)(s->pointer, f->offset); } else { @@ -386,10 +383,7 @@ struct_aset(VALUE self, VALUE fieldName, VALUE value) s = struct_validate(self); f = struct_field(s, fieldName); - if (f->put != NULL) { - (*f->put)(f, s, value); - - } else if (f->memoryOp != NULL) { + if (f->memoryOp != NULL) { (*f->memoryOp->put)(s->pointer, f->offset, value); diff --git a/ext/ffi_c/Struct.h b/ext/ffi_c/Struct.h index 8e9491b..b86607d 100644 --- a/ext/ffi_c/Struct.h +++ b/ext/ffi_c/Struct.h @@ -59,9 +59,6 @@ extern "C" { VALUE rbType; VALUE rbName; - VALUE (*get)(StructField* field, Struct* s); - void (*put)(StructField* field, Struct* s, VALUE value); - MemoryOp* memoryOp; }; diff --git a/ext/ffi_c/compat.h b/ext/ffi_c/compat.h index 27a99be..a1be55d 100644 --- a/ext/ffi_c/compat.h +++ b/ext/ffi_c/compat.h @@ -32,26 +32,6 @@ #include <ruby.h> -#ifndef RARRAY_LEN -# define RARRAY_LEN(ary) RARRAY(ary)->len -#endif - -#ifndef RARRAY_PTR -# define RARRAY_PTR(ary) RARRAY(ary)->ptr -#endif - -#ifndef RSTRING_LEN -# define RSTRING_LEN(s) RSTRING(s)->len -#endif - -#ifndef RSTRING_PTR -# define RSTRING_PTR(s) RSTRING(s)->ptr -#endif - -#ifndef NUM2ULL -# define NUM2ULL(x) rb_num2ull((VALUE)x) -#endif - #ifndef roundup # define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif @@ -75,9 +55,6 @@ # define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif -#ifndef RB_GC_GUARD -# define RB_GC_GUARD(x) (x) -#endif /* For compatibility with ruby < 2.7 */ diff --git a/ext/ffi_c/extconf.rb b/ext/ffi_c/extconf.rb index a03b433..b3eb020 100755 --- a/ext/ffi_c/extconf.rb +++ b/ext/ffi_c/extconf.rb @@ -63,6 +63,7 @@ if RUBY_ENGINE == 'ruby' || RUBY_ENGINE == 'rbx' append_ldflags "-pthread" ffi_alloc_default = RbConfig::CONFIG['host_os'] =~ /darwin/i && RbConfig::CONFIG['host'] =~ /arm|aarch64/i + ffi_alloc_default = ffi_alloc_default || RbConfig::CONFIG['host'] =~ /hppa/i if enable_config('libffi-alloc', ffi_alloc_default) $defs << "-DUSE_FFI_ALLOC" end diff --git a/lib/ffi/autopointer.rb b/lib/ffi/autopointer.rb index bd4c911..bbcb6db 100644 --- a/lib/ffi/autopointer.rb +++ b/lib/ffi/autopointer.rb @@ -84,13 +84,13 @@ module FFI if not proc.respond_to?(:call) raise RuntimeError.new("proc must be callable") end - CallableReleaser.new(ptr, proc) + Releaser.new(ptr, proc) else - if not self.class.respond_to?(:release) + if not self.class.respond_to?(:release, true) raise RuntimeError.new("no release method defined") end - DefaultReleaser.new(ptr, self.class) + Releaser.new(ptr, self.class.method(:release)) end ObjectSpace.define_finalizer(self, @releaser) @@ -150,23 +150,7 @@ module FFI def call(*args) release(@ptr) if @autorelease && @ptr end - end - - # DefaultReleaser is a {Releaser} used when an {AutoPointer} is defined - # without Proc or Method. In this case, the pointer to release must be of - # a class derived from AutoPointer with a {release} class method. - class DefaultReleaser < Releaser - # @param [Pointer] ptr - # @return [nil] - # Release +ptr+ using the {release} class method of its class. - def release(ptr) - @proc.release(ptr) - end - end - # CallableReleaser is a {Releaser} used when an {AutoPointer} is defined with a - # Proc or a Method. - class CallableReleaser < Releaser # Release +ptr+ by using Proc or Method defined at +ptr+ # {AutoPointer#initialize initialization}. # @@ -183,7 +167,7 @@ module FFI # @return [Type::POINTER] # @raise {RuntimeError} if class does not implement a +#release+ method def self.native_type - if not self.respond_to?(:release) + if not self.respond_to?(:release, true) raise RuntimeError.new("no release method defined for #{self.inspect}") end Type::POINTER diff --git a/lib/ffi/managedstruct.rb b/lib/ffi/managedstruct.rb index b5ec8a3..5d243e5 100644 --- a/lib/ffi/managedstruct.rb +++ b/lib/ffi/managedstruct.rb @@ -75,7 +75,7 @@ module FFI # @overload initialize # A new instance of FFI::ManagedStruct. def initialize(pointer=nil) - raise NoMethodError, "release() not implemented for class #{self}" unless self.class.respond_to? :release + raise NoMethodError, "release() not implemented for class #{self}" unless self.class.respond_to?(:release, true) raise ArgumentError, "Must supply a pointer to memory for the Struct" unless pointer super AutoPointer.new(pointer, self.class.method(:release)) end diff --git a/lib/ffi/platform/hppa1.1-linux/types.conf b/lib/ffi/platform/hppa1.1-linux/types.conf new file mode 100644 index 0000000..c8a8141 --- /dev/null +++ b/lib/ffi/platform/hppa1.1-linux/types.conf @@ -0,0 +1,178 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino64_t = ulong_long +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = ushort +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = ushort +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off64_t = long_long +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = uint +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = uint +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = int +rbx.platform.typedef.__kernel_size_t = uint +rbx.platform.typedef.__kernel_ssize_t = int +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds64_t = long_long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/lib/ffi/platform/hppa2.0-linux/types.conf b/lib/ffi/platform/hppa2.0-linux/types.conf new file mode 100644 index 0000000..c8a8141 --- /dev/null +++ b/lib/ffi/platform/hppa2.0-linux/types.conf @@ -0,0 +1,178 @@ +rbx.platform.typedef.*__caddr_t = char +rbx.platform.typedef.__blkcnt64_t = long_long +rbx.platform.typedef.__blkcnt_t = long +rbx.platform.typedef.__blksize_t = long +rbx.platform.typedef.__clock_t = long +rbx.platform.typedef.__clockid_t = int +rbx.platform.typedef.__daddr_t = int +rbx.platform.typedef.__dev_t = ulong_long +rbx.platform.typedef.__fd_mask = long +rbx.platform.typedef.__fsblkcnt64_t = ulong_long +rbx.platform.typedef.__fsblkcnt_t = ulong +rbx.platform.typedef.__fsfilcnt64_t = ulong_long +rbx.platform.typedef.__fsfilcnt_t = ulong +rbx.platform.typedef.__fsword_t = int +rbx.platform.typedef.__gid_t = uint +rbx.platform.typedef.__id_t = uint +rbx.platform.typedef.__ino64_t = ulong_long +rbx.platform.typedef.__ino_t = ulong +rbx.platform.typedef.__int16_t = short +rbx.platform.typedef.__int32_t = int +rbx.platform.typedef.__int64_t = long_long +rbx.platform.typedef.__int8_t = char +rbx.platform.typedef.__int_least16_t = short +rbx.platform.typedef.__int_least32_t = int +rbx.platform.typedef.__int_least64_t = long_long +rbx.platform.typedef.__int_least8_t = char +rbx.platform.typedef.__intmax_t = long_long +rbx.platform.typedef.__intptr_t = int +rbx.platform.typedef.__kernel_caddr_t = string +rbx.platform.typedef.__kernel_clock_t = long +rbx.platform.typedef.__kernel_clockid_t = int +rbx.platform.typedef.__kernel_daddr_t = int +rbx.platform.typedef.__kernel_gid16_t = ushort +rbx.platform.typedef.__kernel_gid32_t = uint +rbx.platform.typedef.__kernel_gid_t = uint +rbx.platform.typedef.__kernel_ino64_t = ulong_long +rbx.platform.typedef.__kernel_ino_t = ulong +rbx.platform.typedef.__kernel_ipc_pid_t = ushort +rbx.platform.typedef.__kernel_key_t = int +rbx.platform.typedef.__kernel_loff_t = long_long +rbx.platform.typedef.__kernel_long_t = long +rbx.platform.typedef.__kernel_mode_t = ushort +rbx.platform.typedef.__kernel_mqd_t = int +rbx.platform.typedef.__kernel_off64_t = long_long +rbx.platform.typedef.__kernel_off_t = long +rbx.platform.typedef.__kernel_old_dev_t = uint +rbx.platform.typedef.__kernel_old_gid_t = uint +rbx.platform.typedef.__kernel_old_time_t = long +rbx.platform.typedef.__kernel_old_uid_t = uint +rbx.platform.typedef.__kernel_pid_t = int +rbx.platform.typedef.__kernel_ptrdiff_t = int +rbx.platform.typedef.__kernel_size_t = uint +rbx.platform.typedef.__kernel_ssize_t = int +rbx.platform.typedef.__kernel_suseconds_t = long +rbx.platform.typedef.__kernel_time64_t = long_long +rbx.platform.typedef.__kernel_time_t = long +rbx.platform.typedef.__kernel_timer_t = int +rbx.platform.typedef.__kernel_uid16_t = ushort +rbx.platform.typedef.__kernel_uid32_t = uint +rbx.platform.typedef.__kernel_uid_t = uint +rbx.platform.typedef.__kernel_ulong_t = ulong +rbx.platform.typedef.__key_t = int +rbx.platform.typedef.__loff_t = long_long +rbx.platform.typedef.__mode_t = uint +rbx.platform.typedef.__nlink_t = uint +rbx.platform.typedef.__off64_t = long_long +rbx.platform.typedef.__off_t = long +rbx.platform.typedef.__pid_t = int +rbx.platform.typedef.__priority_which_t = int +rbx.platform.typedef.__quad_t = long_long +rbx.platform.typedef.__rlim64_t = ulong_long +rbx.platform.typedef.__rlim_t = ulong +rbx.platform.typedef.__rlimit_resource_t = int +rbx.platform.typedef.__rusage_who_t = int +rbx.platform.typedef.__sig_atomic_t = int +rbx.platform.typedef.__socklen_t = uint +rbx.platform.typedef.__ssize_t = int +rbx.platform.typedef.__suseconds64_t = long_long +rbx.platform.typedef.__suseconds_t = long +rbx.platform.typedef.__syscall_slong_t = long +rbx.platform.typedef.__syscall_ulong_t = ulong +rbx.platform.typedef.__thrd_t = ulong +rbx.platform.typedef.__time64_t = long_long +rbx.platform.typedef.__time_t = long +rbx.platform.typedef.__timer_t = pointer +rbx.platform.typedef.__tss_t = uint +rbx.platform.typedef.__u_char = uchar +rbx.platform.typedef.__u_int = uint +rbx.platform.typedef.__u_long = ulong +rbx.platform.typedef.__u_quad_t = ulong_long +rbx.platform.typedef.__u_short = ushort +rbx.platform.typedef.__uid_t = uint +rbx.platform.typedef.__uint16_t = ushort +rbx.platform.typedef.__uint32_t = uint +rbx.platform.typedef.__uint64_t = ulong_long +rbx.platform.typedef.__uint8_t = uchar +rbx.platform.typedef.__uint_least16_t = ushort +rbx.platform.typedef.__uint_least32_t = uint +rbx.platform.typedef.__uint_least64_t = ulong_long +rbx.platform.typedef.__uint_least8_t = uchar +rbx.platform.typedef.__uintmax_t = ulong_long +rbx.platform.typedef.__useconds_t = uint +rbx.platform.typedef.blkcnt_t = long_long +rbx.platform.typedef.blksize_t = long +rbx.platform.typedef.clock_t = long +rbx.platform.typedef.clockid_t = int +rbx.platform.typedef.daddr_t = int +rbx.platform.typedef.dev_t = ulong_long +rbx.platform.typedef.fd_mask = long +rbx.platform.typedef.fsblkcnt_t = ulong_long +rbx.platform.typedef.fsfilcnt_t = ulong_long +rbx.platform.typedef.gid_t = uint +rbx.platform.typedef.id_t = uint +rbx.platform.typedef.in_addr_t = uint +rbx.platform.typedef.in_port_t = ushort +rbx.platform.typedef.ino_t = ulong_long +rbx.platform.typedef.int16_t = short +rbx.platform.typedef.int32_t = int +rbx.platform.typedef.int64_t = long_long +rbx.platform.typedef.int8_t = char +rbx.platform.typedef.int_fast16_t = int +rbx.platform.typedef.int_fast32_t = int +rbx.platform.typedef.int_fast64_t = long_long +rbx.platform.typedef.int_fast8_t = char +rbx.platform.typedef.int_least16_t = short +rbx.platform.typedef.int_least32_t = int +rbx.platform.typedef.int_least64_t = long_long +rbx.platform.typedef.int_least8_t = char +rbx.platform.typedef.intmax_t = long_long +rbx.platform.typedef.intptr_t = int +rbx.platform.typedef.key_t = int +rbx.platform.typedef.loff_t = long_long +rbx.platform.typedef.mode_t = uint +rbx.platform.typedef.nlink_t = uint +rbx.platform.typedef.off_t = long_long +rbx.platform.typedef.pid_t = int +rbx.platform.typedef.pthread_key_t = uint +rbx.platform.typedef.pthread_once_t = int +rbx.platform.typedef.pthread_t = ulong +rbx.platform.typedef.ptrdiff_t = int +rbx.platform.typedef.quad_t = long_long +rbx.platform.typedef.register_t = long +rbx.platform.typedef.rlim_t = ulong_long +rbx.platform.typedef.sa_family_t = ushort +rbx.platform.typedef.size_t = uint +rbx.platform.typedef.socklen_t = uint +rbx.platform.typedef.ssize_t = int +rbx.platform.typedef.suseconds_t = long +rbx.platform.typedef.time_t = long +rbx.platform.typedef.timer_t = pointer +rbx.platform.typedef.u_char = uchar +rbx.platform.typedef.u_int = uint +rbx.platform.typedef.u_int16_t = ushort +rbx.platform.typedef.u_int32_t = uint +rbx.platform.typedef.u_int64_t = ulong_long +rbx.platform.typedef.u_int8_t = uchar +rbx.platform.typedef.u_long = ulong +rbx.platform.typedef.u_quad_t = ulong_long +rbx.platform.typedef.u_short = ushort +rbx.platform.typedef.uid_t = uint +rbx.platform.typedef.uint = uint +rbx.platform.typedef.uint16_t = ushort +rbx.platform.typedef.uint32_t = uint +rbx.platform.typedef.uint64_t = ulong_long +rbx.platform.typedef.uint8_t = uchar +rbx.platform.typedef.uint_fast16_t = uint +rbx.platform.typedef.uint_fast32_t = uint +rbx.platform.typedef.uint_fast64_t = ulong_long +rbx.platform.typedef.uint_fast8_t = uchar +rbx.platform.typedef.uint_least16_t = ushort +rbx.platform.typedef.uint_least32_t = uint +rbx.platform.typedef.uint_least64_t = ulong_long +rbx.platform.typedef.uint_least8_t = uchar +rbx.platform.typedef.uintmax_t = ulong_long +rbx.platform.typedef.uintptr_t = uint +rbx.platform.typedef.ulong = ulong +rbx.platform.typedef.ushort = ushort +rbx.platform.typedef.wchar_t = long diff --git a/spec/ffi/fixtures/ClosureTest.c b/spec/ffi/fixtures/ClosureTest.c index 16f72c4..47273e8 100644 --- a/spec/ffi/fixtures/ClosureTest.c +++ b/spec/ffi/fixtures/ClosureTest.c @@ -16,10 +16,10 @@ double testClosureVrDva(double d, ...) { va_list args; - double (*closure)(void); + typedef double (*closure_fun)(void); va_start(args, d); - closure = va_arg(args, double (*)(void)); + closure_fun closure = va_arg(args, closure_fun); va_end(args); return d + closure(); @@ -27,12 +27,12 @@ double testClosureVrDva(double d, ...) { long testClosureVrILva(int i, long l, ...) { va_list args; - int (*cl1)(int); - long (*cl2)(long); + typedef int (*cl1_fun)(int); + typedef long (*cl2_fun)(long); va_start(args, l); - cl1 = va_arg(args, int (*)(int)); - cl2 = va_arg(args, long (*)(long)); + cl1_fun cl1 = va_arg(args, cl1_fun); + cl2_fun cl2 = va_arg(args, cl2_fun); va_end(args); return cl1(i) + cl2(l); diff --git a/spec/ffi/fixtures/PipeHelperWindows.c b/spec/ffi/fixtures/PipeHelperWindows.c index 0bdbd2e..31b4a2a 100644 --- a/spec/ffi/fixtures/PipeHelperWindows.c +++ b/spec/ffi/fixtures/PipeHelperWindows.c @@ -16,7 +16,7 @@ int pipeHelperCreatePipe(FD_TYPE pipefd[2]) sprintf( name, "\\\\.\\Pipe\\pipeHelper-%u-%i", (unsigned int)GetCurrentProcessId(), pipe_idx++ ); - pipefd[0] = CreateNamedPipe( name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, + pipefd[0] = CreateNamedPipeA( name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_WAIT, 1, // Number of pipes 5, // Out buffer size @@ -26,7 +26,7 @@ int pipeHelperCreatePipe(FD_TYPE pipefd[2]) if(pipefd[0] == INVALID_HANDLE_VALUE) return -1; - pipefd[1] = CreateFile( name, GENERIC_WRITE, 0, NULL, + pipefd[1] = CreateFileA( name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); diff --git a/spec/ffi/fixtures/PointerTest.c b/spec/ffi/fixtures/PointerTest.c index a7f392a..02dbc27 100644 --- a/spec/ffi/fixtures/PointerTest.c +++ b/spec/ffi/fixtures/PointerTest.c @@ -5,7 +5,9 @@ */ #include <sys/types.h> +#ifndef _MSC_VER #include <sys/param.h> +#endif #include <stdint.h> #include <stdio.h> #include <stdlib.h> diff --git a/spec/ffi/gc_compact_spec.rb b/spec/ffi/gc_compact_spec.rb new file mode 100644 index 0000000..974d7f8 --- /dev/null +++ b/spec/ffi/gc_compact_spec.rb @@ -0,0 +1,66 @@ +# -*- rspec -*- +# encoding: utf-8 +# +# Tests to verify correct implementation of compaction callbacks in rb_data_type_t definitions. +# +# Compaction callbacks update moved VALUEs. +# In ruby-2.7 they are invoked only while GC.compact or GC.verify_compaction_references. +# Ruby constants are usually moved, but local variables are not. +# +# Effectiveness of the tests below should be verified by commenting the compact callback out like so: +# +# const rb_data_type_t rbffi_struct_layout_data_type = { +# .wrap_struct_name = "FFI::StructLayout", +# .function = { +# .dmark = struct_layout_mark, +# .dfree = struct_layout_free, +# .dsize = struct_layout_memsize, +# # ffi_compact_callback( struct_layout_compact ) +# }, +# .parent = &rbffi_type_data_type, +# .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED +# }; +# +# This should result in a segmentation fault aborting the whole process. +# Therefore the effectiveness of only one test can be verified per rspec run. + +require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper")) + +describe "GC.compact", if: GC.respond_to?(:compact) do + before :all do + + class St1 < FFI::Struct + layout :i, :int + end + ST1 = St1.new + + class St2 < FFI::Struct + layout :i, :int + end + ST2 = St2.new + ST2[:i] = 6789 + + begin + # Use GC.verify_compaction_references instead of GC.compact . + # This has the advantage that all movable objects are actually moved. + # The downside is that it doubles the heap space of the Ruby process. + # Therefore we call it only once and do several tests afterwards. + GC.verify_compaction_references(toward: :empty, double_heap: true) + rescue NotImplementedError, NoMethodError => err + skip("GC.compact skipped: #{err}") + end + end + + it "should compact FFI::StructLayout without field cache" do + expect( ST1[:i] ).to eq( 0 ) + end + + it "should compact FFI::StructLayout with field cache" do + expect( ST2[:i] ).to eq( 6789 ) + end + + it "should compact FFI::StructLayout::Field" do + l = St1.layout + expect( l.fields.first.type ).to eq( FFI::Type::Builtin::INT32 ) + end +end diff --git a/spec/ffi/managed_struct_spec.rb b/spec/ffi/managed_struct_spec.rb index b4e80bb..6299bdc 100644 --- a/spec/ffi/managed_struct_spec.rb +++ b/spec/ffi/managed_struct_spec.rb @@ -46,6 +46,8 @@ describe "Managed Struct" do def self.release(_ptr) @@count += 1 end + private_class_method :release + def self.wait_gc(count) loop = 5 while loop > 0 && @@count < count diff --git a/spec/ffi/pointer_spec.rb b/spec/ffi/pointer_spec.rb index 880ffd3..8716d30 100644 --- a/spec/ffi/pointer_spec.rb +++ b/spec/ffi/pointer_spec.rb @@ -264,6 +264,7 @@ describe "AutoPointer" do def self.release @@count += 1 if @@count > 0 end + private_class_method(:release) def self.reset @@count = 0 end @@ -282,10 +283,11 @@ describe "AutoPointer" do end class AutoPointerSubclass < FFI::AutoPointer def self.release(ptr); end + private_class_method(:release) end # see #427 - it "cleanup via default release method", :broken => true do + it "cleanup via default release method", gc_dependent: true do expect(AutoPointerSubclass).to receive(:release).at_least(loop_count-wiggle_room).times AutoPointerTestHelper.reset loop_count.times do @@ -298,7 +300,7 @@ describe "AutoPointer" do end # see #427 - it "cleanup when passed a proc", :broken => true do + it "cleanup when passed a proc", gc_dependent: true do # NOTE: passing a proc is touchy, because it's so easy to create a memory leak. # # specifically, if we made an inline call to @@ -317,7 +319,7 @@ describe "AutoPointer" do end # see #427 - it "cleanup when passed a method", :broken => true do + it "cleanup when passed a method", gc_dependent: true do expect(AutoPointerTestHelper).to receive(:release).at_least(loop_count-wiggle_room).times AutoPointerTestHelper.reset loop_count.times do @@ -334,6 +336,7 @@ describe "AutoPointer" do ffi_lib TestLibrary::PATH class CustomAutoPointer < FFI::AutoPointer def self.release(ptr); end + private_class_method(:release) end attach_function :ptr_from_address, [ FFI::Platform::ADDRESS_SIZE == 32 ? :uint : :ulong_long ], CustomAutoPointer end @@ -356,6 +359,7 @@ describe "AutoPointer" do describe "#autorelease?" do ptr_class = Class.new(FFI::AutoPointer) do def self.release(ptr); end + private_class_method(:release) end it "should be true by default" do @@ -377,6 +381,7 @@ describe "AutoPointer" do describe "#type_size" do ptr_class = Class.new(FFI::AutoPointer) do def self.release(ptr); end + private_class_method(:release) end it "type_size of AutoPointer should match wrapped Pointer" do diff --git a/spec/ffi/spec_helper.rb b/spec/ffi/spec_helper.rb index 3d8a025..22d1c47 100644 --- a/spec/ffi/spec_helper.rb +++ b/spec/ffi/spec_helper.rb @@ -8,7 +8,7 @@ require 'timeout' require 'objspace' RSpec.configure do |c| - c.filter_run_excluding :broken => true + c.filter_run_excluding gc_dependent: true unless ENV['FFI_TEST_GC'] == 'true' c.filter_run_excluding( :ractor ) unless defined?(Ractor) && RUBY_VERSION >= "3.1" end |