ffi 0.4.0 → 0.5.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.
- data/README.rdoc +15 -15
- data/Rakefile +57 -8
- data/ext/ffi_c/AbstractMemory.c +101 -24
- data/ext/ffi_c/AbstractMemory.h +98 -6
- data/ext/ffi_c/ArrayType.c +129 -0
- data/ext/ffi_c/ArrayType.h +58 -0
- data/ext/ffi_c/AutoPointer.c +1 -0
- data/ext/ffi_c/Buffer.c +59 -43
- data/ext/ffi_c/Call.c +853 -0
- data/ext/ffi_c/Call.h +86 -0
- data/ext/ffi_c/ClosurePool.c +302 -0
- data/ext/ffi_c/ClosurePool.h +29 -0
- data/ext/ffi_c/DynamicLibrary.c +3 -0
- data/ext/ffi_c/Function.c +478 -0
- data/ext/ffi_c/Function.h +80 -0
- data/ext/ffi_c/FunctionInfo.c +221 -0
- data/ext/ffi_c/LastError.c +30 -6
- data/ext/ffi_c/MemoryPointer.c +50 -28
- data/ext/ffi_c/MethodHandle.c +346 -0
- data/ext/ffi_c/MethodHandle.h +53 -0
- data/ext/ffi_c/Pointer.c +73 -13
- data/ext/ffi_c/Pointer.h +31 -7
- data/ext/ffi_c/Struct.c +517 -224
- data/ext/ffi_c/Struct.h +60 -6
- data/ext/ffi_c/StructByValue.c +140 -0
- data/ext/ffi_c/StructByValue.h +53 -0
- data/ext/ffi_c/StructLayout.c +450 -0
- data/ext/ffi_c/Type.c +121 -22
- data/ext/ffi_c/Type.h +37 -8
- data/ext/ffi_c/Types.c +46 -61
- data/ext/ffi_c/Types.h +38 -7
- data/ext/ffi_c/Variadic.c +260 -0
- data/ext/ffi_c/compat.h +53 -3
- data/ext/ffi_c/extconf.rb +6 -7
- data/ext/ffi_c/ffi.c +45 -39
- data/ext/ffi_c/libffi.darwin.mk +2 -2
- data/ext/ffi_c/rbffi.h +3 -0
- data/lib/ffi/ffi.rb +7 -4
- data/lib/ffi/library.rb +34 -59
- data/lib/ffi/platform.rb +14 -4
- data/lib/ffi/struct.rb +110 -281
- data/lib/ffi/union.rb +4 -9
- data/lib/ffi/variadic.rb +1 -6
- data/spec/ffi/buffer_spec.rb +6 -0
- data/spec/ffi/callback_spec.rb +34 -3
- data/spec/ffi/function_spec.rb +73 -0
- data/spec/ffi/library_spec.rb +56 -52
- data/spec/ffi/pointer_spec.rb +3 -3
- data/spec/ffi/struct_callback_spec.rb +26 -3
- data/spec/ffi/struct_spec.rb +56 -3
- metadata +42 -11
- data/ext/ffi_c/Callback.c +0 -374
- data/ext/ffi_c/Callback.h +0 -47
- data/ext/ffi_c/Invoker.c +0 -962
- data/ext/ffi_c/NullPointer.c +0 -143
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
ruby-ffi
|
2
2
|
by Wayne Meissner
|
3
|
-
http://
|
3
|
+
http://wiki.github.com/ffi/ffi
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
@@ -8,7 +8,7 @@ Ruby-FFI is a ruby extension for programmatically loading dynamic
|
|
8
8
|
libraries, binding functions within them, and calling those functions
|
9
9
|
from Ruby code. Moreover, a Ruby-FFI extension works without changes
|
10
10
|
on Ruby and JRuby. Discover why should you write your next extension
|
11
|
-
using Ruby-FFI
|
11
|
+
using Ruby-FFI here[http://wiki.github.com/ffi/ffi/why-use-ffi].
|
12
12
|
|
13
13
|
== FEATURES/PROBLEMS:
|
14
14
|
|
@@ -32,8 +32,8 @@ using Ruby-FFI {here}[http://kenai.com/projects/ruby-ffi/pages/WhyUseFFI].
|
|
32
32
|
For less minimalistic and more sane examples you may look at:
|
33
33
|
|
34
34
|
* the samples/ folder
|
35
|
-
* the examples on the
|
36
|
-
* the projects using FFI listed on this
|
35
|
+
* the examples on the wiki[http://wiki.github.com/ffi/ffi]
|
36
|
+
* the projects using FFI listed on this page[http://wiki.github.com/ffi/ffi/projects-using-ffi]
|
37
37
|
|
38
38
|
== REQUIREMENTS:
|
39
39
|
|
@@ -45,24 +45,24 @@ From rubyforge:
|
|
45
45
|
|
46
46
|
[sudo] gem install ffi
|
47
47
|
|
48
|
-
or from the
|
48
|
+
or from the git repository on github:
|
49
49
|
|
50
|
-
|
51
|
-
cd
|
50
|
+
git clone git://github.com/ffi/ffi.git
|
51
|
+
cd ffi
|
52
52
|
rake gem:install
|
53
53
|
|
54
54
|
== CREDITS:
|
55
55
|
|
56
56
|
Special thanks to:
|
57
57
|
|
58
|
-
Yehuda Katz
|
59
|
-
Luc Heinrich
|
60
|
-
Andrea Fazzi
|
61
|
-
Mike Dalessio
|
62
|
-
Hongli Lai
|
63
|
-
Evan Phoenix
|
64
|
-
Aman Gupta
|
65
|
-
Beoran
|
58
|
+
* Yehuda Katz
|
59
|
+
* Luc Heinrich
|
60
|
+
* Andrea Fazzi
|
61
|
+
* Mike Dalessio
|
62
|
+
* Hongli Lai
|
63
|
+
* Evan Phoenix
|
64
|
+
* Aman Gupta
|
65
|
+
* Beoran
|
66
66
|
|
67
67
|
== LICENSE:
|
68
68
|
|
data/Rakefile
CHANGED
@@ -23,8 +23,52 @@ rescue LoadError
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
LIBEXT = Config::CONFIG['host_os'].downcase
|
27
|
-
|
26
|
+
LIBEXT = case Config::CONFIG['host_os'].downcase
|
27
|
+
when /darwin/
|
28
|
+
"dylib"
|
29
|
+
when /mswin|mingw/
|
30
|
+
"dll"
|
31
|
+
else
|
32
|
+
Config::CONFIG['DLEXT']
|
33
|
+
end
|
34
|
+
|
35
|
+
CPU = case Config::CONFIG['host_cpu'].downcase
|
36
|
+
when /i[3456]86/
|
37
|
+
# Darwin always reports i686, even when running in 64bit mode
|
38
|
+
if Config::CONFIG['host_os'] =~ /darwin/ && 0xfee1deadbeef.is_a?(Fixnum)
|
39
|
+
"x86_64"
|
40
|
+
else
|
41
|
+
"i386"
|
42
|
+
end
|
43
|
+
when /amd64|x86_64/
|
44
|
+
"x86_64"
|
45
|
+
when /ppc|powerpc/
|
46
|
+
"powerpc"
|
47
|
+
else
|
48
|
+
Config::CONFIG['host_cpu']
|
49
|
+
end
|
50
|
+
|
51
|
+
OS = case Config::CONFIG['host_os'].downcase
|
52
|
+
when /linux/
|
53
|
+
"linux"
|
54
|
+
when /darwin/
|
55
|
+
"darwin"
|
56
|
+
when /freebsd/
|
57
|
+
"freebsd"
|
58
|
+
when /openbsd/
|
59
|
+
"openbsd"
|
60
|
+
when /sunos|solaris/
|
61
|
+
"solaris"
|
62
|
+
when /mswin|mingw/
|
63
|
+
"win32"
|
64
|
+
else
|
65
|
+
Config::CONFIG['host_os'].downcase
|
66
|
+
end
|
67
|
+
|
68
|
+
CC=ENV['CC'] || Config::CONFIG['CC'] || "gcc"
|
69
|
+
|
70
|
+
GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd|solaris/ ? "gmake" : "make"
|
71
|
+
|
28
72
|
LIBTEST = "build/libtest.#{LIBEXT}"
|
29
73
|
BUILD_DIR = "build"
|
30
74
|
BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_VERSION)
|
@@ -33,8 +77,8 @@ BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_
|
|
33
77
|
PROJ.name = 'ffi'
|
34
78
|
PROJ.authors = 'Wayne Meissner'
|
35
79
|
PROJ.email = 'wmeissner@gmail.com'
|
36
|
-
PROJ.url = 'http://
|
37
|
-
PROJ.version = '0.
|
80
|
+
PROJ.url = 'http://wiki.github.com/ffi/ffi'
|
81
|
+
PROJ.version = '0.5.0'
|
38
82
|
PROJ.rubyforge.name = 'ffi'
|
39
83
|
PROJ.readme_file = 'README.rdoc'
|
40
84
|
|
@@ -42,7 +86,7 @@ PROJ.readme_file = 'README.rdoc'
|
|
42
86
|
PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
|
43
87
|
|
44
88
|
PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
|
45
|
-
PROJ.ann.email[:to] << '
|
89
|
+
PROJ.ann.email[:to] << 'ruby-ffi@groups.google.com'
|
46
90
|
PROJ.ann.email[:server] = 'smtp.gmail.com'
|
47
91
|
|
48
92
|
# Gem specifications
|
@@ -61,9 +105,14 @@ PROJ.rdoc.opts << '-x' << 'ext'
|
|
61
105
|
PROJ.ruby_opts = []
|
62
106
|
PROJ.ruby_opts << '-I' << BUILD_EXT_DIR unless RUBY_PLATFORM == "java"
|
63
107
|
|
64
|
-
#RSpec
|
108
|
+
# RSpec
|
109
|
+
PROJ.spec.files.exclude /rbx/
|
65
110
|
PROJ.spec.opts << '--color' << '-fs'
|
66
111
|
|
112
|
+
# Dependencies
|
113
|
+
|
114
|
+
depend_on 'rake', '>=0.8.7'
|
115
|
+
|
67
116
|
TEST_DEPS = [ LIBTEST ]
|
68
117
|
if RUBY_PLATFORM == "java"
|
69
118
|
desc "Run all specs"
|
@@ -98,7 +147,7 @@ task :install => 'gem:install'
|
|
98
147
|
desc "Clean all built files"
|
99
148
|
task :distclean => :clobber do
|
100
149
|
FileUtils.rm_rf('build')
|
101
|
-
FileUtils.rm_rf(Dir[
|
150
|
+
FileUtils.rm_rf(Dir["lib/**/ffi_c.#{Config::CONFIG['DLEXT']}"])
|
102
151
|
FileUtils.rm_rf('lib/1.8')
|
103
152
|
FileUtils.rm_rf('lib/1.9')
|
104
153
|
FileUtils.rm_rf('conftest.dSYM')
|
@@ -108,7 +157,7 @@ end
|
|
108
157
|
|
109
158
|
desc "Build the native test lib"
|
110
159
|
task "build/libtest.#{LIBEXT}" do
|
111
|
-
sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{
|
160
|
+
sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{CPU} OS=#{OS} }
|
112
161
|
end
|
113
162
|
|
114
163
|
|
data/ext/ffi_c/AbstractMemory.c
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2008, 2009, Wayne Meissner
|
3
|
+
*
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions are met:
|
8
|
+
*
|
9
|
+
* * Redistributions of source code must retain the above copyright notice, this
|
10
|
+
* list of conditions and the following disclaimer.
|
11
|
+
* * Redistributions in binary form must reproduce the above copyright notice
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
* * The name of the author or authors may not be used to endorse or promote
|
15
|
+
* products derived from this software without specific prior written permission.
|
16
|
+
*
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
*/
|
28
|
+
|
1
29
|
#include <sys/types.h>
|
2
30
|
#include <sys/param.h>
|
3
31
|
#include <stdint.h>
|
@@ -7,13 +35,13 @@
|
|
7
35
|
#include "compat.h"
|
8
36
|
#include "AbstractMemory.h"
|
9
37
|
#include "Pointer.h"
|
10
|
-
#include "
|
38
|
+
#include "Function.h"
|
11
39
|
|
12
40
|
|
13
41
|
static inline char* memory_address(VALUE self);
|
14
42
|
VALUE rbffi_AbstractMemoryClass = Qnil;
|
15
|
-
static
|
16
|
-
static ID id_call = 0;
|
43
|
+
static VALUE NullPointerErrorClass = Qnil;
|
44
|
+
static ID id_to_ptr = 0, id_plus = 0, id_call = 0;
|
17
45
|
|
18
46
|
static VALUE
|
19
47
|
memory_allocate(VALUE klass)
|
@@ -22,6 +50,7 @@ memory_allocate(VALUE klass)
|
|
22
50
|
VALUE obj;
|
23
51
|
obj = Data_Make_Struct(klass, AbstractMemory, NULL, -1, memory);
|
24
52
|
memory->ops = &rbffi_AbstractMemoryOps;
|
53
|
+
memory->access = MEM_RD | MEM_WR;
|
25
54
|
|
26
55
|
return obj;
|
27
56
|
}
|
@@ -32,6 +61,7 @@ static void \
|
|
32
61
|
memory_op_put_##name(AbstractMemory* memory, long off, VALUE value) \
|
33
62
|
{ \
|
34
63
|
type tmp = (type) toNative(value); \
|
64
|
+
checkWrite(memory); \
|
35
65
|
checkBounds(memory, off, sizeof(type)); \
|
36
66
|
memcpy(memory->address + off, &tmp, sizeof(tmp)); \
|
37
67
|
} \
|
@@ -49,6 +79,7 @@ static VALUE \
|
|
49
79
|
memory_op_get_##name(AbstractMemory* memory, long off) \
|
50
80
|
{ \
|
51
81
|
type tmp; \
|
82
|
+
checkRead(memory); \
|
52
83
|
checkBounds(memory, off, sizeof(type)); \
|
53
84
|
memcpy(&tmp, memory->address + off, sizeof(tmp)); \
|
54
85
|
return fromNative(tmp); \
|
@@ -71,6 +102,7 @@ memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary) \
|
|
71
102
|
long off = NUM2LONG(offset); \
|
72
103
|
AbstractMemory* memory = MEMORY(self); \
|
73
104
|
long i; \
|
105
|
+
checkWrite(memory); \
|
74
106
|
checkBounds(memory, off, count * sizeof(type)); \
|
75
107
|
for (i = 0; i < count; i++) { \
|
76
108
|
type tmp = (type) toNative(RARRAY_PTR(ary)[i]); \
|
@@ -86,6 +118,7 @@ memory_get_array_of_##name(VALUE self, VALUE offset, VALUE length) \
|
|
86
118
|
long off = NUM2LONG(offset); \
|
87
119
|
AbstractMemory* memory = MEMORY(self); \
|
88
120
|
long i; \
|
121
|
+
checkRead(memory); \
|
89
122
|
checkBounds(memory, off, count * sizeof(type)); \
|
90
123
|
VALUE retVal = rb_ary_new2(count); \
|
91
124
|
for (i = 0; i < count; ++i) { \
|
@@ -128,24 +161,6 @@ get_pointer_value(VALUE value)
|
|
128
161
|
|
129
162
|
NUM_OP(pointer, void *, get_pointer_value, rbffi_Pointer_NewInstance);
|
130
163
|
|
131
|
-
static VALUE
|
132
|
-
memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
|
133
|
-
{
|
134
|
-
AbstractMemory* memory = MEMORY(self);
|
135
|
-
long off = NUM2LONG(offset);
|
136
|
-
checkBounds(memory, off, sizeof(void *));
|
137
|
-
|
138
|
-
if (rb_obj_is_kind_of(proc, rb_cProc) || rb_respond_to(proc, id_call)) {
|
139
|
-
VALUE callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
|
140
|
-
void* code = ((NativeCallback *) DATA_PTR(callback))->code;
|
141
|
-
memcpy(memory->address + off, &code, sizeof(code));
|
142
|
-
} else {
|
143
|
-
rb_raise(rb_eArgError, "parameter is not a proc");
|
144
|
-
}
|
145
|
-
|
146
|
-
return self;
|
147
|
-
}
|
148
|
-
|
149
164
|
static VALUE
|
150
165
|
memory_clear(VALUE self)
|
151
166
|
{
|
@@ -157,7 +172,11 @@ memory_clear(VALUE self)
|
|
157
172
|
static VALUE
|
158
173
|
memory_size(VALUE self)
|
159
174
|
{
|
160
|
-
|
175
|
+
AbstractMemory* ptr;
|
176
|
+
|
177
|
+
Data_Get_Struct(self, AbstractMemory, ptr);
|
178
|
+
|
179
|
+
return LONG2NUM(ptr->size);
|
161
180
|
}
|
162
181
|
|
163
182
|
static VALUE
|
@@ -171,7 +190,9 @@ memory_get_string(int argc, VALUE* argv, VALUE self)
|
|
171
190
|
|
172
191
|
off = NUM2LONG(offset);
|
173
192
|
len = nargs > 1 && length != Qnil ? NUM2LONG(length) : (ptr->size - off);
|
193
|
+
checkRead(ptr);
|
174
194
|
checkBounds(ptr, off, len);
|
195
|
+
|
175
196
|
end = memchr(ptr->address + off, 0, len);
|
176
197
|
return rb_tainted_str_new((char *) ptr->address + off,
|
177
198
|
(end != NULL ? end - ptr->address - off : len));
|
@@ -191,6 +212,7 @@ memory_get_array_of_string(int argc, VALUE* argv, VALUE self)
|
|
191
212
|
retVal = rb_ary_new2(count);
|
192
213
|
|
193
214
|
Data_Get_Struct(self, AbstractMemory, ptr);
|
215
|
+
checkRead(ptr);
|
194
216
|
|
195
217
|
if (countnum != Qnil) {
|
196
218
|
int i;
|
@@ -226,12 +248,16 @@ memory_put_string(VALUE self, VALUE offset, VALUE str)
|
|
226
248
|
off = NUM2LONG(offset);
|
227
249
|
len = RSTRING_LEN(str);
|
228
250
|
|
251
|
+
checkWrite(ptr);
|
229
252
|
checkBounds(ptr, off, len + 1);
|
253
|
+
|
230
254
|
if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
|
231
255
|
rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
|
232
256
|
}
|
257
|
+
|
233
258
|
memcpy(ptr->address + off, RSTRING_PTR(str), len);
|
234
259
|
*((char *) ptr->address + off + len) = '\0';
|
260
|
+
|
235
261
|
return self;
|
236
262
|
}
|
237
263
|
|
@@ -243,7 +269,10 @@ memory_get_bytes(VALUE self, VALUE offset, VALUE length)
|
|
243
269
|
|
244
270
|
off = NUM2LONG(offset);
|
245
271
|
len = NUM2LONG(length);
|
272
|
+
|
273
|
+
checkRead(ptr);
|
246
274
|
checkBounds(ptr, off, len);
|
275
|
+
|
247
276
|
return rb_tainted_str_new((char *) ptr->address + off, len);
|
248
277
|
}
|
249
278
|
|
@@ -266,14 +295,41 @@ memory_put_bytes(int argc, VALUE* argv, VALUE self)
|
|
266
295
|
if ((idx + len) > RSTRING_LEN(str)) {
|
267
296
|
rb_raise(rb_eRangeError, "index+length is greater than size of string");
|
268
297
|
}
|
298
|
+
|
299
|
+
checkWrite(ptr);
|
269
300
|
checkBounds(ptr, off, len);
|
301
|
+
|
270
302
|
if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
|
271
303
|
rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
|
272
304
|
}
|
273
305
|
memcpy(ptr->address + off, RSTRING_PTR(str) + idx, len);
|
306
|
+
|
274
307
|
return self;
|
275
308
|
}
|
276
309
|
|
310
|
+
static VALUE
|
311
|
+
memory_type_size(VALUE self)
|
312
|
+
{
|
313
|
+
AbstractMemory* ptr;
|
314
|
+
|
315
|
+
Data_Get_Struct(self, AbstractMemory, ptr);
|
316
|
+
|
317
|
+
return INT2NUM(ptr->typeSize);
|
318
|
+
}
|
319
|
+
|
320
|
+
static VALUE
|
321
|
+
memory_aref(VALUE self, VALUE idx)
|
322
|
+
{
|
323
|
+
AbstractMemory* ptr;
|
324
|
+
VALUE rbOffset = Qnil;
|
325
|
+
|
326
|
+
Data_Get_Struct(self, AbstractMemory, ptr);
|
327
|
+
|
328
|
+
rbOffset = ULONG2NUM(NUM2ULONG(idx) * ptr->typeSize);
|
329
|
+
|
330
|
+
return rb_funcall2(self, id_plus, 1, &rbOffset);
|
331
|
+
}
|
332
|
+
|
277
333
|
static inline char*
|
278
334
|
memory_address(VALUE obj)
|
279
335
|
{
|
@@ -293,12 +349,26 @@ rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass)
|
|
293
349
|
return NULL;
|
294
350
|
}
|
295
351
|
|
352
|
+
void
|
353
|
+
rbffi_AbstractMemory_Error(AbstractMemory *mem, int op)
|
354
|
+
{
|
355
|
+
VALUE rbErrorClass = mem->address == NULL ? NullPointerErrorClass : rb_eRuntimeError;
|
356
|
+
if (op == MEM_RD) {
|
357
|
+
rb_raise(rbErrorClass, "invalid memory read at address=%p", mem->address);
|
358
|
+
} else if (op == MEM_WR) {
|
359
|
+
rb_raise(rbErrorClass, "invalid memory write at address=%p", mem->address);
|
360
|
+
} else {
|
361
|
+
rb_raise(rbErrorClass, "invalid memory access at address=%p", mem->address);
|
362
|
+
}
|
363
|
+
}
|
364
|
+
|
296
365
|
static VALUE
|
297
366
|
memory_op_get_strptr(AbstractMemory* ptr, long offset)
|
298
367
|
{
|
299
368
|
void* tmp = NULL;
|
300
369
|
|
301
370
|
if (ptr != NULL && ptr->address != NULL) {
|
371
|
+
checkRead(ptr);
|
302
372
|
checkBounds(ptr, offset, sizeof(tmp));
|
303
373
|
memcpy(&tmp, ptr->address + offset, sizeof(tmp));
|
304
374
|
}
|
@@ -337,8 +407,12 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
|
|
337
407
|
VALUE classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
|
338
408
|
rbffi_AbstractMemoryClass = classMemory;
|
339
409
|
rb_global_variable(&rbffi_AbstractMemoryClass);
|
340
|
-
|
341
410
|
rb_define_alloc_func(classMemory, memory_allocate);
|
411
|
+
|
412
|
+
NullPointerErrorClass = rb_define_class_under(moduleFFI, "NullPointerError", rb_eRuntimeError);
|
413
|
+
rb_global_variable(&NullPointerErrorClass);
|
414
|
+
|
415
|
+
|
342
416
|
#undef INT
|
343
417
|
#define INT(type) \
|
344
418
|
rb_define_method(classMemory, "put_" #type, memory_put_##type, 2); \
|
@@ -396,7 +470,6 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
|
|
396
470
|
rb_define_method(classMemory, "get_pointer", memory_get_pointer, 1);
|
397
471
|
rb_define_method(classMemory, "put_array_of_pointer", memory_put_array_of_pointer, 2);
|
398
472
|
rb_define_method(classMemory, "get_array_of_pointer", memory_get_array_of_pointer, 2);
|
399
|
-
rb_define_method(classMemory, "put_callback", memory_put_callback, 3);
|
400
473
|
rb_define_method(classMemory, "get_string", memory_get_string, -1);
|
401
474
|
rb_define_method(classMemory, "put_string", memory_put_string, 2);
|
402
475
|
rb_define_method(classMemory, "get_bytes", memory_get_bytes, 2);
|
@@ -405,8 +478,12 @@ rbffi_AbstractMemory_Init(VALUE moduleFFI)
|
|
405
478
|
|
406
479
|
rb_define_method(classMemory, "clear", memory_clear, 0);
|
407
480
|
rb_define_method(classMemory, "total", memory_size, 0);
|
481
|
+
rb_define_alias(classMemory, "size", "total");
|
482
|
+
rb_define_method(classMemory, "type_size", memory_type_size, 0);
|
483
|
+
rb_define_method(classMemory, "[]", memory_aref, 1);
|
408
484
|
|
409
485
|
id_to_ptr = rb_intern("to_ptr");
|
410
486
|
id_call = rb_intern("call");
|
487
|
+
id_plus = rb_intern("+");
|
411
488
|
}
|
412
489
|
|
data/ext/ffi_c/AbstractMemory.h
CHANGED
@@ -1,16 +1,50 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2008, 2009, Wayne Meissner
|
3
|
+
*
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* Redistribution and use in source and binary forms, with or without
|
7
|
+
* modification, are permitted provided that the following conditions are met:
|
8
|
+
*
|
9
|
+
* * Redistributions of source code must retain the above copyright notice, this
|
10
|
+
* list of conditions and the following disclaimer.
|
11
|
+
* * Redistributions in binary form must reproduce the above copyright notice
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
* * The name of the author or authors may not be used to endorse or promote
|
15
|
+
* products derived from this software without specific prior written permission.
|
16
|
+
*
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
*/
|
28
|
+
|
29
|
+
#ifndef RBFFI_ABSTRACTMEMORY_H
|
30
|
+
#define RBFFI_ABSTRACTMEMORY_H
|
3
31
|
|
4
32
|
#include <sys/param.h>
|
5
33
|
#include <sys/types.h>
|
6
34
|
#include <stdint.h>
|
7
35
|
|
8
36
|
#include "compat.h"
|
37
|
+
#include "Types.h"
|
9
38
|
|
10
39
|
#ifdef __cplusplus
|
11
40
|
extern "C" {
|
12
41
|
#endif
|
13
42
|
|
43
|
+
|
44
|
+
#define MEM_RD 0x01
|
45
|
+
#define MEM_WR 0x02
|
46
|
+
#define MEM_CODE 0x04
|
47
|
+
|
14
48
|
typedef struct AbstractMemory_ AbstractMemory;
|
15
49
|
|
16
50
|
typedef struct {
|
@@ -36,33 +70,91 @@ typedef struct {
|
|
36
70
|
struct AbstractMemory_ {
|
37
71
|
char* address; // Use char* instead of void* to ensure adding to it works correctly
|
38
72
|
long size;
|
73
|
+
int access;
|
74
|
+
int typeSize;
|
39
75
|
MemoryOps* ops;
|
40
76
|
};
|
41
77
|
|
78
|
+
extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
|
79
|
+
|
80
|
+
extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
|
81
|
+
|
82
|
+
extern void rbffi_AbstractMemory_Error(AbstractMemory *, int op);
|
42
83
|
|
43
84
|
static inline void
|
44
85
|
checkBounds(AbstractMemory* mem, long off, long len)
|
45
86
|
{
|
46
|
-
if ((off | len | (off + len) | (mem->size - (off + len))) < 0) {
|
87
|
+
if (unlikely((off | len | (off + len) | (mem->size - (off + len))) < 0)) {
|
47
88
|
rb_raise(rb_eIndexError, "Memory access offset=%ld size=%ld is out of bounds",
|
48
89
|
off, len);
|
49
90
|
}
|
50
91
|
}
|
51
92
|
|
93
|
+
static inline void
|
94
|
+
checkRead(AbstractMemory* mem)
|
95
|
+
{
|
96
|
+
if (unlikely((mem->access & MEM_RD) == 0)) {
|
97
|
+
rbffi_AbstractMemory_Error(mem, MEM_RD);
|
98
|
+
}
|
99
|
+
}
|
100
|
+
|
101
|
+
static inline void
|
102
|
+
checkWrite(AbstractMemory* mem)
|
103
|
+
{
|
104
|
+
if (unlikely((mem->access & MEM_WR) == 0)) {
|
105
|
+
rbffi_AbstractMemory_Error(mem, MEM_WR);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
static inline MemoryOp*
|
110
|
+
memory_get_op(AbstractMemory* ptr, Type* type)
|
111
|
+
{
|
112
|
+
if (ptr == NULL || ptr->ops == NULL || type == NULL) {
|
113
|
+
return NULL;
|
114
|
+
}
|
115
|
+
switch (type->nativeType) {
|
116
|
+
case NATIVE_INT8:
|
117
|
+
return ptr->ops->int8;
|
118
|
+
case NATIVE_UINT8:
|
119
|
+
return ptr->ops->uint8;
|
120
|
+
case NATIVE_INT16:
|
121
|
+
return ptr->ops->int16;
|
122
|
+
case NATIVE_UINT16:
|
123
|
+
return ptr->ops->uint16;
|
124
|
+
case NATIVE_INT32:
|
125
|
+
return ptr->ops->int32;
|
126
|
+
case NATIVE_UINT32:
|
127
|
+
return ptr->ops->uint32;
|
128
|
+
case NATIVE_INT64:
|
129
|
+
return ptr->ops->int64;
|
130
|
+
case NATIVE_UINT64:
|
131
|
+
return ptr->ops->uint64;
|
132
|
+
case NATIVE_FLOAT32:
|
133
|
+
return ptr->ops->float32;
|
134
|
+
case NATIVE_FLOAT64:
|
135
|
+
return ptr->ops->float64;
|
136
|
+
case NATIVE_POINTER:
|
137
|
+
return ptr->ops->pointer;
|
138
|
+
case NATIVE_STRING:
|
139
|
+
return ptr->ops->strptr;
|
140
|
+
default:
|
141
|
+
return NULL;
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
52
145
|
#define MEMORY(obj) rbffi_AbstractMemory_Cast((obj), rbffi_AbstractMemoryClass)
|
53
146
|
#define MEMORY_PTR(obj) MEMORY((obj))->address
|
54
147
|
#define MEMORY_LEN(obj) MEMORY((obj))->size
|
55
148
|
|
56
|
-
extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
|
57
149
|
|
58
|
-
extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
|
59
150
|
|
60
151
|
extern VALUE rbffi_AbstractMemoryClass;
|
61
152
|
extern MemoryOps rbffi_AbstractMemoryOps;
|
62
153
|
|
154
|
+
|
63
155
|
#ifdef __cplusplus
|
64
156
|
}
|
65
157
|
#endif
|
66
158
|
|
67
|
-
#endif /*
|
159
|
+
#endif /* RBFFI_ABSTRACTMEMORY_H */
|
68
160
|
|