Skip to content

Commit 67aa2e6

Browse files
committed
refactor(go): avoid using unsafe.Pointer for passing handles (#195)
Functions that receive a `void*` in the C world must be called with an `unsafe.Pointer` from the Go world. However, we are not really passing a pointer, but a "handle", and coercing a handle into an `unsafe.Pointer` is problematic (`go vet` complains with "possible misuse of unsafe.Pointer", and it could cause a panic as described in https://i.hsfzxjy.site/invalid-pointer-will-bite-you/). The solution is introducing small C stub functions that receive an `uintptr_t` instead of a `void*`, and the call the original function, casting the `uintptr_t` into `void*`.
1 parent e8bf6ed commit 67aa2e6

File tree

3 files changed

+45
-24
lines changed

3 files changed

+45
-24
lines changed

go/example_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,4 @@ func Example_compilerAndScanner() {
7272
// Output:
7373
// rule foo matched
7474
// rule bar matched
75-
}
75+
}

go/main.go

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,42 @@ package yara_x
55
// #cgo static_link pkg-config: --static yara_x_capi
66
// #include <yara_x.h>
77
//
8-
// static uint64_t meta_i64(void* value) {
8+
// static inline uint64_t meta_i64(void* value) {
99
// return ((YRX_METADATA_VALUE*) value)->i64;
1010
// }
1111
//
12-
// static double meta_f64(void* value) {
12+
// static inline double meta_f64(void* value) {
1313
// return ((YRX_METADATA_VALUE*) value)->f64;
1414
// }
1515
//
16-
// static bool meta_bool(void* value) {
16+
// static inline bool meta_bool(void* value) {
1717
// return ((YRX_METADATA_VALUE*) value)->boolean;
1818
// }
1919
//
20-
// static char* meta_str(void* value) {
20+
// static inline char* meta_str(void* value) {
2121
// return ((YRX_METADATA_VALUE*) value)->string;
2222
// }
2323
//
24-
// static YRX_METADATA_BYTES* meta_bytes(void* value) {
24+
// static inline YRX_METADATA_BYTES* meta_bytes(void* value) {
2525
// return &(((YRX_METADATA_VALUE*) value)->bytes);
2626
// }
2727
//
28-
// void onRule(YRX_RULE*, void*);
28+
// enum YRX_RESULT static inline _yrx_rules_iterate(
29+
// struct YRX_RULES *rules,
30+
// YRX_RULE_CALLBACK callback,
31+
// uintptr_t user_data) {
32+
// return yrx_rules_iterate(rules, callback, (void*) user_data);
33+
// }
34+
//
35+
// enum YRX_RESULT static inline _yrx_rules_iterate_imports(
36+
// struct YRX_RULES *rules,
37+
// YRX_IMPORT_CALLBACK callback,
38+
// uintptr_t user_data) {
39+
// return yrx_rules_iterate_imports(rules, callback, (void*) user_data);
40+
// }
41+
//
42+
//
43+
// void onRule(YRX_RULE*, uintptr_t);
2944
// void onImport(char*, void*);
3045
import "C"
3146

@@ -157,8 +172,8 @@ func (r *Rules) Destroy() {
157172
// This is the callback called by yrx_rules_iterate, when Rules.GetRules is
158173
// called.
159174
//export onRule
160-
func onRule(rule *C.YRX_RULE, handle unsafe.Pointer) {
161-
h := (cgo.Handle)(handle)
175+
func onRule(rule *C.YRX_RULE, handle C.uintptr_t) {
176+
h := cgo.Handle(handle)
162177
rules, ok := h.Value().(*[]*Rule)
163178
if !ok {
164179
panic("onRule didn't receive a *[]Rule")
@@ -173,10 +188,10 @@ func (r *Rules) Slice() []*Rule {
173188
handle := cgo.NewHandle(&rules)
174189
defer handle.Delete()
175190

176-
C.yrx_rules_iterate(
191+
C._yrx_rules_iterate(
177192
r.cRules,
178193
C.YRX_RULE_CALLBACK(C.onRule),
179-
unsafe.Pointer(handle))
194+
C.uintptr_t(handle))
180195

181196
runtime.KeepAlive(r)
182197
return rules
@@ -195,7 +210,7 @@ func (r *Rules) Count() int {
195210
// is called.
196211
//export onImport
197212
func onImport(module_name *C.char, handle unsafe.Pointer) {
198-
h := (cgo.Handle)(handle)
213+
h := cgo.Handle(handle)
199214
imports, ok := h.Value().(*[]string)
200215
if !ok {
201216
panic("onImport didn't receive a *[]string")
@@ -206,13 +221,13 @@ func onImport(module_name *C.char, handle unsafe.Pointer) {
206221
// Count returns the total number of rules.
207222
func (r *Rules) Imports() []string {
208223
imports := make([]string, 0)
209-
handle := cgo.NewHandle(&imports)
210-
defer handle.Delete()
224+
handle := cgo.NewHandle(&imports)
225+
defer handle.Delete()
211226

212-
C.yrx_rules_iterate_imports(
227+
C._yrx_rules_iterate_imports(
213228
r.cRules,
214229
C.YRX_RULE_CALLBACK(C.onImport),
215-
unsafe.Pointer(handle))
230+
C.uintptr_t(handle))
216231

217232
runtime.KeepAlive(r)
218233
return imports

go/scanner.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ package yara_x
22

33
// #include <yara_x.h>
44
//
5-
// void onMatchingRule(YRX_RULE*, void*);
5+
// enum YRX_RESULT static inline _yrx_scanner_on_matching_rule(
6+
// struct YRX_SCANNER *scanner,
7+
// YRX_RULE_CALLBACK callback,
8+
// uintptr_t user_data) {
9+
// return yrx_scanner_on_matching_rule(scanner, callback, (void*) user_data);
10+
// }
11+
//
12+
// void onMatchingRule(YRX_RULE*, uintptr_t);
613
import "C"
714

815
import (
@@ -19,8 +26,6 @@ import (
1926
"google.golang.org/protobuf/proto"
2027
)
2128

22-
23-
2429
// Scanner scans data with a set of compiled YARA rules.
2530
type Scanner struct {
2631
// Pointer to C-side scanner.
@@ -55,9 +60,10 @@ func (s ScanResults) MatchingRules() []*Rule {
5560
}
5661

5762
// This is the callback function called every time a YARA rule matches.
63+
//
5864
//export onMatchingRule
59-
func onMatchingRule(rule *C.YRX_RULE, handle unsafe.Pointer) {
60-
h := (cgo.Handle)(handle)
65+
func onMatchingRule(rule *C.YRX_RULE, handle C.uintptr_t) {
66+
h := cgo.Handle(handle)
6167
scanner, ok := h.Value().(*Scanner)
6268
if !ok {
6369
panic("onMatchingRule didn't receive a Scanner")
@@ -76,13 +82,12 @@ func NewScanner(r *Rules) *Scanner {
7682
panic("yrx_scanner_create failed")
7783
}
7884

79-
// Create a new handle that points to the scanner.
8085
s.handle = cgo.NewHandle(s)
8186

82-
C.yrx_scanner_on_matching_rule(
87+
C._yrx_scanner_on_matching_rule(
8388
s.cScanner,
8489
C.YRX_RULE_CALLBACK(C.onMatchingRule),
85-
unsafe.Pointer(s.handle))
90+
C.uintptr_t(s.handle))
8691

8792
runtime.SetFinalizer(s, (*Scanner).Destroy)
8893
return s
@@ -242,5 +247,6 @@ func (s *Scanner) Destroy() {
242247
s.handle.Delete()
243248
s.cScanner = nil
244249
}
250+
s.rules = nil
245251
runtime.SetFinalizer(s, nil)
246252
}

0 commit comments

Comments
 (0)