Daniel Berger
2012-Jul-02 21:45 UTC
[Win32utils-devel] Trouble getting a callback to work with FFI
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'')
Heesob Park
2012-Jul-03 00:43 UTC
[Win32utils-devel] Trouble getting a callback to work with FFI
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 ... Regards, Park Heesob -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/win32utils-devel/attachments/20120703/b27c89e9/attachment.html>
Daniel Berger
2012-Jul-03 13:26 UTC
[Win32utils-devel] Trouble getting a callback to work with FFI
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 lineThanks, 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? Regards, Dan
Daniel Berger
2012-Jul-03 14:24 UTC
[Win32utils-devel] Trouble getting a callback to work with FFI
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
Heesob Park
2012-Jul-03 15:15 UTC
[Win32utils-devel] Trouble getting a callback to work with FFI
Hi, 2012/7/3 Daniel Berger <djberg96 at gmail.com>> 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? > >First, I can see segfaults with MSVC++ version. Yet, I have no idea what is the cause. Second, the calling convention is the matter. cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer]){ |x,y,z| } should be cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer],{:convention =>:stdcall}){ |x,y,z| } Regards, Park Heesob -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/win32utils-devel/attachments/20120704/5ef9c641/attachment.html>
Daniel Berger
2012-Jul-03 16:14 UTC
[Win32utils-devel] Trouble getting a callback to work with FFI
On Tue, Jul 3, 2012 at 9:15 AM, Heesob Park <phasis at gmail.com> wrote:> Hi, > > 2012/7/3 Daniel Berger <djberg96 at gmail.com> >> >> 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? >> > > First, I can see segfaults with MSVC++ version. > Yet, I have no idea what is the cause. > > Second, the calling convention is the matter. > > cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer]){ |x,y,z| } > should be > cproc = FFI::Function.new(:void, [:ulong, :ulong, :pointer],{:convention > =>:stdcall}){ |x,y,z| }Ah, thanks. I thought it was automatic if I called it earlier. It probably should be, but I digress. I can make it work if I wrap the SleepEx call in its own thread, though I think that defeats the purpose of calling SleepEx in the first place, since it wouldn''t put the main thread in an alertable state, right? I suppose I could wrap the majority of the code in its own thread. Regards, Dan