Skip to content

Commit 687f214

Browse files
tenderlovekou
andcommitted
Add a helper methods for reading and writing memory
This commit adds two new methods, `Fiddle::Pointer.read` and `Fiddle::Pointer.write`. Both methods take an address, and will read or write bytes at that address respectively. For example we can read from an address without making a Pointer object: ```ruby Fiddle::Pointer.read(address, 5) # read 5 bytes ``` We can also write to an address without allocating a Pointer object: ```ruby Fiddle::Pointer.write(address, "bytes") # write 5 bytes ``` This allows us to read / write memory at arbitrary addresses without instantiating a new `Fiddle::Pointer` object. Co-Authored-By: Sutou Kouhei <[email protected]>
1 parent 36b2432 commit 687f214

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

ext/fiddle/pointer.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,33 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
799799
return ptr;
800800
}
801801

802+
/*
803+
* call-seq:
804+
* Fiddle::Pointer.read(address, len) => string
805+
*
806+
* Or read the memory at address +address+ with length +len+ and return a
807+
* string with that memory
808+
*/
809+
810+
static VALUE
811+
rb_fiddle_ptr_read_mem(VALUE klass, VALUE address, VALUE len)
812+
{
813+
return rb_str_new((char *)NUM2ULONG(address), NUM2ULONG(len));
814+
}
815+
816+
/*
817+
* call-seq:
818+
* Fiddle::Pointer.write(address, str)
819+
*
820+
* Write bytes in +str+ to the location pointed to by +address+.
821+
*/
822+
static VALUE
823+
rb_fiddle_ptr_write_mem(VALUE klass, VALUE addr, VALUE str)
824+
{
825+
memcpy(NUM2PTR(addr), StringValuePtr(str), RSTRING_LEN(str));
826+
return str;
827+
}
828+
802829
void
803830
Init_fiddle_pointer(void)
804831
{
@@ -815,6 +842,8 @@ Init_fiddle_pointer(void)
815842
rb_define_singleton_method(rb_cPointer, "malloc", rb_fiddle_ptr_s_malloc, -1);
816843
rb_define_singleton_method(rb_cPointer, "to_ptr", rb_fiddle_ptr_s_to_ptr, 1);
817844
rb_define_singleton_method(rb_cPointer, "[]", rb_fiddle_ptr_s_to_ptr, 1);
845+
rb_define_singleton_method(rb_cPointer, "read", rb_fiddle_ptr_read_mem, 2);
846+
rb_define_singleton_method(rb_cPointer, "write", rb_fiddle_ptr_write_mem, 2);
818847
rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
819848
rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
820849
rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);

test/fiddle/test_pointer.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,38 @@ def dlwrap arg
1010
Fiddle.dlwrap arg
1111
end
1212

13+
def test_can_write_memory
14+
# Allocate some memory
15+
address = Fiddle.malloc(Fiddle::SIZEOF_VOIDP)
16+
17+
bytes_to_write = Fiddle::SIZEOF_VOIDP.times.to_a.pack("C*")
18+
19+
# Write to the memory
20+
Fiddle::Pointer.write(address, bytes_to_write)
21+
22+
# Read the bytes out again
23+
bytes = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP)
24+
assert_equal bytes_to_write, bytes
25+
ensure
26+
Fiddle.free address
27+
end
28+
29+
def test_can_read_memory
30+
# Allocate some memory
31+
address = Fiddle.malloc(Fiddle::SIZEOF_VOIDP)
32+
33+
# Write some bytes in to the memory
34+
ptr = Fiddle::Pointer.new(address)
35+
bytes_to_write = Fiddle::SIZEOF_VOIDP.times.to_a
36+
bytes_to_write.each { |i| ptr[i] = i }
37+
38+
# Read the bytes out again
39+
bytes = Fiddle::Pointer.read(address, Fiddle::SIZEOF_VOIDP).bytes
40+
assert_equal bytes_to_write, bytes
41+
ensure
42+
Fiddle.free address
43+
end
44+
1345
def test_cptr_to_int
1446
null = Fiddle::NULL
1547
assert_equal(null.to_i, null.to_int)

0 commit comments

Comments
 (0)