fiddle 1.1.5 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0f57583928674b1ebb1313d3d079afd7f72b7103f1cdff830ef5aa77f868faa
4
- data.tar.gz: 0c2d7bbb4d6efd3da8f8023cb9b0d8de11b9baa3ab4e4f82d13e126e7eb301fd
3
+ metadata.gz: b031b86e4ccc2f94430cb9322a38e7d06932800eb597452f130f01329ecd78ed
4
+ data.tar.gz: 0b6ccf708b048792e7e6afec9f3f7114289b0d9755353c37d95857085f1fadef
5
5
  SHA512:
6
- metadata.gz: 6c7a270b8a8d967fcff910335e93051d8aaddaa0617387598ce90031f1c92170f58ba255de84b742a16eb6a2b647df45b07c91ee712c5c34247a6adceaacadc6
7
- data.tar.gz: 121958d7cc7be584a1146c3a1ded233ab52facc1f4a31e4e02e49a91b5293897b3e6ae9f5280264ecc5adfbf72165a84837c05a75a82eae70764f16f48d567ef
6
+ metadata.gz: 4e98b34f7c1deed926635fa0a99c24beadf19d4f5804acc87dec5ceab87a364a27538d5e715b1c7064b34cce8966de0b594a0a4c4131a3f9dfa5952935b2d1d5
7
+ data.tar.gz: 52782b8d2ab08ef3ac8cdecf78271b7e6fdcbc62e0e27bdad576034dfe0eabf410ba57f4809b14e0f26e24180c80f89234a812ead950088e1b56b80444e3ad47
data/Rakefile CHANGED
@@ -5,6 +5,15 @@ task :test do
5
5
  ruby("test/run.rb")
6
6
  end
7
7
 
8
+ release_task = Rake.application["release"]
9
+ release_task.prerequisites.delete("build")
10
+ release_task.prerequisites.delete("release:rubygem_push")
11
+ release_task_comment = release_task.comment
12
+ if release_task_comment
13
+ release_task.clear_comments
14
+ release_task.comment = release_task_comment.gsub(/ and build.*$/, "")
15
+ end
16
+
8
17
  namespace :version do
9
18
  desc "Bump version"
10
19
  task :bump do
data/ext/fiddle/pointer.c CHANGED
@@ -827,7 +827,8 @@ rb_fiddle_ptr_read_mem(VALUE klass, VALUE address, VALUE len)
827
827
  static VALUE
828
828
  rb_fiddle_ptr_write_mem(VALUE klass, VALUE addr, VALUE str)
829
829
  {
830
- memcpy(NUM2PTR(addr), StringValuePtr(str), RSTRING_LEN(str));
830
+ const char *ptr = StringValuePtr(str);
831
+ memcpy(NUM2PTR(addr), ptr, RSTRING_LEN(str));
831
832
  return str;
832
833
  }
833
834
 
@@ -247,7 +247,7 @@ module Fiddle
247
247
  return TYPE_INTPTR_T
248
248
  when /\Auintptr_t(?:\s+\w+)?\z/
249
249
  return TYPE_UINTPTR_T
250
- when "bool"
250
+ when /\Abool(?:\s+\w+)?\z/
251
251
  return TYPE_BOOL
252
252
  when /\*/, /\[[\s\d]*\]/
253
253
  return TYPE_VOIDP
@@ -159,15 +159,16 @@ module Fiddle
159
159
  args[i] = Fiddle::FFIBackend.to_ffi_type(args[i])
160
160
  end
161
161
  else
162
- args.map! do |arg|
163
- if arg.respond_to?(:to_ptr)
164
- begin
165
- arg = arg.to_ptr
166
- end until arg.is_a?(FFI::Pointer) || !arg.respond_to?(:to_ptr)
167
- arg
168
- else
169
- arg
170
- end
162
+ @args.each_with_index do |arg_type, i|
163
+ next unless arg_type == Types::VOIDP
164
+
165
+ src = args[i]
166
+ next if src.nil?
167
+ next if src.is_a?(String)
168
+ next if src.is_a?(FFI::AbstractMemory)
169
+ next if src.is_a?(FFI::Struct)
170
+
171
+ args[i] = Pointer[src]
171
172
  end
172
173
  end
173
174
  result = @function.call(*args, &block)
@@ -187,8 +188,10 @@ module Fiddle
187
188
  end
188
189
  return_type = Fiddle::FFIBackend.to_ffi_type(@ctype)
189
190
  raise "#{self.class} must implement #call" unless respond_to?(:call)
190
- callable = method(:call)
191
- @function = FFI::Function.new(return_type, ffi_args, callable, convention: abi)
191
+ wrapper = lambda do |*args|
192
+ call(*args.map { |v| v.is_a?(FFI::Pointer) ? Pointer.new(v) : v })
193
+ end
194
+ @function = FFI::Function.new(return_type, ffi_args, wrapper, convention: abi)
192
195
  @freed = false
193
196
  end
194
197
 
@@ -215,8 +218,8 @@ module Fiddle
215
218
  class DLError < Error; end
216
219
  class ClearedReferenceError < Error; end
217
220
 
221
+ # Pointer isn't thread safe for now
218
222
  class Pointer
219
- attr_reader :ffi_ptr
220
223
  extend FFI::DataConverter
221
224
  native_type FFI::Type::Builtin::POINTER
222
225
 
@@ -239,7 +242,7 @@ module Fiddle
239
242
  def self.to_ptr(value)
240
243
  if value.is_a?(String)
241
244
  cptr = Pointer.malloc(value.bytesize)
242
- cptr.ffi_ptr.put_string(0, value)
245
+ cptr.ffi_ptr.put_bytes(0, value)
243
246
  cptr
244
247
 
245
248
  elsif value.is_a?(Array)
@@ -261,6 +264,14 @@ module Fiddle
261
264
  end
262
265
  end
263
266
 
267
+ def self.write(addr, bytes)
268
+ FFI::Pointer.new(addr).write_bytes(bytes)
269
+ end
270
+
271
+ def self.read(addr, len)
272
+ FFI::Pointer.new(addr).read_bytes(len)
273
+ end
274
+
264
275
  class << self
265
276
  alias [] to_ptr
266
277
  end
@@ -274,7 +285,7 @@ module Fiddle
274
285
  value = value.to_str(args[1])
275
286
  end
276
287
 
277
- @ffi_ptr.put_bytes(args[0], value, 0, args[1])
288
+ ffi_ptr.put_bytes(args[0], value, 0, args[1])
278
289
  elsif args.size == 1
279
290
  if value.is_a?(Fiddle::Pointer)
280
291
  value = value.to_str(args[0] + 1)
@@ -282,7 +293,7 @@ module Fiddle
282
293
  value = value.chr
283
294
  end
284
295
 
285
- @ffi_ptr.put_bytes(args[0], value, 0, 1)
296
+ ffi_ptr.put_bytes(args[0], value, 0, 1)
286
297
  end
287
298
  rescue FFI::NullPointerError
288
299
  raise DLError.new("NULL pointer access")
@@ -308,14 +319,27 @@ module Fiddle
308
319
  end
309
320
  elsif addr.is_a?(IO)
310
321
  raise NotImplementedError, "IO ptr isn't supported"
322
+ else
323
+ FFI::Pointer.new(Integer(addr))
311
324
  end
312
325
 
313
- @size = size ? size : ptr.size
326
+ if size
327
+ @size = size
328
+ elsif ptr.size_limit?
329
+ @size = ptr.size
330
+ else
331
+ @size = 0
332
+ end
314
333
  @free = free
315
334
  @ffi_ptr = ptr
335
+ @addr_ptr = nil
316
336
  @freed = false
317
337
  end
318
338
 
339
+ def ffi_ptr
340
+ @addr_ptr ? @addr_ptr.get_pointer(0) : @ffi_ptr
341
+ end
342
+
319
343
  module LibC
320
344
  extend FFI::Library
321
345
  ffi_lib FFI::Library::LIBC
@@ -344,11 +368,11 @@ module Fiddle
344
368
  end
345
369
 
346
370
  def null?
347
- @ffi_ptr.null?
371
+ ffi_ptr.null?
348
372
  end
349
373
 
350
374
  def to_ptr
351
- @ffi_ptr
375
+ ffi_ptr
352
376
  end
353
377
 
354
378
  def size
@@ -367,9 +391,9 @@ module Fiddle
367
391
  return if @free.nil?
368
392
  return if @freed
369
393
  if @free == RUBY_FREE
370
- LibC::FREE.call(@ffi_ptr)
394
+ LibC::FREE.call(ffi_ptr)
371
395
  else
372
- @free.call(@ffi_ptr)
396
+ @free.call(ffi_ptr)
373
397
  end
374
398
  @freed = true
375
399
  end
@@ -397,12 +421,13 @@ module Fiddle
397
421
  end
398
422
  alias to_int to_i
399
423
 
400
- # without \0
401
424
  def to_s(len = nil)
402
425
  if len
403
- ffi_ptr.get_string(0, len)
426
+ ffi_ptr.read_string(len)
427
+ elsif @size == 0
428
+ ffi_ptr.read_string
404
429
  else
405
- ffi_ptr.get_string(0)
430
+ ffi_ptr.get_string(0, @size)
406
431
  end
407
432
  rescue FFI::NullPointerError
408
433
  raise DLError.new("NULL pointer access")
@@ -412,6 +437,9 @@ module Fiddle
412
437
  if len
413
438
  ffi_ptr.read_string(len)
414
439
  else
440
+ if @size < 0
441
+ raise ArgumentError.new("negative string size (or size too big)")
442
+ end
415
443
  ffi_ptr.read_string(@size)
416
444
  end
417
445
  rescue FFI::NullPointerError
@@ -423,7 +451,16 @@ module Fiddle
423
451
  end
424
452
 
425
453
  def inspect
426
- "#<#{self.class.name} ptr=#{to_i.to_s(16)} size=#{@size} free=#{@free.inspect}>"
454
+ # SIZEOF_VOIDP * 2 == Math.log(2 ** (SIZEOF_VOIDP * 8), 16)
455
+ pointer_inspect_width = SIZEOF_VOIDP * 2
456
+ "#<%s ptr=0x%0.*x size=%d free=0x%0.*x>" % [
457
+ self.class.name,
458
+ pointer_inspect_width,
459
+ to_i,
460
+ size,
461
+ pointer_inspect_width,
462
+ @free || 0,
463
+ ]
427
464
  end
428
465
 
429
466
  def +(delta)
@@ -463,9 +500,8 @@ module Fiddle
463
500
  end
464
501
 
465
502
  def ref
466
- cptr = Pointer.malloc(FFI::Type::POINTER.size, RUBY_FREE)
467
- cptr.ffi_ptr.put_pointer(0, ffi_ptr)
468
- cptr
503
+ @addr_ptr ||= FFI::MemoryPointer.new(:pointer).put_pointer(0, @ffi_ptr)
504
+ Pointer.new(@addr_ptr, 0)
469
505
  end
470
506
  end
471
507
 
@@ -1,3 +1,3 @@
1
1
  module Fiddle
2
- VERSION = "1.1.5"
2
+ VERSION = "1.1.7"
3
3
  end
data/lib/fiddle.rb CHANGED
@@ -10,98 +10,80 @@ require 'fiddle/function'
10
10
  require 'fiddle/version'
11
11
 
12
12
  module Fiddle
13
- if WINDOWS
14
- # Returns the last win32 +Error+ of the current executing +Thread+ or nil
15
- # if none
16
- def self.win32_last_error
17
- if RUBY_ENGINE == 'jruby'
18
- errno = FFI.errno
19
- errno == 0 ? nil : errno
20
- else
21
- Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
22
- end
13
+ if RUBY_ENGINE != 'ruby' # FFI backend
14
+ def self.last_error
15
+ FFI.errno
23
16
  end
24
17
 
25
- # Sets the last win32 +Error+ of the current executing +Thread+ to +error+
26
- def self.win32_last_error= error
27
- if RUBY_ENGINE == 'jruby'
28
- FFI.errno = error || 0
29
- else
30
- Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
31
- end
18
+ def self.last_error=(error)
19
+ FFI.errno = error || 0
32
20
  end
33
21
 
34
- # Returns the last win32 socket +Error+ of the current executing
35
- # +Thread+ or nil if none
36
- def self.win32_last_socket_error
37
- if RUBY_ENGINE == 'jruby'
38
- errno = FFI.errno
39
- errno == 0 ? nil : errno
40
- else
41
- Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
42
- end
43
- end
22
+ if WINDOWS
23
+ class << self
24
+ def win32_last_error
25
+ FFI.errno.nonzero?
26
+ end
27
+ def win32_last_error=(error)
28
+ FFI.errno = error || 0
29
+ end
44
30
 
45
- # Sets the last win32 socket +Error+ of the current executing
46
- # +Thread+ to +error+
47
- def self.win32_last_socket_error= error
48
- if RUBY_ENGINE == 'jruby'
49
- FFI.errno = error || 0
50
- else
51
- Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
31
+ def win32_last_socket_error
32
+ FFI.errno.nonzero?
33
+ end
34
+ def win32_last_socket_error=(error)
35
+ FFI.errno = error || 0
36
+ end
52
37
  end
53
38
  end
54
- end
55
-
56
- # Returns the last +Error+ of the current executing +Thread+ or nil if none
57
- def self.last_error
58
- if RUBY_ENGINE == 'jruby'
59
- errno = FFI.errno
60
- errno == 0 ? nil : errno
61
- else
39
+ else
40
+ # Returns the last +Error+ of the current executing +Thread+ or nil if none
41
+ def self.last_error
62
42
  Thread.current[:__FIDDLE_LAST_ERROR__]
63
43
  end
64
- end
65
44
 
66
- # Sets the last +Error+ of the current executing +Thread+ to +error+
67
- def self.last_error= error
68
- if RUBY_ENGINE == 'jruby'
69
- FFI.errno = error || 0
70
- else
45
+ # Sets the last +Error+ of the current executing +Thread+ to +error+
46
+ def self.last_error= error
71
47
  Thread.current[:__DL2_LAST_ERROR__] = error
72
48
  Thread.current[:__FIDDLE_LAST_ERROR__] = error
73
49
  end
50
+
51
+ if WINDOWS
52
+ # Returns the last win32 +Error+ of the current executing +Thread+ or nil
53
+ # if none
54
+ def self.win32_last_error
55
+ Thread.current[:__FIDDLE_WIN32_LAST_ERROR__]
56
+ end
57
+
58
+ # Sets the last win32 +Error+ of the current executing +Thread+ to +error+
59
+ def self.win32_last_error= error
60
+ Thread.current[:__FIDDLE_WIN32_LAST_ERROR__] = error
61
+ end
62
+
63
+ # Returns the last win32 socket +Error+ of the current executing
64
+ # +Thread+ or nil if none
65
+ def self.win32_last_socket_error
66
+ Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__]
67
+ end
68
+
69
+ # Sets the last win32 socket +Error+ of the current executing
70
+ # +Thread+ to +error+
71
+ def self.win32_last_socket_error= error
72
+ Thread.current[:__FIDDLE_WIN32_LAST_SOCKET_ERROR__] = error
73
+ end
74
+ end
74
75
  end
75
76
 
76
- # call-seq: dlopen(library) => Fiddle::Handle
77
- #
78
- # Creates a new handler that opens +library+, and returns an instance of
79
- # Fiddle::Handle.
80
- #
81
- # If +nil+ is given for the +library+, Fiddle::Handle::DEFAULT is used, which
82
- # is the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
83
- #
84
- # lib = Fiddle.dlopen(nil)
85
- #
86
- # The default is dependent on OS, and provide a handle for all libraries
87
- # already loaded. For example, in most cases you can use this to access
88
- # +libc+ functions, or ruby functions like +rb_str_new+.
89
- #
90
- # See Fiddle::Handle.new for more.
91
- def dlopen library
92
- begin
77
+ case RUBY_PLATFORM
78
+ when /linux/
79
+ def dlopen library
93
80
  Fiddle::Handle.new(library)
94
81
  rescue DLError => error
95
- case RUBY_PLATFORM
96
- when /linux/
97
- case error.message
98
- when /\A(\/.+?): (?:invalid ELF header|file too short)/
99
- # This may be a linker script:
100
- # https://sourceware.org/binutils/docs/ld.html#Scripts
101
- path = $1
102
- else
103
- raise
104
- end
82
+ case error.message
83
+ when /\A(\/.+?): (?:invalid ELF header|file too short)/
84
+ # This may be a linker script:
85
+ # https://sourceware.org/binutils/docs/ld.html#Scripts
86
+ path = $1
105
87
  else
106
88
  raise
107
89
  end
@@ -111,7 +93,11 @@ module Fiddle
111
93
  case line
112
94
  when /\A\s*(?:INPUT|GROUP)\s*\(\s*([^\s,\)]+)/
113
95
  # TODO: Should we support multiple files?
114
- return dlopen($1)
96
+ first_input = $1
97
+ if first_input.start_with?("-l")
98
+ first_input = "lib#{first_input[2..-1]}.so"
99
+ end
100
+ return dlopen(first_input)
115
101
  end
116
102
  end
117
103
  end
@@ -119,6 +105,25 @@ module Fiddle
119
105
  # Not found
120
106
  raise
121
107
  end
108
+ else
109
+ # call-seq: dlopen(library) => Fiddle::Handle
110
+ #
111
+ # Creates a new handler that opens +library+, and returns an instance of
112
+ # Fiddle::Handle.
113
+ #
114
+ # If +nil+ is given for the +library+, Fiddle::Handle::DEFAULT is used, which
115
+ # is the equivalent to RTLD_DEFAULT. See <code>man 3 dlopen</code> for more.
116
+ #
117
+ # lib = Fiddle.dlopen(nil)
118
+ #
119
+ # The default is dependent on OS, and provide a handle for all libraries
120
+ # already loaded. For example, in most cases you can use this to access
121
+ # +libc+ functions, or ruby functions like +rb_str_new+.
122
+ #
123
+ # See Fiddle::Handle.new for more.
124
+ def dlopen library
125
+ Fiddle::Handle.new(library)
126
+ end
122
127
  end
123
128
  module_function :dlopen
124
129
 
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fiddle
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.5
4
+ version: 1.1.7
5
5
  platform: ruby
6
- original_platform: ''
7
6
  authors:
8
7
  - Aaron Patterson
9
8
  - SHIBATA Hiroshi
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-11-09 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: A libffi wrapper for Ruby.
15
14
  email:
@@ -70,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
69
  - !ruby/object:Gem::Version
71
70
  version: '0'
72
71
  requirements: []
73
- rubygems_version: 3.6.0.dev
72
+ rubygems_version: 3.6.7
74
73
  specification_version: 4
75
74
  summary: A libffi wrapper for Ruby.
76
75
  test_files: []