fiddle 1.0.0.beta1 → 1.0.3

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.
@@ -2,6 +2,7 @@
2
2
  * $Id$
3
3
  */
4
4
 
5
+ #include <stdbool.h>
5
6
  #include <ruby/ruby.h>
6
7
  #include <ruby/io.h>
7
8
  #include <ctype.h>
@@ -24,6 +25,7 @@ struct ptr_data {
24
25
  void *ptr;
25
26
  long size;
26
27
  freefunc_t free;
28
+ bool freed;
27
29
  VALUE wrap[2];
28
30
  };
29
31
 
@@ -57,14 +59,19 @@ fiddle_ptr_mark(void *ptr)
57
59
  }
58
60
 
59
61
  static void
60
- fiddle_ptr_free(void *ptr)
62
+ fiddle_ptr_free_ptr(void *ptr)
61
63
  {
62
64
  struct ptr_data *data = ptr;
63
- if (data->ptr) {
64
- if (data->free) {
65
- (*(data->free))(data->ptr);
66
- }
65
+ if (data->ptr && data->free && !data->freed) {
66
+ data->freed = true;
67
+ (*(data->free))(data->ptr);
67
68
  }
69
+ }
70
+
71
+ static void
72
+ fiddle_ptr_free(void *ptr)
73
+ {
74
+ fiddle_ptr_free_ptr(ptr);
68
75
  xfree(ptr);
69
76
  }
70
77
 
@@ -89,8 +96,8 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
89
96
  val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
90
97
  data->ptr = ptr;
91
98
  data->free = func;
99
+ data->freed = false;
92
100
  data->size = size;
93
- OBJ_TAINT(val);
94
101
 
95
102
  return val;
96
103
  }
@@ -102,13 +109,13 @@ rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
102
109
  }
103
110
 
104
111
  static VALUE
105
- rb_fiddle_ptr_malloc(long size, freefunc_t func)
112
+ rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
106
113
  {
107
114
  void *ptr;
108
115
 
109
116
  ptr = ruby_xmalloc((size_t)size);
110
117
  memset(ptr,0,(size_t)size);
111
- return rb_fiddle_ptr_new(ptr, size, func);
118
+ return rb_fiddle_ptr_new2(klass, ptr, size, func);
112
119
  }
113
120
 
114
121
  static void *
@@ -141,6 +148,7 @@ rb_fiddle_ptr_s_allocate(VALUE klass)
141
148
  data->ptr = 0;
142
149
  data->size = 0;
143
150
  data->free = 0;
151
+ data->freed = false;
144
152
 
145
153
  return obj;
146
154
  }
@@ -192,16 +200,53 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
192
200
  return Qnil;
193
201
  }
194
202
 
203
+ static VALUE
204
+ rb_fiddle_ptr_call_free(VALUE self);
205
+
195
206
  /*
196
207
  * call-seq:
197
- *
198
208
  * Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
209
+ * Fiddle::Pointer.malloc(size, freefunc) { |pointer| ... } => ...
210
+ *
211
+ * == Examples
212
+ *
213
+ * # Automatically freeing the pointer when the block is exited - recommended
214
+ * Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer|
215
+ * ...
216
+ * end
217
+ *
218
+ * # Manually freeing but relying on the garbage collector otherwise
219
+ * pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
220
+ * ...
221
+ * pointer.call_free
222
+ *
223
+ * # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe
224
+ * pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
225
+ * ...
226
+ *
227
+ * # Only manually freeing
228
+ * pointer = Fiddle::Pointer.malloc(size)
229
+ * begin
230
+ * ...
231
+ * ensure
232
+ * Fiddle.free pointer
233
+ * end
234
+ *
235
+ * # No free function and no call to free - the native memory will leak if the pointer is garbage collected
236
+ * pointer = Fiddle::Pointer.malloc(size)
237
+ * ...
199
238
  *
200
239
  * Allocate +size+ bytes of memory and associate it with an optional
201
- * +freefunc+ that will be called when the pointer is garbage collected.
240
+ * +freefunc+.
241
+ *
242
+ * If a block is supplied, the pointer will be yielded to the block instead of
243
+ * being returned, and the return value of the block will be returned. A
244
+ * +freefunc+ must be supplied if a block is.
202
245
  *
203
- * +freefunc+ must be an address pointing to a function or an instance of
204
- * Fiddle::Function
246
+ * If a +freefunc+ is supplied it will be called once, when the pointer is
247
+ * garbage collected or when the block is left if a block is supplied or
248
+ * when the user calls +call_free+, whichever happens first. +freefunc+ must be
249
+ * an address pointing to a function or an instance of +Fiddle::Function+.
205
250
  */
206
251
  static VALUE
207
252
  rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
@@ -223,10 +268,17 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
223
268
  rb_bug("rb_fiddle_ptr_s_malloc");
224
269
  }
225
270
 
226
- obj = rb_fiddle_ptr_malloc(s,f);
271
+ obj = rb_fiddle_ptr_malloc(klass, s,f);
227
272
  if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
228
273
 
229
- return obj;
274
+ if (rb_block_given_p()) {
275
+ if (!f) {
276
+ rb_raise(rb_eArgError, "a free function must be supplied to Fiddle::Pointer.malloc when it is called with a block");
277
+ }
278
+ return rb_ensure(rb_yield, obj, rb_fiddle_ptr_call_free, obj);
279
+ } else {
280
+ return obj;
281
+ }
230
282
  }
231
283
 
232
284
  /*
@@ -351,6 +403,34 @@ rb_fiddle_ptr_free_get(VALUE self)
351
403
  return rb_fiddle_new_function(address, arg_types, ret_type);
352
404
  }
353
405
 
406
+ /*
407
+ * call-seq: call_free => nil
408
+ *
409
+ * Call the free function for this pointer. Calling more than once will do
410
+ * nothing. Does nothing if there is no free function attached.
411
+ */
412
+ static VALUE
413
+ rb_fiddle_ptr_call_free(VALUE self)
414
+ {
415
+ struct ptr_data *pdata;
416
+ TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
417
+ fiddle_ptr_free_ptr(pdata);
418
+ return Qnil;
419
+ }
420
+
421
+ /*
422
+ * call-seq: freed? => bool
423
+ *
424
+ * Returns if the free function for this pointer has been called.
425
+ */
426
+ static VALUE
427
+ rb_fiddle_ptr_freed_p(VALUE self)
428
+ {
429
+ struct ptr_data *pdata;
430
+ TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
431
+ return pdata->freed ? Qtrue : Qfalse;
432
+ }
433
+
354
434
  /*
355
435
  * call-seq:
356
436
  *
@@ -376,11 +456,11 @@ rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
376
456
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
377
457
  switch (rb_scan_args(argc, argv, "01", &arg1)) {
378
458
  case 0:
379
- val = rb_tainted_str_new2((char*)(data->ptr));
459
+ val = rb_str_new2((char*)(data->ptr));
380
460
  break;
381
461
  case 1:
382
462
  len = NUM2INT(arg1);
383
- val = rb_tainted_str_new((char*)(data->ptr), len);
463
+ val = rb_str_new((char*)(data->ptr), len);
384
464
  break;
385
465
  default:
386
466
  rb_bug("rb_fiddle_ptr_to_s");
@@ -414,11 +494,11 @@ rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
414
494
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
415
495
  switch (rb_scan_args(argc, argv, "01", &arg1)) {
416
496
  case 0:
417
- val = rb_tainted_str_new((char*)(data->ptr),data->size);
497
+ val = rb_str_new((char*)(data->ptr),data->size);
418
498
  break;
419
499
  case 1:
420
500
  len = NUM2INT(arg1);
421
- val = rb_tainted_str_new((char*)(data->ptr), len);
501
+ val = rb_str_new((char*)(data->ptr), len);
422
502
  break;
423
503
  default:
424
504
  rb_bug("rb_fiddle_ptr_to_str");
@@ -440,7 +520,7 @@ rb_fiddle_ptr_inspect(VALUE self)
440
520
 
441
521
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
442
522
  return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
443
- RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free);
523
+ RB_OBJ_CLASSNAME(self), (void *)data, data->ptr, data->size, (void *)data->free);
444
524
  }
445
525
 
446
526
  /*
@@ -542,7 +622,7 @@ rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
542
622
  struct ptr_data *data;
543
623
 
544
624
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
545
- if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
625
+ if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
546
626
  switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
547
627
  case 1:
548
628
  offset = NUM2ULONG(arg0);
@@ -551,7 +631,7 @@ rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
551
631
  case 2:
552
632
  offset = NUM2ULONG(arg0);
553
633
  len = NUM2ULONG(arg1);
554
- retval = rb_tainted_str_new((char *)data->ptr + offset, len);
634
+ retval = rb_str_new((char *)data->ptr + offset, len);
555
635
  break;
556
636
  default:
557
637
  rb_bug("rb_fiddle_ptr_aref()");
@@ -580,7 +660,7 @@ rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
580
660
  struct ptr_data *data;
581
661
 
582
662
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
583
- if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
663
+ if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
584
664
  switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
585
665
  case 2:
586
666
  offset = NUM2ULONG(arg0);
@@ -661,7 +741,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
661
741
  wrap = 0;
662
742
  }
663
743
  else{
664
- rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
744
+ rb_raise(rb_eFiddleDLError, "to_ptr should return a Fiddle::Pointer object");
665
745
  }
666
746
  }
667
747
  else{
@@ -669,7 +749,6 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
669
749
  if (num == val) wrap = 0;
670
750
  ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
671
751
  }
672
- OBJ_INFECT(ptr, val);
673
752
  if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
674
753
  return ptr;
675
754
  }
@@ -677,6 +756,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
677
756
  void
678
757
  Init_fiddle_pointer(void)
679
758
  {
759
+ #undef rb_intern
680
760
  id_to_ptr = rb_intern("to_ptr");
681
761
 
682
762
  /* Document-class: Fiddle::Pointer
@@ -692,6 +772,8 @@ Init_fiddle_pointer(void)
692
772
  rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
693
773
  rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
694
774
  rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
775
+ rb_define_method(rb_cPointer, "call_free", rb_fiddle_ptr_call_free, 0);
776
+ rb_define_method(rb_cPointer, "freed?", rb_fiddle_ptr_freed_p, 0);
695
777
  rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
696
778
  rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
697
779
  rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);
File without changes
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/ruby
2
- # frozen_string_literal: false
2
+ # frozen_string_literal: true
3
3
  require 'fileutils'
4
4
 
5
5
  basedir = File.dirname(__FILE__)
@@ -32,7 +32,7 @@ IO.foreach("#{srcdir}/configure.ac") do |line|
32
32
  end
33
33
  end
34
34
 
35
- builddir = srcdir == "." ? enable['builddir'] : "."
35
+ builddir = srcdir == "." ? (enable['builddir'] || ".") : "."
36
36
  conf['TARGET'] = /^x64/ =~ host ? "X86_WIN64" : "X86_WIN32"
37
37
 
38
38
  FileUtils.mkdir_p([builddir, "#{builddir}/include", "#{builddir}/src/x86"])
File without changes
@@ -1,23 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ version_module = Module.new do
4
+ version_rb = File.join(__dir__, "lib/fiddle/version.rb")
5
+ module_eval(File.read(version_rb), version_rb, __LINE__)
6
+ end
7
+
1
8
  Gem::Specification.new do |spec|
2
9
  spec.name = "fiddle"
3
- spec.version = '1.0.0.beta1'
10
+ spec.version = version_module::Fiddle::VERSION
4
11
  spec.authors = ["Aaron Patterson", "SHIBATA Hiroshi"]
5
12
  spec.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org"]
6
13
 
7
14
  spec.summary = %q{A libffi wrapper for Ruby.}
8
15
  spec.description = %q{A libffi wrapper for Ruby.}
9
16
  spec.homepage = "https://github.com/ruby/fiddle"
10
- spec.license = "MIT"
17
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
11
18
 
12
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
13
- f.match(%r{^(test|spec|features)/})
14
- end
15
- spec.bindir = "exe"
16
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.files = [
20
+ "LICENSE.txt",
21
+ "README.md",
22
+ "Rakefile",
23
+ "bin/downloader.rb",
24
+ "bin/extlibs.rb",
25
+ "ext/fiddle/closure.c",
26
+ "ext/fiddle/closure.h",
27
+ "ext/fiddle/conversions.c",
28
+ "ext/fiddle/conversions.h",
29
+ "ext/fiddle/depend",
30
+ "ext/fiddle/extconf.rb",
31
+ "ext/fiddle/extlibs",
32
+ "ext/fiddle/fiddle.c",
33
+ "ext/fiddle/fiddle.h",
34
+ "ext/fiddle/function.c",
35
+ "ext/fiddle/function.h",
36
+ "ext/fiddle/handle.c",
37
+ "ext/fiddle/pinned.c",
38
+ "ext/fiddle/pointer.c",
39
+ "ext/fiddle/win32/fficonfig.h",
40
+ "ext/fiddle/win32/libffi-3.2.1-mswin.patch",
41
+ "ext/fiddle/win32/libffi-config.rb",
42
+ "ext/fiddle/win32/libffi.mk.tmpl",
43
+ "fiddle.gemspec",
44
+ "lib/fiddle.rb",
45
+ "lib/fiddle/closure.rb",
46
+ "lib/fiddle/cparser.rb",
47
+ "lib/fiddle/function.rb",
48
+ "lib/fiddle/import.rb",
49
+ "lib/fiddle/pack.rb",
50
+ "lib/fiddle/struct.rb",
51
+ "lib/fiddle/types.rb",
52
+ "lib/fiddle/value.rb",
53
+ "lib/fiddle/version.rb",
54
+ ]
17
55
  spec.require_paths = ["lib"]
56
+ spec.extensions = ["ext/fiddle/extconf.rb"]
57
+
58
+ spec.required_ruby_version = ">= 2.3.0"
18
59
 
19
60
  spec.add_development_dependency "bundler"
20
61
  spec.add_development_dependency "rake"
21
- spec.add_development_dependency "minitest", "~> 4.0"
22
62
  spec.add_development_dependency "rake-compiler"
63
+
64
+ spec.metadata["msys2_mingw_dependencies"] = "libffi"
23
65
  end
@@ -1,7 +1,9 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
+
2
3
  require 'fiddle.so'
3
- require 'fiddle/function'
4
4
  require 'fiddle/closure'
5
+ require 'fiddle/function'
6
+ require 'fiddle/version'
5
7
 
6
8
  module Fiddle
7
9
  if WINDOWS
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  module Fiddle
3
3
  class Closure
4
4
 
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  module Fiddle
3
3
  # A mixin that provides methods for parsing C struct and prototype signatures.
4
4
  #
@@ -21,6 +21,7 @@ module Fiddle
21
21
  # Parses a C struct's members
22
22
  #
23
23
  # Example:
24
+ # require 'fiddle/import'
24
25
  #
25
26
  # include Fiddle::CParser
26
27
  # #=> Object
@@ -34,12 +35,37 @@ module Fiddle
34
35
  def parse_struct_signature(signature, tymap=nil)
35
36
  if signature.is_a?(String)
36
37
  signature = split_arguments(signature, /[,;]/)
38
+ elsif signature.is_a?(Hash)
39
+ signature = [signature]
37
40
  end
38
41
  mems = []
39
42
  tys = []
40
43
  signature.each{|msig|
41
- msig = compact(msig)
44
+ msig = compact(msig) if msig.is_a?(String)
42
45
  case msig
46
+ when Hash
47
+ msig.each do |struct_name, struct_signature|
48
+ struct_name = struct_name.to_s if struct_name.is_a?(Symbol)
49
+ struct_name = compact(struct_name)
50
+ struct_count = nil
51
+ if struct_name =~ /^([\w\*\s]+)\[(\d+)\]$/
52
+ struct_count = $2.to_i
53
+ struct_name = $1
54
+ end
55
+ if struct_signature.respond_to?(:entity_class)
56
+ struct_type = struct_signature
57
+ else
58
+ parsed_struct = parse_struct_signature(struct_signature, tymap)
59
+ struct_type = CStructBuilder.create(CStruct, *parsed_struct)
60
+ end
61
+ if struct_count
62
+ ty = [struct_type, struct_count]
63
+ else
64
+ ty = struct_type
65
+ end
66
+ mems.push([struct_name, struct_type.members])
67
+ tys.push(ty)
68
+ end
43
69
  when /^[\w\*\s]+[\*\s](\w+)$/
44
70
  mems.push($1)
45
71
  tys.push(parse_ctype(msig, tymap))
@@ -66,6 +92,7 @@ module Fiddle
66
92
  # be looked up.
67
93
  #
68
94
  # Example:
95
+ # require 'fiddle/import'
69
96
  #
70
97
  # include Fiddle::CParser
71
98
  # #=> Object
@@ -102,6 +129,7 @@ module Fiddle
102
129
  # value will be the C type to be looked up.
103
130
  #
104
131
  # Example:
132
+ # require 'fiddle/import'
105
133
  #
106
134
  # include Fiddle::CParser
107
135
  # #=> Object
@@ -169,6 +197,8 @@ module Fiddle
169
197
  return TYPE_UINTPTR_T
170
198
  when /\*/, /\[[\s\d]*\]/
171
199
  return TYPE_VOIDP
200
+ when "..."
201
+ return TYPE_VARIADIC
172
202
  else
173
203
  ty = ty.split(' ', 2)[0]
174
204
  if( tymap[ty] )
@@ -183,7 +213,7 @@ module Fiddle
183
213
 
184
214
  def split_arguments(arguments, sep=',')
185
215
  return [] if arguments.strip == 'void'
186
- arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+)(?:#{sep}\s*|$)/).collect {|m| m[0]}
216
+ arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+|\.\.\.)(?:#{sep}\s*|$)/).collect {|m| m[0]}
187
217
  end
188
218
 
189
219
  def compact(signature)