Skip to content

Commit

Permalink
Merge pull request #5 from furunkel/managed_struct
Browse files Browse the repository at this point in the history
Get rid of finalizer hack
  • Loading branch information
bnagy committed Sep 13, 2015
2 parents 059e652 + 29baaeb commit 5ef6f24
Showing 1 changed file with 31 additions and 47 deletions.
78 changes: 31 additions & 47 deletions lib/crabstone.rb
Expand Up @@ -158,7 +158,7 @@ def self.raise_errno errno
module Binding

extend FFI::Library
ffi_lib 'capstone'
ffi_lib ['capstone', 'libcapstone.so.3']

# This is because JRuby FFI on x64 Windows thinks size_t is 32 bit
case FFI::Platform::ADDRESS_SIZE
Expand Down Expand Up @@ -202,16 +202,22 @@ class Detail < FFI::Struct
)
end

class Instruction < FFI::Struct
class Instruction < FFI::ManagedStruct
layout(
:id, :uint,
:address, :ulong_long,
:size, :uint16,
:bytes, [:uchar, 16],
:mnemonic, [:char, 32],
:op_str, [:char, 160],
:detail, Detail.ptr
:detail, Detail.by_ref
)

def self.release(ptr)
detail_ptr = ptr.+(Instruction.offset_of(:detail)).read_ptr
Binding.free(detail_ptr)
Binding.free(ptr)
end
end

callback :skipdata_cb, [:pointer, :size_t, :size_t, :pointer], :size_t
Expand All @@ -231,7 +237,6 @@ class SkipdataConfig < FFI::Struct
)
attach_function :cs_close, [:pointer], :cs_err
attach_function :cs_errno, [:csh], :cs_err
attach_function :cs_free, [:pointer, :size_t], :void
attach_function :cs_group_name, [:csh, :uint], :string
attach_function :cs_insn_group, [:csh, Instruction, :uint], :bool
attach_function :cs_insn_name, [:csh, :uint], :string
Expand All @@ -244,6 +249,9 @@ class SkipdataConfig < FFI::Struct
attach_function :cs_strerror, [:cs_err], :string
attach_function :cs_support, [:cs_arch], :bool
attach_function :cs_version, [:pointer, :pointer], :uint
attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
attach_function :malloc, [:size_t], :pointer
attach_function :free, [:pointer], :void

end # Binding

Expand Down Expand Up @@ -422,69 +430,45 @@ class Disassembly
include Enumerable

attr_reader :engine
attr_reader :insns

def initialize engine, code, offset, count=0
def initialize(engine, code, offset, count = 0)
@engine = engine
@code = code
@offset = offset
@count = count

disasm!
end

def each &blk
def each(&block)
insns.each(&block)
end

insn = Binding::Instruction.new
insn_ptr = FFI::MemoryPointer.new insn
private
def disasm!
insn_ptr = FFI::MemoryPointer.new :pointer
insn_count = Binding.cs_disasm(
engine.csh,
@engine.csh,
@code,
@code.bytesize,
@offset,
@count,
insn_ptr
)
Crabstone.raise_errno(@engine.errno) if insn_count.zero?
cs_resources = [insn_ptr.read_pointer, insn_count]
Crabstone.raise_errno(errno) if insn_count.zero?

begin
(0...insn_count * insn.size).step(insn.size).each {|insn_offset|
cs_insn = Binding::Instruction.new( (insn_ptr.read_pointer)+insn_offset )
yield Instruction.new engine.csh, cs_insn, engine.arch
}
ensure
Binding.cs_free( *cs_resources )
@insns = (0...insn_count * Binding::Instruction.size).step(Binding::Instruction.size).map do |off|
cs_insn_ptr = Binding.malloc Binding::Instruction.size
cs_insn = Binding::Instruction.new cs_insn_ptr
Binding.memcpy(cs_insn_ptr, insn_ptr.read_pointer + off, Binding::Instruction.size)
Instruction.new engine.csh, cs_insn, engine.arch
end

end

# Use of this method CAN BE LEAKY, please take care.
def insns
insn = Binding::Instruction.new
insn_ptr = FFI::MemoryPointer.new insn
insns = []
insn_count = Binding.cs_disasm(
engine.csh,
@code,
@code.bytesize,
@offset,
@count,
insn_ptr
)
Crabstone.raise_errno(errno) if insn_count.zero?
cs_resources = [insn_ptr.read_pointer, insn_count]
@insns.freeze

(0...insn_count * insn.size).step(insn.size).each {|insn_offset|
cs_insn = Binding::Instruction.new( (insn_ptr.read_pointer)+insn_offset )
insns << Instruction.new( engine.csh, cs_insn, engine.arch )
}
# Once insns goes out of scope the underlying C memory will be freed.
# HOWEVER, if you're still keeping a ref to any of the Instructions that
# were inside that Array, they will still be valid, and will now behave
# in an undefined manner, which might include segfaults, missing data,
# or all kinds of other troubles.
ObjectSpace.define_finalizer(insns) {Binding.cs_free(*cs_resources)}
insns
Binding.free(insn_ptr.read_pointer)
end

end

class Disassembler
Expand Down

0 comments on commit 5ef6f24

Please sign in to comment.