ffi 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (62) hide show
  1. data/Rakefile +52 -29
  2. data/ext/AbstractMemory.c +72 -28
  3. data/ext/AutoPointer.c +54 -0
  4. data/ext/AutoPointer.h +18 -0
  5. data/ext/Buffer.c +21 -17
  6. data/ext/Callback.c +81 -43
  7. data/ext/Callback.h +1 -1
  8. data/ext/Invoker.c +465 -108
  9. data/ext/MemoryPointer.c +25 -90
  10. data/ext/NativeLibrary.c +90 -0
  11. data/ext/NativeLibrary.h +22 -0
  12. data/ext/Platform.c +21 -2
  13. data/ext/Pointer.c +107 -0
  14. data/ext/Pointer.h +21 -0
  15. data/ext/Types.c +16 -5
  16. data/ext/Types.h +3 -1
  17. data/ext/compat.h +14 -0
  18. data/ext/extconf.rb +13 -1
  19. data/ext/ffi.c +11 -1
  20. data/ext/ffi.mk +3 -3
  21. data/ext/libffi.darwin.mk +19 -8
  22. data/gen/Rakefile +12 -0
  23. data/lib/ffi/autopointer.rb +61 -0
  24. data/lib/ffi/errno.rb +8 -0
  25. data/lib/ffi/ffi.rb +38 -201
  26. data/lib/ffi/io.rb +7 -0
  27. data/lib/ffi/library.rb +116 -0
  28. data/lib/ffi/managedstruct.rb +55 -0
  29. data/lib/ffi/memorypointer.rb +3 -96
  30. data/lib/ffi/platform.rb +8 -5
  31. data/lib/ffi/pointer.rb +105 -0
  32. data/lib/ffi/struct.rb +97 -42
  33. data/lib/ffi/tools/const_generator.rb +177 -0
  34. data/lib/ffi/tools/generator.rb +58 -0
  35. data/lib/ffi/tools/generator_task.rb +35 -0
  36. data/lib/ffi/tools/struct_generator.rb +194 -0
  37. data/lib/ffi/tools/types_generator.rb +123 -0
  38. data/lib/ffi/types.rb +150 -0
  39. data/lib/ffi/variadic.rb +30 -0
  40. data/nbproject/Makefile-Default.mk +6 -3
  41. data/nbproject/Makefile-impl.mk +5 -5
  42. data/nbproject/Package-Default.bash +72 -0
  43. data/nbproject/configurations.xml +139 -25
  44. data/nbproject/private/configurations.xml +1 -1
  45. data/nbproject/project.xml +4 -0
  46. data/samples/gettimeofday.rb +6 -2
  47. data/samples/inotify.rb +59 -0
  48. data/samples/pty.rb +75 -0
  49. data/specs/buffer_spec.rb +64 -9
  50. data/specs/callback_spec.rb +308 -4
  51. data/specs/errno_spec.rb +13 -0
  52. data/specs/library_spec.rb +55 -0
  53. data/specs/managed_struct_spec.rb +40 -0
  54. data/specs/number_spec.rb +183 -0
  55. data/specs/pointer_spec.rb +126 -0
  56. data/specs/rbx/memory_pointer_spec.rb +7 -7
  57. data/specs/spec_helper.rb +7 -0
  58. data/specs/string_spec.rb +34 -0
  59. data/specs/struct_spec.rb +223 -0
  60. data/specs/typedef_spec.rb +48 -0
  61. data/specs/variadic_spec.rb +84 -0
  62. metadata +270 -237
data/Rakefile CHANGED
@@ -1,16 +1,19 @@
1
1
  require 'rubygems'
2
2
  require 'rake/gempackagetask'
3
3
  require 'rubygems/specification'
4
- require "spec/rake/spectask"
5
4
  require 'date'
6
5
  require 'fileutils'
6
+ require 'rbconfig'
7
7
 
8
8
  GEM = "ffi"
9
- GEM_VERSION = "0.1.1"
9
+ GEM_VERSION = "0.2.0"
10
10
  AUTHOR = "Wayne Meissner"
11
11
  EMAIL = "wmeissner@gmail.com"
12
12
  HOMEPAGE = "http://kenai.com/projects/ruby-ffi"
13
13
  SUMMARY = "A Ruby foreign function interface (compatible with Rubinius and JRuby FFI)"
14
+ LIBEXT = Config::CONFIG['host_os'].downcase =~ /darwin/ ? "dylib" : "so"
15
+ GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd/ ? "gmake" : "make"
16
+ LIBTEST = "build/libtest.#{LIBEXT}"
14
17
 
15
18
  spec = Gem::Specification.new do |s|
16
19
  s.name = GEM
@@ -24,41 +27,33 @@ spec = Gem::Specification.new do |s|
24
27
  s.email = EMAIL
25
28
  s.homepage = HOMEPAGE
26
29
  s.rubyforge_project = 'ffi'
27
- s.extensions = %w(ext/extconf.rb)
30
+ s.extensions = %w(ext/extconf.rb gen/Rakefile)
28
31
 
29
32
  s.require_path = 'lib'
30
33
  s.autorequire = GEM
31
34
  s.files = %w(LICENSE README Rakefile) + Dir.glob("{ext,lib,nbproject,samples,specs}/**/*")
32
35
  end
33
-
34
- desc "Run all specs"
35
- Spec::Rake::SpecTask.new("specs") do |t|
36
- t.spec_opts = ["--format", "specdoc", "--colour"]
37
- t.spec_files = Dir["spec/**/*_spec.rb"].sort
38
- end
39
- desc "Run rubinius specs"
40
- Spec::Rake::SpecTask.new("rbxspecs") do |t|
41
- t.spec_opts = ["--format", "specdoc", "--colour"]
42
- t.spec_files = Dir["spec/rbx/*_spec.rb"].sort
43
- end
44
-
36
+ TEST_DEPS = [ LIBTEST ]
45
37
  if RUBY_PLATFORM == "java"
46
- desc "Run specs"
47
- task :specs do
38
+ desc "Run all specs"
39
+ task :specs => TEST_DEPS do
48
40
  sh %{#{Gem.ruby} -S spec #{Dir["specs/**/*_spec.rb"].join(" ")} -fs --color}
49
41
  end
50
- task :rbxspecs do
42
+ desc "Run rubinius specs"
43
+ task :rbxspecs => TEST_DEPS do
51
44
  sh %{#{Gem.ruby} -S spec #{Dir["specs/rbx/**/*_spec.rb"].join(" ")} -fs --color}
52
45
  end
53
46
  else
54
- desc "Run specs"
55
- task :specs do
47
+ TEST_DEPS.unshift :compile
48
+ desc "Run all specs"
49
+ task :specs => TEST_DEPS do
56
50
  ENV["MRI_FFI"] = "1"
57
- sh %{#{Gem.ruby} -S spec #{Dir["specs/**/*_spec.rb"].join(" ")} -fs --color}
51
+ sh %{#{Gem.ruby} -Ibuild -Ilib -S spec #{Dir["specs/**/*_spec.rb"].join(" ")} -fs --color}
58
52
  end
59
- task :rbxspecs do
53
+ desc "Run rubinius specs"
54
+ task :rbxspecs => TEST_DEPS do
60
55
  ENV["MRI_FFI"] = "1"
61
- sh %{#{Gem.ruby} -S spec #{Dir["specs/rbx/**/*_spec.rb"].join(" ")} -fs --color}
56
+ sh %{#{Gem.ruby} -Ibuild -Ilib -S spec #{Dir["specs/rbx/**/*_spec.rb"].join(" ")} -fs --color}
62
57
  end
63
58
  end
64
59
 
@@ -77,14 +72,42 @@ task :make_spec do
77
72
  file.puts spec.to_ruby
78
73
  end
79
74
  end
80
- file "Makefile" do
81
- sh %{#{Gem.ruby} ext/extconf.rb}
75
+ file "build/Makefile" do
76
+ FileUtils.mkdir_p("build") unless File.directory?("build")
77
+ sh %{cd build && #{Gem.ruby} ../ext/extconf.rb}
82
78
  end
83
- task :compile => "Makefile" do
84
- sh %{make}
79
+ desc "Compile the native module"
80
+ task :compile => "build/Makefile" do
81
+ sh %{cd build; make}
85
82
  end
83
+ desc "Clean all built files"
86
84
  task :clean do
87
- sh %{make clean} if File.exists?("Makefile")
85
+ sh %{cd build;make distclean} if File.exists?("build/Makefile")
88
86
  FileUtils.rm_rf("build")
89
- FileUtils.rm_f(Dir["pkg/*.gem", "Makefile"])
87
+ FileUtils.rm_rf("conftest.dSYM")
88
+ FileUtils.rm_f(Dir["pkg/*.gem"])
89
+ FileUtils.rm_f("Makefile")
90
90
  end
91
+ task "build/libtest.#{LIBEXT}" do
92
+ sh %{#{GMAKE} -f libtest/GNUmakefile}
93
+ end
94
+
95
+ desc "Test the extension"
96
+ task :test => [ :specs, :rbxspecs ] do
97
+
98
+ end
99
+ namespace :bench do
100
+ ITER = ENV['ITER'] ? ENV['ITER'].to_i : 100000
101
+ bench_libs = "-Ibuild -Ilib" unless RUBY_PLATFORM == "java"
102
+ bench_files = Dir["bench/bench_*.rb"].reject { |f| f == "bench_helper.rb" }
103
+ bench_files.each do |bench|
104
+ task File.basename(bench, ".rb")[6..-1] => TEST_DEPS do
105
+ sh %{#{Gem.ruby} #{bench_libs} #{bench} #{ITER}}
106
+ end
107
+ end
108
+ task :all => TEST_DEPS do
109
+ bench_files.each do |bench|
110
+ sh %{#{Gem.ruby} #{bench_libs} #{bench}}
111
+ end
112
+ end
113
+ end
@@ -4,8 +4,9 @@
4
4
  #include <stdbool.h>
5
5
  #include <ruby.h>
6
6
  #include "rbffi.h"
7
+ #include "compat.h"
7
8
  #include "AbstractMemory.h"
8
- #include "MemoryPointer.h"
9
+ #include "Pointer.h"
9
10
 
10
11
  static VALUE memory_put_float32(VALUE self, VALUE offset, VALUE value);
11
12
  static VALUE memory_get_float32(VALUE self, VALUE offset);
@@ -17,6 +18,7 @@ static VALUE memory_get_pointer(VALUE self, VALUE offset);
17
18
  static inline caddr_t memory_address(VALUE self);
18
19
  VALUE rb_FFI_AbstractMemory_class = Qnil;
19
20
  static VALUE classMemory = Qnil;
21
+ static ID to_ptr = 0;
20
22
 
21
23
  #define ADDRESS(self, offset) (memory_address((self)) + NUM2ULONG(offset))
22
24
  #ifndef RARRAY_LEN
@@ -98,19 +100,29 @@ memory_put_pointer(VALUE self, VALUE offset, VALUE value)
98
100
  {
99
101
  AbstractMemory* memory = (AbstractMemory *) DATA_PTR(self);
100
102
  long off = NUM2LONG(offset);
103
+ const int type = TYPE(value);
101
104
  checkBounds(memory, off, sizeof(void *));
102
- if (rb_obj_is_kind_of(value, rb_FFI_MemoryPointer_class)) {
105
+
106
+ if (rb_obj_is_kind_of(value, rb_FFI_Pointer_class) && type == T_DATA) {
103
107
  void* tmp = memory_address(value);
104
108
  memcpy(memory->address + off, &tmp, sizeof(tmp));
105
- } else if (TYPE(value) == T_NIL) {
109
+ } else if (type == T_NIL) {
106
110
  void* tmp = NULL;
107
111
  memcpy(memory->address + off, &tmp, sizeof(tmp));
108
- } else if (TYPE(value) == T_FIXNUM) {
112
+ } else if (type == T_FIXNUM) {
109
113
  uintptr_t tmp = (uintptr_t) FIX2INT(value);
110
114
  memcpy(memory->address + off, &tmp, sizeof(tmp));
111
- } else if (TYPE(value) == T_BIGNUM) {
115
+ } else if (type == T_BIGNUM) {
112
116
  uintptr_t tmp = (uintptr_t) NUM2ULL(value);
113
117
  memcpy(memory->address + off, &tmp, sizeof(tmp));
118
+ } else if (rb_respond_to(value, to_ptr)) {
119
+ VALUE ptr = rb_funcall2(value, to_ptr, 0, NULL);
120
+ if (rb_obj_is_kind_of(ptr, rb_FFI_Pointer_class) && TYPE(ptr) == T_DATA) {
121
+ void* tmp = memory_address(ptr);
122
+ memcpy(memory->address + off, &tmp, sizeof(tmp));
123
+ } else {
124
+ rb_raise(rb_eArgError, "to_ptr returned an invalid pointer");
125
+ }
114
126
  } else {
115
127
  rb_raise(rb_eArgError, "value is not a pointer");
116
128
  }
@@ -125,7 +137,7 @@ memory_get_pointer(VALUE self, VALUE offset)
125
137
  caddr_t tmp;
126
138
  checkBounds(memory, off, sizeof(tmp));
127
139
  memcpy(&tmp, memory->address + off, sizeof(tmp));
128
- return rb_FFI_MemoryPointer_new(tmp);
140
+ return rb_FFI_Pointer_new(tmp);
129
141
  }
130
142
 
131
143
  static VALUE
@@ -148,44 +160,71 @@ memory_get_string(int argc, VALUE* argv, VALUE self)
148
160
  VALUE length = Qnil, offset = Qnil;
149
161
  AbstractMemory* ptr = (AbstractMemory *) DATA_PTR(self);
150
162
  long off, len;
163
+ caddr_t end;
151
164
  int nargs = rb_scan_args(argc, argv, "11", &offset, &length);
152
165
 
153
- off = NUM2LONG(offset);
154
- if (nargs > 1) {
155
- len = NUM2LONG(length);
156
- } else {
157
- caddr_t end;
158
- checkBounds(ptr, off, 1);
159
- end = memchr(ptr->address + off, 0, ptr->size - off);
160
- len = ((end != NULL) ? end - ptr->address: ptr->size) - off;
161
- }
166
+ off = NUM2LONG(offset);
167
+ len = nargs > 1 && length != Qnil ? NUM2LONG(length) : (ptr->size - off);
162
168
  checkBounds(ptr, off, len);
163
- return rb_str_new((char *) ptr->address + off, len);
169
+ end = memchr(ptr->address + off, 0, len);
170
+ return rb_tainted_str_new((char *) ptr->address + off,
171
+ (end != NULL ? end - ptr->address - off : len));
164
172
  }
165
173
 
166
174
  static VALUE
167
- memory_put_string(int argc, VALUE* argv, VALUE self)
175
+ memory_put_string(VALUE self, VALUE offset, VALUE str)
168
176
  {
169
177
  AbstractMemory* ptr = (AbstractMemory *) DATA_PTR(self);
170
- VALUE offset = Qnil, str = Qnil, length = Qnil;
171
- bool nulTerminate = true;
172
178
  long off, len;
173
- int nargs = rb_scan_args(argc, argv, "21", &offset, &str, &length);
179
+
174
180
  off = NUM2LONG(offset);
175
181
  len = RSTRING_LEN(str);
176
- if (nargs > 2 && length != Qnil) {
177
- len = MIN(NUM2ULONG(length), len);
178
- nulTerminate = false;
179
- }
180
182
  checkBounds(ptr, off, len);
183
+ if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
184
+ rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
185
+ }
181
186
  memcpy(ptr->address + off, RSTRING_PTR(str), len);
187
+ *((char *) ptr->address + off + len) = '\0';
188
+ return self;
189
+ }
190
+
191
+ static VALUE
192
+ memory_get_bytes(VALUE self, VALUE offset, VALUE length)
193
+ {
194
+ AbstractMemory* ptr = (AbstractMemory *) DATA_PTR(self);
195
+ long off, len;
196
+
197
+ off = NUM2LONG(offset);
198
+ len = NUM2LONG(length);
199
+ checkBounds(ptr, off, len);
200
+ return rb_tainted_str_new((char *) ptr->address + off, len);
201
+ }
202
+
203
+ static VALUE
204
+ memory_put_bytes(int argc, VALUE* argv, VALUE self)
205
+ {
206
+ AbstractMemory* ptr = (AbstractMemory *) DATA_PTR(self);
207
+ VALUE offset = Qnil, str = Qnil, rbIndex = Qnil, rbLength = Qnil;
208
+ long off, len, idx;
209
+ int nargs = rb_scan_args(argc, argv, "22", &offset, &str, &rbIndex, &rbLength);
182
210
 
183
- if (nulTerminate) {
184
- char nul = '\0';
185
- memcpy(ptr->address + off + len, &nul, sizeof(nul));
211
+ off = NUM2LONG(offset);
212
+ idx = nargs > 2 ? NUM2LONG(rbIndex) : 0;
213
+ if (idx < 0) {
214
+ rb_raise(rb_eRangeError, "index canot be less than zero");
215
+ }
216
+ len = nargs > 3 ? NUM2LONG(rbLength) : (RSTRING_LEN(str) - idx);
217
+ if ((idx + len) > RSTRING_LEN(str)) {
218
+ rb_raise(rb_eRangeError, "index+length is greater than size of string");
219
+ }
220
+ checkBounds(ptr, off, len);
221
+ if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
222
+ rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
186
223
  }
224
+ memcpy(ptr->address + off, RSTRING_PTR(str) + idx, len);
187
225
  return self;
188
226
  }
227
+
189
228
  static inline caddr_t
190
229
  memory_address(VALUE self)
191
230
  {
@@ -250,8 +289,13 @@ rb_FFI_AbstractMemory_Init()
250
289
  rb_define_method(classMemory, "put_pointer", memory_put_pointer, 2);
251
290
  rb_define_method(classMemory, "get_pointer", memory_get_pointer, 1);
252
291
  rb_define_method(classMemory, "get_string", memory_get_string, -1);
253
- rb_define_method(classMemory, "put_string", memory_put_string, -1);
292
+ rb_define_method(classMemory, "put_string", memory_put_string, 2);
293
+ rb_define_method(classMemory, "get_bytes", memory_get_bytes, 2);
294
+ rb_define_method(classMemory, "put_bytes", memory_put_bytes, -1);
295
+
254
296
  rb_define_method(classMemory, "clear", memory_clear, 0);
255
297
  rb_define_method(classMemory, "total", memory_size, 0);
298
+
299
+ to_ptr = rb_intern("to_ptr");
256
300
  }
257
301
 
@@ -0,0 +1,54 @@
1
+
2
+ #include <stdbool.h>
3
+ #include <stdint.h>
4
+ #include <limits.h>
5
+ #include <ruby.h>
6
+ #include "rbffi.h"
7
+ #include "AbstractMemory.h"
8
+ #include "Pointer.h"
9
+ #include "AutoPointer.h"
10
+
11
+ typedef struct AutoPointer {
12
+ AbstractMemory memory;
13
+ VALUE parent;
14
+ } AutoPointer;
15
+
16
+ VALUE rb_FFI_AutoPointer_class;
17
+ static VALUE classAutoPointer = Qnil;
18
+ static void autoptr_mark(AutoPointer* ptr);
19
+ static void autoptr_free(AutoPointer* ptr);
20
+
21
+ static VALUE
22
+ autoptr_new(VALUE klass, VALUE other)
23
+ {
24
+ AutoPointer* p;
25
+ AbstractMemory* ptr;
26
+ VALUE retval;
27
+
28
+ retval = Data_Make_Struct(klass, AutoPointer, autoptr_mark, autoptr_free, p);
29
+ ptr = (AbstractMemory *) DATA_PTR(other);
30
+ p->memory = *ptr;
31
+ p->parent = other;
32
+ return retval;
33
+ }
34
+
35
+ static void
36
+ autoptr_mark(AutoPointer* ptr)
37
+ {
38
+ if (ptr->parent != Qnil) {
39
+ rb_gc_mark(ptr->parent);
40
+ }
41
+ }
42
+ static void
43
+ autoptr_free(AutoPointer* ptr)
44
+ {
45
+ xfree(ptr);
46
+ }
47
+
48
+ void
49
+ rb_FFI_AutoPointer_Init()
50
+ {
51
+ VALUE moduleFFI = rb_define_module("FFI");
52
+ rb_FFI_AutoPointer_class = classAutoPointer = rb_define_class_under(moduleFFI, "AutoPointer", rb_FFI_Pointer_class);
53
+ rb_define_singleton_method(classAutoPointer, "__alloc", autoptr_new, 1);
54
+ }
@@ -0,0 +1,18 @@
1
+
2
+ #ifndef _AUTOPOINTER_H
3
+ #define _AUTOPOINTER_H
4
+
5
+ #ifdef __cplusplus
6
+ extern "C" {
7
+ #endif
8
+
9
+ extern void rb_FFI_AutoPointer_Init(void);
10
+ extern VALUE rb_FFI_AutoPointer_class;
11
+
12
+
13
+ #ifdef __cplusplus
14
+ }
15
+ #endif
16
+
17
+ #endif /* _AUTOPOINTER_H */
18
+
@@ -7,6 +7,7 @@
7
7
 
8
8
  typedef struct Buffer {
9
9
  AbstractMemory memory;
10
+ caddr_t address; /* The C heap address */
10
11
  VALUE parent;
11
12
  } Buffer;
12
13
 
@@ -20,22 +21,24 @@ static VALUE
20
21
  buffer_allocate(VALUE self, VALUE size, VALUE count, VALUE clear)
21
22
  {
22
23
  Buffer* p;
24
+ VALUE retval;
25
+ unsigned long msize = NUM2LONG(size) * (count == Qnil ? 1 : NUM2LONG(count));
26
+ caddr_t memory;
23
27
 
24
- p = ALLOC(Buffer);
25
- memset(p, 0, sizeof(*p));
26
- p->memory.size = NUM2LONG(size) * (count == Qnil ? 1 : NUM2LONG(count));
27
- p->memory.address = p->memory.size > 0 ? malloc(p->memory.size) : NULL;
28
- p->parent = Qnil;
29
-
30
- if (p->memory.address == NULL) {
31
- int size = p->memory.size;
32
- xfree(p);
33
- rb_raise(rb_eNoMemError, "Failed to allocate memory size=%u bytes", size);
28
+ memory = malloc(msize + 7);
29
+ if (memory == NULL) {
30
+ rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", msize);
34
31
  }
35
- if (TYPE(clear) == T_TRUE) {
32
+ retval = Data_Make_Struct(classBuffer, Buffer, buffer_mark, buffer_release, p);
33
+ p->address = memory;
34
+ p->memory.size = msize;
35
+ /* ensure the memory is aligned on at least a 8 byte boundary */
36
+ p->memory.address = (caddr_t) (((uintptr_t) memory + 0x7) & (uintptr_t) ~0x7UL);;
37
+ p->parent = Qnil;
38
+ if (TYPE(clear) == T_TRUE && p->memory.size > 0) {
36
39
  memset(p->memory.address, 0, p->memory.size);
37
40
  }
38
- return Data_Wrap_Struct(classBuffer, buffer_mark, buffer_release, p);
41
+ return retval;
39
42
  }
40
43
 
41
44
  static VALUE
@@ -43,15 +46,15 @@ buffer_plus(VALUE self, VALUE offset)
43
46
  {
44
47
  Buffer* ptr = (Buffer *) DATA_PTR(self);
45
48
  Buffer* p;
49
+ VALUE retval;
46
50
  long off = NUM2LONG(offset);
47
51
 
48
52
  checkBounds(&ptr->memory, off, 1);
49
- p = ALLOC(Buffer);
50
- memset(p, 0, sizeof(*p));
53
+ retval = Data_Make_Struct(classBuffer, Buffer, buffer_mark, buffer_release, p);
51
54
  p->memory.address = ptr->memory.address + off;;
52
55
  p->memory.size = ptr->memory.size - off;
53
56
  p->parent = self;
54
- return Data_Wrap_Struct(classBuffer, buffer_mark, buffer_release, p);
57
+ return retval;
55
58
  }
56
59
 
57
60
  static VALUE
@@ -66,8 +69,9 @@ buffer_inspect(VALUE self)
66
69
  static void
67
70
  buffer_release(Buffer* ptr)
68
71
  {
69
- if (ptr->parent != Qnil && ptr->memory.address != NULL) {
70
- free(ptr->memory.address);
72
+ if (ptr->parent == Qnil && ptr->address != NULL) {
73
+ free(ptr->address);
74
+ ptr->address = NULL;
71
75
  }
72
76
  xfree(ptr);
73
77
 
@@ -1,50 +1,58 @@
1
+ #include <sys/param.h>
1
2
  #include <sys/types.h>
3
+ #include <sys/mman.h>
2
4
  #include <ruby.h>
3
- #include "MemoryPointer.h"
5
+ #include <ffi.h>
4
6
  #include "AbstractMemory.h"
7
+ #include "Pointer.h"
8
+ #include "MemoryPointer.h"
5
9
  #include "Callback.h"
6
10
  #include "Types.h"
7
11
  #include "rbffi.h"
12
+ #include "compat.h"
13
+ #include "extconf.h"
8
14
 
9
15
 
16
+ static void CallbackInfo_mark(CallbackInfo *);
17
+ static void CallbackInfo_free(CallbackInfo *);
10
18
 
11
- static void callback_mark(CallbackInfo *);
12
- static void callback_free(CallbackInfo *);
19
+ #if defined(HAVE_LIBFFI) && !defined(HAVE_FFI_CLOSURE_ALLOC)
20
+ static void* ffi_closure_alloc(size_t size, void** code);
21
+ static void ffi_closure_free(void* ptr);
22
+ ffi_status ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif,
23
+ void (*fun)(ffi_cif*, void*, void**, void*),
24
+ void* user_data, void* code);
25
+ #endif /* HAVE_FFI_CLOSURE_ALLOC */
13
26
 
14
- static VALUE classCallback = Qnil;
27
+ static VALUE classCallbackInfo = Qnil;
15
28
  static VALUE classNativeCallback = Qnil;
16
29
  static ID callID = Qnil;
17
30
 
18
- //static VALUE classCallbackImpl = Qnil;
19
- VALUE rb_FFI_Callback_class = Qnil;
31
+ VALUE rb_FFI_CallbackInfo_class = Qnil;
20
32
 
21
33
  static VALUE
22
- callback_new(VALUE self, VALUE rbReturnType, VALUE rbParamTypes)
34
+ CallbackInfo_new(VALUE klass, VALUE rbReturnType, VALUE rbParamTypes)
23
35
  {
24
- CallbackInfo *cbInfo = ALLOC(CallbackInfo);
36
+ CallbackInfo *cbInfo;
37
+ VALUE retval;
25
38
  int paramCount = RARRAY_LEN(rbParamTypes);
26
39
  ffi_status status;
27
40
  int i;
28
41
 
42
+ retval = Data_Make_Struct(klass, CallbackInfo, CallbackInfo_mark, CallbackInfo_free, cbInfo);
29
43
  cbInfo->parameterCount = paramCount;
30
- cbInfo->parameterTypes = calloc(paramCount, sizeof(NativeType));
31
- cbInfo->ffiParameterTypes = calloc(paramCount, sizeof(ffi_type *));
32
- if (cbInfo->parameterTypes == NULL || cbInfo->ffiParameterTypes == NULL) {
33
- callback_free(cbInfo);
34
- rb_raise(rb_eNoMemError, "Failed to allocate native memory");
35
- }
44
+ cbInfo->parameterTypes = xcalloc(paramCount, sizeof(NativeType));
45
+ cbInfo->ffiParameterTypes = xcalloc(paramCount, sizeof(ffi_type *));
36
46
  for (i = 0; i < paramCount; ++i) {
37
47
  cbInfo->parameterTypes[i] = FIX2INT(rb_ary_entry(rbParamTypes, i));
38
48
  cbInfo->ffiParameterTypes[i] = rb_FFI_NativeTypeToFFI(cbInfo->parameterTypes[i]);
39
49
  if (cbInfo->ffiParameterTypes[i] == NULL) {
40
- callback_free(cbInfo);
41
50
  rb_raise(rb_eArgError, "Unknown argument type: %#x", cbInfo->parameterTypes[i]);
42
51
  }
43
52
  }
44
53
  cbInfo->returnType = FIX2INT(rbReturnType);
45
54
  cbInfo->ffiReturnType = rb_FFI_NativeTypeToFFI(cbInfo->returnType);
46
55
  if (cbInfo->ffiReturnType == NULL) {
47
- callback_free(cbInfo);
48
56
  rb_raise(rb_eArgError, "Unknown return type: %#x", cbInfo->returnType);
49
57
  }
50
58
  #ifdef _WIN32
@@ -56,34 +64,33 @@ callback_new(VALUE self, VALUE rbReturnType, VALUE rbParamTypes)
56
64
  cbInfo->ffiReturnType, cbInfo->ffiParameterTypes);
57
65
  switch (status) {
58
66
  case FFI_BAD_ABI:
59
- callback_free(cbInfo);
60
67
  rb_raise(rb_eArgError, "Invalid ABI specified");
61
68
  case FFI_BAD_TYPEDEF:
62
- callback_free(cbInfo);
63
69
  rb_raise(rb_eArgError, "Invalid argument type specified");
64
70
  case FFI_OK:
65
71
  break;
66
72
  default:
67
- callback_free(cbInfo);
68
73
  rb_raise(rb_eArgError, "Unknown FFI error");
69
74
  }
70
- return Data_Wrap_Struct(classCallback, callback_mark, callback_free, cbInfo);
75
+ return retval;
71
76
  }
72
77
 
73
78
  static void
74
- callback_mark(CallbackInfo* cbinfo)
79
+ CallbackInfo_mark(CallbackInfo* cbinfo)
75
80
  {
76
81
  }
77
82
 
78
83
  static void
79
- callback_free(CallbackInfo* cbInfo)
84
+ CallbackInfo_free(CallbackInfo* cbInfo)
80
85
  {
81
86
  if (cbInfo != NULL) {
82
87
  if (cbInfo->parameterTypes != NULL) {
83
- free(cbInfo->parameterTypes);
88
+ xfree(cbInfo->parameterTypes);
89
+ cbInfo->parameterTypes = NULL;
84
90
  }
85
91
  if (cbInfo->ffiParameterTypes != NULL) {
86
- free(cbInfo->ffiParameterTypes);
92
+ xfree(cbInfo->ffiParameterTypes);
93
+ cbInfo->ffiParameterTypes = NULL;
87
94
  }
88
95
  xfree(cbInfo);
89
96
  }
@@ -120,19 +127,19 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
120
127
  VALUE param;
121
128
  switch (cbInfo->parameterTypes[i]) {
122
129
  case INT8:
123
- param = INT2FIX(*(int8_t *) parameters[i]);
130
+ param = INT2NUM(*(int8_t *) parameters[i]);
124
131
  break;
125
132
  case UINT8:
126
133
  param = UINT2NUM(*(u_int8_t *) parameters[i]);
127
134
  break;
128
135
  case INT16:
129
- param = INT2FIX(*(int16_t *) parameters[i]);
136
+ param = INT2NUM(*(int16_t *) parameters[i]);
130
137
  break;
131
138
  case UINT16:
132
139
  param = UINT2NUM(*(u_int16_t *) parameters[i]);
133
140
  break;
134
141
  case INT32:
135
- param = INT2FIX(*(int32_t *) parameters[i]);
142
+ param = INT2NUM(*(int32_t *) parameters[i]);
136
143
  break;
137
144
  case UINT32:
138
145
  param = UINT2NUM(*(u_int32_t *) parameters[i]);
@@ -150,10 +157,10 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
150
157
  param = rb_float_new(*(double *) parameters[i]);
151
158
  break;
152
159
  case STRING:
153
- param = rb_str_new2(*(char **) parameters[i]);
160
+ param = rb_tainted_str_new2(*(char **) parameters[i]);
154
161
  break;
155
162
  case POINTER:
156
- param = rb_FFI_MemoryPointer_new(*(caddr_t *) parameters[i]);
163
+ param = rb_FFI_Pointer_new(*(caddr_t *) parameters[i]);
157
164
  break;
158
165
  default:
159
166
  param = Qnil;
@@ -166,22 +173,14 @@ native_callback_invoke(ffi_cif* cif, void* retval, void** parameters, void* user
166
173
  memset(retval, 0, cbInfo->ffiReturnType->size);
167
174
  } else switch (cbInfo->returnType) {
168
175
  case INT8:
169
- *((int8_t *) retval) = NUM2INT(rbReturnValue);
170
- break;
171
- case UINT8:
172
- *((u_int8_t *) retval) = NUM2UINT(rbReturnValue);
173
- break;
174
176
  case INT16:
175
- *((int16_t *) retval) = NUM2INT(rbReturnValue);
176
- break;
177
- case UINT16:
178
- *((u_int16_t *) retval) = NUM2UINT(rbReturnValue);
179
- break;
180
177
  case INT32:
181
- *((int32_t *) retval) = NUM2INT(rbReturnValue);
178
+ *((long *) retval) = NUM2INT(rbReturnValue);
182
179
  break;
180
+ case UINT8:
181
+ case UINT16:
183
182
  case UINT32:
184
- *((u_int32_t *) retval) = NUM2UINT(rbReturnValue);
183
+ *((unsigned long *) retval) = NUM2UINT(rbReturnValue);
185
184
  break;
186
185
  case INT64:
187
186
  *((int64_t *) retval) = NUM2LL(rbReturnValue);
@@ -229,12 +228,51 @@ rb_FFI_NativeCallback_new(VALUE rbCallbackInfo, VALUE rbProc)
229
228
  return Data_Wrap_Struct(classNativeCallback, native_callback_mark, native_callback_free, closure);
230
229
  }
231
230
 
231
+ #if defined(HAVE_LIBFFI) && !defined(HAVE_FFI_CLOSURE_ALLOC)
232
+ /*
233
+ * versions of ffi_closure_alloc, ffi_closure_free and ffi_prep_closure_loc for older
234
+ * system libffi versions.
235
+ */
236
+ static void*
237
+ ffi_closure_alloc(size_t size, void** code)
238
+ {
239
+ void* closure;
240
+ closure = mmap(NULL, size, PROT_READ | PROT_WRITE,
241
+ MAP_ANON | MAP_PRIVATE, -1, 0);
242
+ if (closure == (void *) -1) {
243
+ return NULL;
244
+ }
245
+ memset(closure, 0, size);
246
+ *code = closure;
247
+ return closure;
248
+ }
249
+
250
+ static void
251
+ ffi_closure_free(void* ptr)
252
+ {
253
+ munmap(ptr, sizeof(ffi_closure));
254
+ }
255
+
256
+ ffi_status
257
+ ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif,
258
+ void (*fun)(ffi_cif*, void*, void**, void*),
259
+ void* user_data, void* code)
260
+ {
261
+ ffi_status retval = ffi_prep_closure(closure, cif, fun, user_data);
262
+ if (retval == FFI_OK) {
263
+ mprotect(closure, sizeof(ffi_closure), PROT_READ | PROT_EXEC);
264
+ }
265
+ return retval;
266
+ }
267
+
268
+ #endif /* HAVE_FFI_CLOSURE_ALLOC */
269
+
232
270
  void
233
271
  rb_FFI_Callback_Init()
234
272
  {
235
273
  VALUE moduleFFI = rb_define_module("FFI");
236
- rb_FFI_Callback_class = classCallback = rb_define_class_under(moduleFFI, "Callback", rb_cObject);
237
- rb_define_singleton_method(classCallback, "new", callback_new, 2);
274
+ rb_FFI_CallbackInfo_class = classCallbackInfo = rb_define_class_under(moduleFFI, "CallbackInfo", rb_cObject);
275
+ rb_define_singleton_method(classCallbackInfo, "new", CallbackInfo_new, 2);
238
276
  classNativeCallback = rb_define_class_under(moduleFFI, "NativeCallback", rb_cObject);
239
277
  callID = rb_intern("call");
240
278
  }