ffi 1.0.9 → 1.0.10

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 (56) hide show
  1. data/Rakefile +4 -4
  2. data/ext/ffi_c/AbstractMemory.c +367 -14
  3. data/ext/ffi_c/AbstractMemory.h +4 -0
  4. data/ext/ffi_c/ArrayType.c +28 -0
  5. data/ext/ffi_c/Buffer.c +101 -25
  6. data/ext/ffi_c/Call.c +8 -5
  7. data/ext/ffi_c/ClosurePool.c +9 -8
  8. data/ext/ffi_c/DataConverter.c +29 -0
  9. data/ext/ffi_c/DynamicLibrary.c +64 -1
  10. data/ext/ffi_c/Function.c +111 -10
  11. data/ext/ffi_c/FunctionInfo.c +13 -1
  12. data/ext/ffi_c/LastError.c +16 -0
  13. data/ext/ffi_c/MappedType.c +22 -0
  14. data/ext/ffi_c/MemoryPointer.c +11 -1
  15. data/ext/ffi_c/MethodHandle.c +18 -11
  16. data/ext/ffi_c/Platform.c +9 -3
  17. data/ext/ffi_c/Pointer.c +98 -0
  18. data/ext/ffi_c/Struct.c +4 -4
  19. data/ext/ffi_c/Struct.h +2 -1
  20. data/ext/ffi_c/StructLayout.c +2 -2
  21. data/ext/ffi_c/Thread.c +124 -1
  22. data/ext/ffi_c/Type.c +108 -17
  23. data/ext/ffi_c/Types.c +9 -2
  24. data/ext/ffi_c/Variadic.c +5 -4
  25. data/ext/ffi_c/compat.h +8 -0
  26. data/ext/ffi_c/endian.h +7 -1
  27. data/ext/ffi_c/extconf.rb +46 -35
  28. data/ext/ffi_c/ffi.c +5 -0
  29. data/ext/ffi_c/libffi.darwin.mk +15 -15
  30. data/ext/ffi_c/libffi.gnu.mk +3 -3
  31. data/ext/ffi_c/libffi.mk +4 -4
  32. data/lib/ffi.rb +13 -9
  33. data/lib/ffi/autopointer.rb +88 -26
  34. data/lib/ffi/enum.rb +42 -0
  35. data/lib/ffi/errno.rb +6 -1
  36. data/lib/ffi/ffi.rb +1 -0
  37. data/lib/ffi/io.rb +13 -2
  38. data/lib/ffi/library.rb +212 -19
  39. data/lib/ffi/memorypointer.rb +1 -33
  40. data/lib/ffi/platform.rb +23 -7
  41. data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
  42. data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
  43. data/lib/ffi/platform/x86_64-freebsd/types.conf +126 -0
  44. data/lib/ffi/platform/x86_64-netbsd/types.conf +126 -0
  45. data/lib/ffi/pointer.rb +44 -0
  46. data/lib/ffi/struct.rb +1 -1
  47. data/lib/ffi/struct_layout_builder.rb +2 -1
  48. data/lib/ffi/tools/const_generator.rb +72 -17
  49. data/lib/ffi/types.rb +21 -1
  50. data/spec/ffi/rbx/memory_pointer_spec.rb +4 -2
  51. data/spec/ffi/struct_spec.rb +10 -0
  52. data/spec/ffi/typedef_spec.rb +11 -0
  53. data/tasks/extension.rake +0 -1
  54. data/tasks/gem.rake +0 -1
  55. data/tasks/yard.rake +11 -0
  56. metadata +15 -8
@@ -37,6 +37,7 @@ extern "C" {
37
37
  #define MEM_WR 0x02
38
38
  #define MEM_CODE 0x04
39
39
  #define MEM_SWAP 0x08
40
+ #define MEM_EMBED 0x10
40
41
 
41
42
  typedef struct AbstractMemory_ AbstractMemory;
42
43
 
@@ -60,6 +61,7 @@ typedef struct {
60
61
  MemoryOp* float64;
61
62
  MemoryOp* pointer;
62
63
  MemoryOp* strptr;
64
+ MemoryOp* boolOp;
63
65
  } MemoryOps;
64
66
 
65
67
  struct AbstractMemory_ {
@@ -136,6 +138,8 @@ get_memory_op(Type* type)
136
138
  return rbffi_AbstractMemoryOps.pointer;
137
139
  case NATIVE_STRING:
138
140
  return rbffi_AbstractMemoryOps.strptr;
141
+ case NATIVE_BOOL:
142
+ return rbffi_AbstractMemoryOps.boolOp;
139
143
  default:
140
144
  return NULL;
141
145
  }
@@ -62,6 +62,13 @@ array_type_free(ArrayType *array)
62
62
  }
63
63
 
64
64
 
65
+ /*
66
+ * call-seq: initialize(component_type, length)
67
+ * @param [Type] component_type
68
+ * @param [Numeric] length
69
+ * @return [self]
70
+ * A new instance of ArrayType.
71
+ */
65
72
  static VALUE
66
73
  array_type_initialize(VALUE self, VALUE rbComponentType, VALUE rbLength)
67
74
  {
@@ -86,6 +93,11 @@ array_type_initialize(VALUE self, VALUE rbComponentType, VALUE rbLength)
86
93
  return self;
87
94
  }
88
95
 
96
+ /*
97
+ * call-seq: length
98
+ * @return [Numeric]
99
+ * Get array's length
100
+ */
89
101
  static VALUE
90
102
  array_type_length(VALUE self)
91
103
  {
@@ -96,6 +108,11 @@ array_type_length(VALUE self)
96
108
  return UINT2NUM(array->length);
97
109
  }
98
110
 
111
+ /*
112
+ * call-seq: element_type
113
+ * @return [Type]
114
+ * Get element type.
115
+ */
99
116
  static VALUE
100
117
  array_type_element_type(VALUE self)
101
118
  {
@@ -109,8 +126,19 @@ array_type_element_type(VALUE self)
109
126
  void
110
127
  rbffi_ArrayType_Init(VALUE moduleFFI)
111
128
  {
129
+ /*
130
+ * Document-class: FFI::ArrayType < FFI::Type
131
+ *
132
+ * This is a typed array. The type is a {NativeType native type}.
133
+ */
112
134
  rbffi_ArrayTypeClass = rb_define_class_under(moduleFFI, "ArrayType", rbffi_TypeClass);
135
+ /*
136
+ * Document-variable: FFI::ArrayType
137
+ */
113
138
  rb_global_variable(&rbffi_ArrayTypeClass);
139
+ /*
140
+ * Document-constant: FFI::Type::Array
141
+ */
114
142
  rb_define_const(rbffi_TypeClass, "Array", rbffi_ArrayTypeClass);
115
143
 
116
144
  rb_define_alloc_func(rbffi_ArrayTypeClass, array_type_s_allocate);
@@ -26,10 +26,15 @@
26
26
  #include "endian.h"
27
27
  #include "AbstractMemory.h"
28
28
 
29
+ #define BUFFER_EMBED_MAXLEN (8)
29
30
  typedef struct Buffer {
30
31
  AbstractMemory memory;
31
- char* storage; /* start of malloc area */
32
- VALUE rbParent;
32
+
33
+ union {
34
+ VALUE rbParent; /* link to parent buffer */
35
+ char* storage; /* start of malloc area */
36
+ long embed[BUFFER_EMBED_MAXLEN / sizeof(long)]; // storage for tiny allocations
37
+ } data;
33
38
  } Buffer;
34
39
 
35
40
  static VALUE buffer_allocate(VALUE klass);
@@ -47,7 +52,7 @@ buffer_allocate(VALUE klass)
47
52
  VALUE obj;
48
53
 
49
54
  obj = Data_Make_Struct(klass, Buffer, NULL, buffer_release, buffer);
50
- buffer->rbParent = Qnil;
55
+ buffer->data.rbParent = Qnil;
51
56
  buffer->memory.flags = MEM_RD | MEM_WR;
52
57
 
53
58
  return obj;
@@ -56,14 +61,23 @@ buffer_allocate(VALUE klass)
56
61
  static void
57
62
  buffer_release(Buffer* ptr)
58
63
  {
59
- if (ptr->storage != NULL) {
60
- xfree(ptr->storage);
61
- ptr->storage = NULL;
64
+ if ((ptr->memory.flags & MEM_EMBED) == 0 && ptr->data.storage != NULL) {
65
+ xfree(ptr->data.storage);
66
+ ptr->data.storage = NULL;
62
67
  }
63
68
 
64
69
  xfree(ptr);
65
70
  }
66
71
 
72
+ /*
73
+ * call-seq: initialize(size, count=1, clear=false)
74
+ * @param [Integer, Symbol, #size] Type or size in bytes of a buffer cell
75
+ * @param [Fixnum] count number of cell in the Buffer
76
+ * @param [Boolean] clear if true, set the buffer to all-zero
77
+ * @return [self]
78
+ * @raise {NoMemoryError} if failed to allocate memory for Buffer
79
+ * A new instance of Buffer.
80
+ */
67
81
  static VALUE
68
82
  buffer_initialize(int argc, VALUE* argv, VALUE self)
69
83
  {
@@ -77,17 +91,23 @@ buffer_initialize(int argc, VALUE* argv, VALUE self)
77
91
  p->memory.typeSize = rbffi_type_size(rbSize);
78
92
  p->memory.size = p->memory.typeSize * (nargs > 1 ? NUM2LONG(rbCount) : 1);
79
93
 
80
- p->storage = xmalloc(p->memory.size + 7);
81
- if (p->storage == NULL) {
82
- rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", p->memory.size);
83
- return Qnil;
84
- }
94
+ if (p->memory.size > BUFFER_EMBED_MAXLEN) {
95
+ p->data.storage = xmalloc(p->memory.size + 7);
96
+ if (p->data.storage == NULL) {
97
+ rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", p->memory.size);
98
+ return Qnil;
99
+ }
85
100
 
86
- /* ensure the memory is aligned on at least a 8 byte boundary */
87
- p->memory.address = (void *) (((uintptr_t) p->storage + 0x7) & (uintptr_t) ~0x7UL);
101
+ /* ensure the memory is aligned on at least a 8 byte boundary */
102
+ p->memory.address = (void *) (((uintptr_t) p->data.storage + 0x7) & (uintptr_t) ~0x7UL);
103
+
104
+ if (p->memory.size > 0 && (nargs < 3 || RTEST(rbClear))) {
105
+ memset(p->memory.address, 0, p->memory.size);
106
+ }
88
107
 
89
- if (nargs > 2 && (RTEST(rbClear) || rbClear == Qnil) && p->memory.size > 0) {
90
- memset(p->memory.address, 0, p->memory.size);
108
+ } else {
109
+ p->memory.flags |= MEM_EMBED;
110
+ p->memory.address = (void *) &p->data.embed[0];
91
111
  }
92
112
 
93
113
  if (rb_block_given_p()) {
@@ -97,6 +117,11 @@ buffer_initialize(int argc, VALUE* argv, VALUE self)
97
117
  return self;
98
118
  }
99
119
 
120
+ /*
121
+ * call-seq: initialize_copy(other)
122
+ * @return [self]
123
+ * DO NOT CALL THIS METHOD.
124
+ */
100
125
  static VALUE
101
126
  buffer_initialize_copy(VALUE self, VALUE other)
102
127
  {
@@ -105,16 +130,16 @@ buffer_initialize_copy(VALUE self, VALUE other)
105
130
 
106
131
  Data_Get_Struct(self, Buffer, dst);
107
132
  src = rbffi_AbstractMemory_Cast(other, BufferClass);
108
- if (dst->storage != NULL) {
109
- xfree(dst->storage);
133
+ if ((dst->memory.flags & MEM_EMBED) == 0 && dst->data.storage != NULL) {
134
+ xfree(dst->data.storage);
110
135
  }
111
- dst->storage = xmalloc(src->size + 7);
112
- if (dst->storage == NULL) {
136
+ dst->data.storage = xmalloc(src->size + 7);
137
+ if (dst->data.storage == NULL) {
113
138
  rb_raise(rb_eNoMemError, "failed to allocate memory size=%lu bytes", src->size);
114
139
  return Qnil;
115
140
  }
116
141
 
117
- dst->memory.address = (void *) (((uintptr_t) dst->storage + 0x7) & (uintptr_t) ~0x7UL);
142
+ dst->memory.address = (void *) (((uintptr_t) dst->data.storage + 0x7) & (uintptr_t) ~0x7UL);
118
143
  dst->memory.size = src->size;
119
144
  dst->memory.typeSize = src->typeSize;
120
145
 
@@ -145,11 +170,17 @@ slice(VALUE self, long offset, long len)
145
170
  result->memory.size = len;
146
171
  result->memory.flags = ptr->memory.flags;
147
172
  result->memory.typeSize = ptr->memory.typeSize;
148
- result->rbParent = self;
173
+ result->data.rbParent = self;
149
174
 
150
175
  return obj;
151
176
  }
152
177
 
178
+ /*
179
+ * call-seq: + offset
180
+ * @param [Numeric] offset
181
+ * @return [Buffer] a new instance of Buffer pointing from offset until end of previous buffer.
182
+ * Add a Buffer with an offset
183
+ */
153
184
  static VALUE
154
185
  buffer_plus(VALUE self, VALUE rbOffset)
155
186
  {
@@ -161,12 +192,24 @@ buffer_plus(VALUE self, VALUE rbOffset)
161
192
  return slice(self, offset, ptr->memory.size - offset);
162
193
  }
163
194
 
195
+ /*
196
+ * call-seq: slice(offset, length)
197
+ * @param [Numeric] offset
198
+ * @param [Numeric] length
199
+ * @return [Buffer] a new instance of Buffer
200
+ * Slice an existing Buffer.
201
+ */
164
202
  static VALUE
165
203
  buffer_slice(VALUE self, VALUE rbOffset, VALUE rbLength)
166
204
  {
167
205
  return slice(self, NUM2LONG(rbOffset), NUM2LONG(rbLength));
168
206
  }
169
207
 
208
+ /*
209
+ * call-seq: inspect
210
+ * @return [String]
211
+ * Inspect a Buffer.
212
+ */
170
213
  static VALUE
171
214
  buffer_inspect(VALUE self)
172
215
  {
@@ -187,6 +230,16 @@ buffer_inspect(VALUE self)
187
230
  # define SWAPPED_ORDER LITTLE_ENDIAN
188
231
  #endif
189
232
 
233
+ /*
234
+ * Set or get endianness of Buffer.
235
+ * @overload order
236
+ * @return [:big, :little]
237
+ * Get endianness of Buffer.
238
+ * @overload order(order)
239
+ * @param [:big, :little, :network] order
240
+ * @return [self]
241
+ * Set endinaness of Buffer (+:network+ is an alias for +:big+).
242
+ */
190
243
  static VALUE
191
244
  buffer_order(int argc, VALUE* argv, VALUE self)
192
245
  {
@@ -232,9 +285,9 @@ buffer_free(VALUE self)
232
285
  Buffer* ptr;
233
286
 
234
287
  Data_Get_Struct(self, Buffer, ptr);
235
- if (ptr->storage != NULL) {
236
- xfree(ptr->storage);
237
- ptr->storage = NULL;
288
+ if ((ptr->memory.flags & MEM_EMBED) == 0 && ptr->data.storage != NULL) {
289
+ xfree(ptr->data.storage);
290
+ ptr->data.storage = NULL;
238
291
  }
239
292
 
240
293
  return self;
@@ -243,19 +296,42 @@ buffer_free(VALUE self)
243
296
  static void
244
297
  buffer_mark(Buffer* ptr)
245
298
  {
246
- rb_gc_mark(ptr->rbParent);
299
+ rb_gc_mark(ptr->data.rbParent);
247
300
  }
248
301
 
249
302
  void
250
303
  rbffi_Buffer_Init(VALUE moduleFFI)
251
304
  {
305
+ /*
306
+ * Document-class: FFI::Buffer < FFI::AbstractMemory
307
+ *
308
+ * A Buffer is a function argument type. It should be use with functions playing with C arrays.
309
+ */
252
310
  BufferClass = rb_define_class_under(moduleFFI, "Buffer", rbffi_AbstractMemoryClass);
253
311
 
312
+ /*
313
+ * Document-variable: FFI::Buffer
314
+ */
254
315
  rb_global_variable(&BufferClass);
255
316
  rb_define_alloc_func(BufferClass, buffer_allocate);
256
317
 
318
+ /*
319
+ * Document-method: alloc_inout
320
+ * call-seq: alloc_inout(*args)
321
+ * Create a new Buffer for in and out arguments (alias : <i>new_inout</i>).
322
+ */
257
323
  rb_define_singleton_method(BufferClass, "alloc_inout", buffer_alloc_inout, -1);
324
+ /*
325
+ * Document-method: alloc_out
326
+ * call-seq: alloc_out(*args)
327
+ * Create a new Buffer for out arguments (alias : <i>new_out</i>).
328
+ */
258
329
  rb_define_singleton_method(BufferClass, "alloc_out", buffer_alloc_inout, -1);
330
+ /*
331
+ * Document-method: alloc_in
332
+ * call-seq: alloc_in(*args)
333
+ * Create a new Buffer for in arguments (alias : <i>new_in</i>).
334
+ */
259
335
  rb_define_singleton_method(BufferClass, "alloc_in", buffer_alloc_inout, -1);
260
336
  rb_define_alias(rb_singleton_class(BufferClass), "new_in", "alloc_in");
261
337
  rb_define_alias(rb_singleton_class(BufferClass), "new_out", "alloc_out");
@@ -288,7 +288,7 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
288
288
  void** ffiValues;
289
289
  FFIStorage* params;
290
290
  VALUE rbReturnValue;
291
-
291
+
292
292
  #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
293
293
  rbffi_thread_t oldThread;
294
294
  #endif
@@ -329,7 +329,6 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
329
329
  oldThread = rbffi_active_thread;
330
330
  rbffi_active_thread = rbffi_thread_self();
331
331
  #endif
332
- retval = alloca(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
333
332
  ffi_call(&fnInfo->ffi_cif, FFI_FN(function), retval, ffiValues);
334
333
 
335
334
  #if !defined(HAVE_RUBY_THREAD_HAS_GVL_P)
@@ -339,9 +338,12 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
339
338
 
340
339
  if (unlikely(!fnInfo->ignoreErrno)) {
341
340
  rbffi_save_errno();
342
- }
343
-
344
- return rbffi_NativeValue_ToRuby(fnInfo->returnType, fnInfo->rbReturnType, retval);
341
+ }
342
+
343
+ RB_GC_GUARD(rbReturnValue) = rbffi_NativeValue_ToRuby(fnInfo->returnType, fnInfo->rbReturnType, retval);
344
+ RB_GC_GUARD(fnInfo->rbReturnType);
345
+
346
+ return rbReturnValue;
345
347
  }
346
348
 
347
349
  static inline void*
@@ -423,6 +425,7 @@ callback_param(VALUE proc, VALUE cbInfo)
423
425
 
424
426
  //callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
425
427
  callback = rbffi_Function_ForProc(cbInfo, proc);
428
+ RB_GC_GUARD(callback);
426
429
 
427
430
  return ((AbstractMemory *) DATA_PTR(callback))->address;
428
431
  }
@@ -28,6 +28,7 @@
28
28
  #ifndef _WIN32
29
29
  # include <unistd.h>
30
30
  #else
31
+ # define _WINSOCKAPI_
31
32
  # include <windows.h>
32
33
  #endif
33
34
  #include <errno.h>
@@ -68,7 +69,7 @@ struct ClosurePool_ {
68
69
  long refcnt;
69
70
  };
70
71
 
71
- static int pageSize;
72
+ static long pageSize;
72
73
 
73
74
  static void* allocatePage(void);
74
75
  static bool freePage(void *);
@@ -102,15 +103,14 @@ cleanup_closure_pool(ClosurePool* pool)
102
103
  free(memory);
103
104
  memory = next;
104
105
  }
105
- free(pool);
106
+ xfree(pool);
106
107
  }
107
108
 
108
109
  void
109
110
  rbffi_ClosurePool_Free(ClosurePool* pool)
110
111
  {
111
112
  if (pool != NULL) {
112
- int refcnt;
113
- refcnt = --(pool->refcnt);
113
+ long refcnt = --(pool->refcnt);
114
114
  if (refcnt == 0) {
115
115
  cleanup_closure_pool(pool);
116
116
  }
@@ -124,7 +124,8 @@ rbffi_Closure_Alloc(ClosurePool* pool)
124
124
  Memory* block = NULL;
125
125
  caddr_t code = NULL;
126
126
  char errmsg[256];
127
- int nclosures, trampolineSize;
127
+ int nclosures;
128
+ long trampolineSize;
128
129
  int i;
129
130
 
130
131
  if (pool->list != NULL) {
@@ -136,7 +137,7 @@ rbffi_Closure_Alloc(ClosurePool* pool)
136
137
  }
137
138
 
138
139
  trampolineSize = roundup(pool->closureSize, 8);
139
- nclosures = pageSize / trampolineSize;
140
+ nclosures = (int) (pageSize / trampolineSize);
140
141
  block = calloc(1, sizeof(*block));
141
142
  list = calloc(nclosures, sizeof(*list));
142
143
  code = allocatePage();
@@ -192,7 +193,7 @@ rbffi_Closure_Free(Closure* closure)
192
193
  {
193
194
  if (closure != NULL) {
194
195
  ClosurePool* pool = closure->pool;
195
- int refcnt;
196
+ long refcnt;
196
197
  // Just push it on the front of the free list
197
198
  closure->next = pool->list;
198
199
  pool->list = closure;
@@ -210,7 +211,7 @@ rbffi_Closure_CodeAddress(Closure* handle)
210
211
  }
211
212
 
212
213
 
213
- static int
214
+ static long
214
215
  getPageSize()
215
216
  {
216
217
  #if defined(_WIN32) || defined(__WIN32__)
@@ -11,6 +11,15 @@
11
11
  VALUE rbffi_DataConverterClass = Qnil;
12
12
  static ID id_native_type_ivar;
13
13
 
14
+ /*
15
+ * Get native type.
16
+ * @overload native_type(type)
17
+ * @param [String, Symbol, Type] type
18
+ * @return [Type]
19
+ * Get native type from +type+.
20
+ * @overload native_type
21
+ * @raise {NotImplementedError} This method must be overriden.
22
+ */
14
23
  static VALUE
15
24
  conv_native_type(int argc, VALUE* argv, VALUE self)
16
25
  {
@@ -33,12 +42,26 @@ conv_native_type(int argc, VALUE* argv, VALUE self)
33
42
  }
34
43
  }
35
44
 
45
+ /*
46
+ * call-seq: to_native(value, ctx)
47
+ * @param value
48
+ * @param ctx
49
+ * @return [value]
50
+ * Convert to a native type.
51
+ */
36
52
  static VALUE
37
53
  conv_to_native(VALUE self, VALUE value, VALUE ctx)
38
54
  {
39
55
  return value;
40
56
  }
41
57
 
58
+ /*
59
+ * call-seq: from_native(value, ctx)
60
+ * @param value
61
+ * @param ctx
62
+ * @return [value]
63
+ * Convert from a native type.
64
+ */
42
65
  static VALUE
43
66
  conv_from_native(VALUE self, VALUE value, VALUE ctx)
44
67
  {
@@ -50,6 +73,12 @@ conv_from_native(VALUE self, VALUE value, VALUE ctx)
50
73
  void
51
74
  rbffi_DataConverter_Init(VALUE moduleFFI)
52
75
  {
76
+ /*
77
+ * Document-module: FFI::DataConverter
78
+ * This module is used to extend somes classes and give then a common API.
79
+ *
80
+ * Most of methods defined here must be overriden.
81
+ */
53
82
  rbffi_DataConverterClass = rb_define_module_under(moduleFFI, "DataConverter");
54
83
 
55
84
  rb_define_method(rbffi_DataConverterClass, "native_type", conv_native_type, -1);