From a6ffb71e4cc4a319656d1fff4f61f8522a54b837 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 30 Oct 2015 21:18:33 -0700 Subject: [PATCH] Go bindings: add Close() and set as GC finalizer --- bindings/go/unicorn/unicorn.go | 19 +++++++++++++++++-- bindings/go/unicorn/unicorn_test.go | 13 +++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index fc52284e..2cabac74 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -1,6 +1,8 @@ package unicorn import ( + "runtime" + "sync" "unsafe" ) @@ -37,10 +39,12 @@ type Unicorn interface { Stop() error HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) HookDel(hook Hook) error + Close() error } type uc struct { handle *C.uc_engine + final sync.Once } type UcOptions struct { @@ -57,8 +61,19 @@ func NewUnicorn(arch, mode int) (Unicorn, error) { if ucerr := C.uc_open(C.uc_arch(arch), C.uc_mode(mode), &handle); ucerr != ERR_OK { return nil, UcError(ucerr) } - uc := &uc{handle} - return uc, nil + u := &uc{handle: handle} + runtime.SetFinalizer(u, func(u *uc) { u.Close() }) + return u, nil +} + +func (u *uc) Close() (err error) { + u.final.Do(func() { + if u.handle != nil { + err = errReturn(C.uc_close(u.handle)) + u.handle = nil + } + }) + return err } func (u *uc) StartWithOptions(begin, until uint64, options *UcOptions) error { diff --git a/bindings/go/unicorn/unicorn_test.go b/bindings/go/unicorn/unicorn_test.go index 72c43c77..caf13126 100644 --- a/bindings/go/unicorn/unicorn_test.go +++ b/bindings/go/unicorn/unicorn_test.go @@ -24,3 +24,16 @@ func TestMemUnmap(t *testing.T) { t.Fatal(fmt.Errorf("Expected ERR_WRITE_UNMAPPED, got: %v", err)) } } + +func TestDoubleClose(t *testing.T) { + mu, err := NewUnicorn(ARCH_X86, MODE_32) + if err != nil { + t.Fatal(err) + } + if err := mu.Close(); err != nil { + t.Fatal(err) + } + if err := mu.Close(); err != nil { + t.Fatal(err) + } +}