[Win32utils-devel] Trouble getting a callback to work with FFI

Daniel Berger djberg96 at gmail.com
Tue Jul 3 14:24:09 UTC 2012


On Tue, Jul 3, 2012 at 7:26 AM, Daniel Berger <djberg96 at gmail.com> wrote:
> On Mon, Jul 2, 2012 at 6:43 PM, Heesob Park <phasis at gmail.com> wrote:
>> Hi,
>>
>> 2012/7/3 Daniel Berger <djberg96 at gmail.com>
>>>
>>> Hi,
>>>
>>> I'm getting a segfault when I try to pass a callback proc to
>>> ReadFileEx. The proc fires, then the interpreter segfaults.
>>>
>>> Any ideas? I tried a blocking callback, too, but that didn't help.
>>>
>>> require 'ffi'
>>>
>>> class Windows
>>>  extend FFI::Library
>>>  ffi_lib :kernel32
>>>
>>>  class Overlapped < FFI::Struct
>>>    layout(
>>>      :Internal, :ulong,
>>>      :InternalHigh, :ulong,
>>>      :Offset, :ulong,
>>>      :OffsetHigh, :ulong,
>>>      :hEvent, :ulong
>>>    )
>>>  end
>>>
>>>  callback :completion_proc, [:ulong, :ulong, Overlapped], :void
>>>
>>>  attach_function :CloseHandle, [:ulong], :bool
>>>  attach_function :CreateFileA, [:string, :ulong, :ulong, :pointer,
>>> :ulong, :ulong, :ulong], :ulong
>>>  attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong,
>>> Overlapped, :completion_proc], :bool
>>>  attach_function :GetOverlappedResult, [:ulong, :pointer, :pointer,
>>> :bool], :bool
>>>  attach_function :SleepEx, [:ulong, :bool], :ulong
>>>
>>>  OPEN_EXISTING             = 3
>>>  GENERIC_READ              = 0x80000000
>>>  FILE_SHARE_READ           = 0x00000001
>>>  FILE_FLAG_OVERLAPPED      = 0x40000000
>>>  FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000
>>>  INVALID_HANDLE_VALUE      = 0xFFFFFFFF
>>>  ERROR_IO_PENDING          = 997
>>>
>>>  def self.read(file)
>>>    flags = FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN
>>>
>>>    begin
>>>      handle = CreateFileA(
>>>        file,
>>>        GENERIC_READ,
>>>        FILE_SHARE_READ,
>>>        nil,
>>>        OPEN_EXISTING,
>>>        flags,
>>>        0
>>>      )
>>>
>>>      if handle == INVALID_HANDLE_VALUE
>>>        raise SystemCallError, FFI.errno, "CreateFile"
>>>      end
>>>
>>>      buf   = 0.chr * File.size(file)
>>>      olap  = Overlapped.new
>>>
>>>      cproc = Proc.new do |error, bytes, overlapped|
>>>        puts "Error: #{error}"
>>>        puts "Bytes: #{bytes}"
>>>        p overlapped
>>>      end
>>>
>>>      ### FAIL: cproc fires, but then I get a segfault
>>>      bool  = ReadFileEx(handle, buf, buf.size, olap, cproc)
>>>      errno = FFI.errno
>>>
>>>      SleepEx(1, true)
>>>
>>>      unless bool
>>>        if errno == ERROR_IO_PENDING
>>>          bytes = FFI::MemoryPointer.new(:ulong)
>>>          unless GetOverlappedResult(handle, olap, bytes, true)
>>>            raise SystemCallError, FFI.errno, "GetOverlappedResult"
>>>          end
>>>        else
>>>          raise SystemCallError, errno, "ReadFileEx"
>>>        end
>>>      end
>>>
>>>      buf.delete(0.chr)
>>>    ensure
>>>      CloseHandle(handle) if handle
>>>    end
>>>  end
>>> end
>>>
>>> File.open('small.txt', 'w'){ |fh| fh.puts "Hello World" }
>>> p Windows.read('small.txt')
>>>
>>
>> I guess this is due to the calling convention mismatch.
>>
>> If you add ffi_convention line, it will work.
>>
>> ...
>> class Windows
>>  extend FFI::Library
>>  ffi_lib :kernel32
>>  ffi_convention :stdcall  # add this line
>
> Thanks, I was thinking this was the default. However, I still noticed issues.
>
> First, it only seems to work with mingw. If I used the MSVC++ version
> it still bombs.
>
> Second, it only seems to work if I declare a callback in the function
> prototype and use a Proc. If I try to use a :pointer + FFI::Function,
> it still segfaults. In other words this works:
>
> callback :completion_proc, [:ulong, :ulong, Overlapped], :void
> attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong, Overlapped,
> :completion_proc], :bool
> cproc = Proc.new{ |x,y,z| }
>
> But this does not:
>
> attach_function :ReadFileEx, [:ulong, :buffer_out, :ulong, Overlapped,
> :pointer], :bool
> cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer]){ |x,y,z| }
>
> Do you see the same thing?

BTW, here's the output:

C:\Users\djberge\Repositories\win32-nio\lib\win32>ruby readfileex.rb
Error: 0
Bytes: 48
#<FFI::Pointer address=0x2ca9280>
readfileex.rb:74: [BUG] Segmentation fault
ruby 1.9.3p194 (2012-04-20 revision 35410) [i386-mswin32_100]

-- Control frame information -----------------------------------------------
c:0005 p:---- s:0024 b:0024 l:000023 d:000023 CFUNC  :SleepEx
c:0004 p:0232 s:0019 b:0019 l:0006e8 d:0006e8 METHOD readfileex.rb:74
c:0003 p:0040 s:0007 b:0006 l:0000fc d:00218c EVAL   readfileex.rb:94
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH
c:0001 p:0000 s:0002 b:0002 l:0000fc d:0000fc TOP

-- Ruby level backtrace information ----------------------------------------
readfileex.rb:94:in `<main>'
readfileex.rb:74:in `read'
readfileex.rb:74:in `SleepEx'

-- C level backtrace information -------------------------------------------
C:\Windows\SysWOW64\ntdll.dll(ZwWaitForSingleObject+0x15) [0x771CF8B1]
C:\Windows\syswow64\kernel32.dll(WaitForSingleObjectEx+0x43) [0x760E1194]
C:\Windows\syswow64\kernel32.dll(WaitForSingleObject+0x12) [0x760E1148]
c:\usr\bin\msvcr100-ruby191.dll(rb_vm_bugreport+0x95) [0x65087609]
c:\users\djberge\downlo
ads\ruby\ruby-1.9.3-p194\vm_dump.c:818
c:\usr\bin\msvcr100-ruby191.dll(report_bug+0xc7) [0x6501CDFD]
c:\users\djberge\downloads\r
uby\ruby-1.9.3-p194\error.c:260
c:\usr\bin\msvcr100-ruby191.dll(rb_bug+0x2b) [0x6501CE42]
c:\users\djberge\downloads\ruby\
ruby-1.9.3-p194\error.c:281
c:\usr\bin\msvcr100-ruby191.dll(sigsegv+0x3d) [0x65043400]
c:\users\djberge\downloads\ruby
\ruby-1.9.3-p194\signal.c:609
C:\Windows\system32\MSVCR100.dll(XcptFilter+0x13e) [0x7206AE8F]
c:\usr\bin\ruby.exe(__tmainCRTStartup+0x14a) [0x010A11E9]
f:\dd\vctools\crt_bld\self_x86\c
rt\src\crtexe.c:572
C:\Windows\system32\MSVCR100.dll(seh_longjmp_unwind4+0x2e) [0x71FE2FB4]
C:\Windows\syswow64\kernel32.dll(BaseThreadInitThunk+0x12) [0x760E339A]
C:\Windows\SysWOW64\ntdll.dll(RtlInitializeExceptionChain+0x63) [0x771E9EF2]

-- Other runtime information -----------------------------------------------

* Loaded script: readfileex.rb

* Loaded features:

    0 enumerator.so
    1 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/enc/encdb.so
    2 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/enc/iso_8859_1.so
    3 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/enc/trans/transdb.so
    4 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/defaults.rb
    5 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/rbconfig.rb
    6 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/deprecate.rb
    7 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/exceptions.rb
    8 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb
    9 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems.rb
   10 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/version.rb
   11 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/requirement.rb
   12 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/platform.rb
   13 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/specification.rb
   14 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/path_support.rb
   15 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/enc/utf_16le.so
   16 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/enc/trans/utf_16_32.so
   17 c:/usr/lib/ruby/1.9.1/i386-mswin32_100/enc/trans/single_byte.so
   18 c:/usr/lib/ruby/site_ruby/1.9.1/rubygems/dependency.rb
   19 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi_c.so
   20 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/platform.rb
   21 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/types.rb
   22 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/library.rb
   23 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/errno.rb
   24 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/pointer.rb
   25 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/memorypointer.rb
   26 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/struct_layout_builder.rb
   27 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/struct.rb
   28 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/union.rb
   29 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/managedstruct.rb
   30 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/callback.rb
   31 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/io.rb
   32 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/autopointer.rb
   33 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/variadic.rb
   34 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/enum.rb
   35 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi/ffi.rb
   36 c:/usr/lib/ruby/gems/1.9.1/gems/ffi-1.0.12.rc2/lib/ffi.rb

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html


More information about the win32utils-devel mailing list