Giter Site home page Giter Site logo

CGO hyperscan crash about gohs HOT 15 CLOSED

flier avatar flier commented on July 29, 2024 4
CGO hyperscan crash

from gohs.

Comments (15)

ajkeeton avatar ajkeeton commented on July 29, 2024 1

Last week I ran into the exact same issue and went down the same problem solving path :) The KeepAlive changes in the develop branch fix the issue. Any idea when they should be merged into master?

from gohs.

flier avatar flier commented on July 29, 2024

I can't reproduce it on my laptop (macbook pro, OSX 10.13.3) with hyperscan 4.7.0 and go1.9.3, anything I missed?

➜ hyperscan git:(develop) go version
go version go1.9.3 darwin/amd64
➜ hyperscan git:(develop) brew info hyperscan
hyperscan: stable 4.7.0 (bottled)
High-performance regular expression matching library
https://01.org/hyperscan
/usr/local/Cellar/hyperscan/4.7.0 (23 files, 16.9MB) *
Poured from bottle on 2018-01-24 at 21:36:22
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/hyperscan.rb
==> Dependencies
Build: boost ✔, ragel ✔, cmake ✔, pkg-config ✔
==> Options
--with-debug
Build with debug symbols
➜ examples git:(develop) ✗ go run test.go
generating random patterns... done
initializing engines... done (1)
matching... matched 1021000/s
matched 1047000/s
matched 1027000/s
matched 1047000/s
matched 1042000/s
matched 1041000/s
matched 1035000/s
matched 981000/s
matched 1005000/s
matched 1045000/s
matched 1037000/s
matched 1001000/s
matched 865000/s
matched 888000/s
matched 795000/s
matched 840000/s
matched 818000/s
matched 1013000/s
matched 998833/s
matched 979000/s
matched 1017000/s
matched 1036000/s
matched 1052000/s
matched 1051000/s
matched 1049000/s
matched 1042000/s
matched 1024000/s
matched 1047000/s
matched 1050000/s
matched 1043833/s
matched 1040000/s
matched 1038000/s
matched 1044000/s
matched 1046000/s
matched 1048000/s
matched 1043000/s
matched 1045000/s
matched 1045000/s
matched 1041000/s
matched 1036000/s
matched 1048000/s
matched 994000/s
matched 1012000/s
matched 1051833/s
matched 1050000/s
matched 1051000/s
matched 1047000/s
matched 1011000/s
matched 1041000/s
matched 1040000/s
matched 1039000/s
matched 1028000/s
matched 1050000/s
matched 1052000/s
matched 1065000/s
matched 1053000/s
matched 1054000/s
matched 1064000/s
matched 1060000/s
matched 1013000/s
matched 960000/s
matched 1008000/s
matched 890000/s
matched 928000/s
matched 926000/s
matched 732000/s
matched 763000/s
matched 894000/s
matched 832000/s
matched 834000/s
matched 805000/s
matched 961000/s
matched 939000/s
matched 965000/s
matched 977000/s
matched 930000/s
matched 947000/s
matched 934000/s
matched 962000/s
matched 919000/s
matched 940000/s
matched 891000/s
matched 859000/s
matched 684000/s
matched 748000/s
matched 1008000/s
matched 892000/s
matched 757000/s
matched 872000/s
matched 1007000/s
matched 856000/s
matched 941000/s
matched 896000/s
matched 968000/s
matched 884000/s
matched 748000/s
matched 972000/s
matched 791000/s
matched 954000/s
matched 1024000/s
matched 1032000/s
matched 1013000/s
matched 1020000/s
matched 965000/s
matched 965000/s
matched 951000/s
matched 932000/s
matched 946000/s
matched 980000/s
matched 951000/s
matched 898000/s
matched 973000/s
matched 959000/s
matched 1003000/s
matched 937000/s
matched 962000/s
matched 872000/s
matched 813000/s
matched 757000/s
matched 645000/s
matched 974000/s
matched 1000000/s
matched 937000/s
matched 863000/s
matched 952417/s
matched 954000/s
matched 1000000/s
matched 958000/s
matched 893000/s
matched 958000/s
matched 937000/s
matched 948000/s
matched 1017000/s
matched 1016000/s
matched 982000/s
matched 929000/s
matched 958000/s
matched 898000/s
matched 1014000/s
matched 1008000/s
matched 1002000/s
matched 919000/s
matched 904000/s
matched 1002000/s
matched 962000/s
matched 997000/s
matched 973000/s
matched 988000/s
matched 999000/s
matched 730000/s
matched 867000/s
matched 967000/s
matched 752000/s
matched 979000/s
matched 885000/s
matched 905000/s
matched 852833/s
matched 959000/s
matched 831000/s
matched 739000/s
matched 933000/s
matched 836000/s
matched 804000/s
matched 867000/s
matched 926000/s
matched 858000/s
matched 961000/s
matched 951000/s
matched 972000/s
matched 958000/s
matched 977000/s
matched 992000/s
matched 978000/s
matched 980000/s
matched 958000/s
matched 962000/s
matched 980000/s
matched 971000/s
matched 817000/s
matched 950000/s
matched 885000/s
matched 851000/s
matched 987000/s
matched 959000/s
matched 1025000/s
matched 818000/s
matched 801000/s
matched 788000/s
matched 447000/s
matched 690000/s
matched 737000/s
matched 514000/s
matched 597000/s
matched 624000/s
matched 861000/s
matched 821000/s
matched 926000/s
matched 956000/s
matched 950833/s
matched 1000000/s
matched 954000/s
matched 949000/s
matched 926000/s
matched 982000/s
matched 947000/s
matched 953000/s
matched 953000/s
matched 936000/s
matched 980000/s
matched 965000/s
matched 949000/s
matched 957000/s
matched 960000/s
matched 974000/s
matched 950000/s
matched 896000/s
matched 890000/s
matched 884000/s
matched 958000/s
matched 728000/s
matched 916000/s
matched 808000/s
matched 914000/s
matched 958000/s
matched 935000/s
matched 960000/s
matched 967000/s
matched 1005000/s
matched 832000/s
matched 680000/s
matched 930000/s
matched 963000/s
matched 955000/s
matched 981000/s
matched 975000/s
matched 976000/s
matched 982000/s
matched 980000/s
matched 943000/s
matched 898000/s
matched 928000/s
matched 840000/s
matched 949000/s
matched 984000/s
matched 975000/s
matched 972000/s
matched 948000/s
matched 959000/s
matched 926000/s
matched 963000/s
matched 938000/s
matched 969000/s
matched 780000/s
matched 951000/s
matched 980000/s
matched 1035000/s
matched 1029000/s
matched 1026000/s
matched 1024000/s
matched 1034000/s
matched 987000/s
matched 1009000/s
matched 1010000/s
matched 1019000/s
matched 1010000/s
matched 1010000/s
matched 1005000/s
matched 1001000/s
matched 1010000/s
matched 1017000/s
matched 1012000/s
matched 1015000/s
matched 1022000/s
matched 1021000/s
matched 1005000/s
matched 1017000/s
matched 1011000/s
matched 1018000/s
matched 1013000/s
matched 1006000/s
matched 1002000/s
matched 1018000/s
matched 1012000/s
matched 1012000/s
matched 1021000/s
matched 1011000/s
matched 1014000/s
matched 1021000/s
matched 1020000/s
matched 961000/s
matched 977000/s
matched 1008000/s
matched 1016000/s
matched 1032000/s
matched 1022000/s
matched 1013000/s
matched 1028000/s
matched 1023000/s
matched 1021000/s
matched 1027833/s
matched 1005000/s
matched 964000/s
matched 997000/s
matched 1027000/s
matched 1019000/s
matched 1022000/s
matched 1027000/s
matched 1013000/s
matched 1001000/s
matched 1015000/s
matched 1012000/s
matched 1010000/s
matched 1022000/s
matched 1031000/s
matched 1013000/s
matched 1024000/s
matched 1023000/s
matched 1016000/s
matched 1009417/s
matched 1013000/s
matched 1020000/s
matched 976000/s
matched 1000000/s
matched 1023000/s
matched 1015000/s
matched 1010000/s
matched 1017000/s
matched 965000/s
matched 740000/s
matched 974000/s
matched 840000/s
matched 794000/s
matched 963000/s
matched 995000/s
matched 1002000/s
matched 967000/s
matched 925000/s
matched 970000/s
matched 886000/s
matched 1011000/s
matched 800000/s
matched 848000/s
matched 954000/s
matched 1026000/s
matched 1022000/s
matched 1029000/s
matched 987000/s
matched 958000/s
matched 936000/s
matched 904000/s
matched 999000/s
matched 962000/s
matched 952000/s
matched 983000/s
matched 982000/s
matched 1011000/s
matched 988000/s
matched 992000/s
matched 926000/s
matched 978000/s
matched 883000/s
matched 867000/s
matched 907000/s
matched 933000/s
matched 925000/s

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

Thanks for looking into this! Sorry, I should have proofread the source before I sent it over. Could you swap the 1 on line 22 for 8 and retry? That will instantiate the wrapper 8 times instead of 1. I am running the same go/hyperscan combination.

from gohs.

flier avatar flier commented on July 29, 2024

It is very strange, because gohs itself only use a context pointer when scan vector, all the other C pointer should only be used in the call.

I have submitted a issue to upstream, maybe hyperscan engine use a GO pointer out of date.

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

Thanks. One of the first theories I had (and debunked) was that the initial corpus was GCed, but the same happens when each goroutine calling into gohs creates its own corpus on the fly before each call.

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

Just on the off-chance that the GC reaps the input data before the CGO call, I marked it as reachable, but it crashes the same way.

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

I have one last theory - the Go stack changes just before the hyperscan library calls back into Go (the hyperscan match handler) and things go wrong.

from gohs.

flier avatar flier commented on July 29, 2024

Great, we seems found the root cause, please check the commit, I can' reproduce the crash with it.

Your expression may too complicate that cross two or more golang GC cycle that trigger the issue.

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

Excellent, thanks. I can confirm this fixes the problem. I wonder though why Go is so aggressive in marking the CGO pointers as unreachable. I have created an issue on their project page to double check.

from gohs.

flier avatar flier commented on July 29, 2024

So, it seems nothing more can do with the Golang limitation, if you think it ok, I will merge the fixes and close the issue.

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

@flier, for the vectored call I think it's worth running some benchmarks, I would not be surprised if we found the cost of the extra copy to C memory to be somewhat negligible compared to the cost of the CGO calls. In my wrapper around your package I tried both zero and one copy string to []byte conversion, the zero copy was obviously faster but they were both at least an order of magnitude faster than everything else we do with CGO.

from gohs.

flier avatar flier commented on July 29, 2024

Yes, I tried to implement a copy string version, it is a little complicate with a slight performance degradation.

In fact, I doubt whether it is worthy to trade an implicit runtime.KeepAlive

func hsScanVector(db hsDatabase, data [][]byte, flags ScanFlag, scratch hsScratch, onEvent hsMatchEventHandler, context interface{}) error {
	if len(data) == 0 {
		return HsError(C.HS_INVALID)
	}

	cPtrSize := int(unsafe.Sizeof(uintptr(0))) * len(data)
	cLenSize := int(unsafe.Sizeof(C.uint(0))) * len(data)
	cDataSize := 0

	for _, b := range data {
		if len(b) == 0 {
			return HsError(C.HS_INVALID)
		}

		cDataSize += len(b)
	}

	p := C.malloc(C.size_t(cPtrSize + cLenSize + cDataSize))

	cPtr := *(*[]uintptr)(unsafe.Pointer(&reflect.SliceHeader{
		Data: uintptr(p),
		Len:  len(data),
		Cap:  len(data),
	}))
	cLen := *(*[]C.uint)(unsafe.Pointer(&reflect.SliceHeader{
		Data: uintptr(p) + uintptr(cPtrSize),
		Len:  len(data),
		Cap:  len(data),
	}))
	cData := uintptr(p) + uintptr(cPtrSize+cLenSize)

	pData := cData

	for i, b := range data {
		cPtr[i] = pData
		cLen[i] = C.uint(len(b))
		C.memcpy(unsafe.Pointer(pData), unsafe.Pointer(&b[0]), C.size_t(len(b)))
		pData += uintptr(len(b))
	}

	ctxt := &hsMatchEventContext{onEvent, context}

	ret := C.hs_scan_vector_cgo(db, (**C.char)(unsafe.Pointer(uintptr(p))), (*C.uint)(unsafe.Pointer(uintptr(p)+uintptr(cPtrSize))),
		C.uint(len(data)), C.uint(flags), scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))

	C.free(p)

	runtime.KeepAlive(ctxt)

	if ret != C.HS_SUCCESS {
		return HsError(ret)
	}

	return nil
}

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

I had something slightly simpler looking in mind that seems to do the trick:

func hsScanVector(db hsDatabase, data [][]byte, flags ScanFlag, scratch hsScratch, onEvent hsMatchEventHandler, context interface{}) error {
	if len(data) == 0 {
		return HsError(C.HS_INVALID)
	}

	cdata := make([]*C.char, len(data))
	clength := make([]C.uint, len(data))

	for i, d := range data {
		if len(d) == 0 {
			for j := 0; j <= i; j++ {
				if cdata[j] != nil {
					C.free(unsafe.Pointer(cdata[j]))
				}
			}
			return HsError(C.HS_INVALID)
		}

		cdata[i] = C.CString(string(d))
		clength[i] = C.uint(len(d))
	}

	ctxt := &hsMatchEventContext{onEvent, context}

	ret := C.hs_scan_vector_cgo(db, (**C.char)(unsafe.Pointer(&cdata[0])), (*C.uint)(unsafe.Pointer(&clength[0])),
		C.uint(len(data)), C.uint(flags), scratch, unsafe.Pointer(ctxt))

	for i, _ := range cdata {
		C.free(unsafe.Pointer(cdata[i]))
	}

	if ret != C.HS_SUCCESS {
		return HsError(ret)
	}

	return nil
}

However, the last item I couldn't find a workable solution for that doesn't involve a callback dictionary (with locking) is the ctxt := &hsMatchEventContext{onEvent, context} encapsulation. That one would still need to be passed down to C as an uintptr - thus losing pointer semantics and needing the KeepAlive() hack.

from gohs.

brknstrngz avatar brknstrngz commented on July 29, 2024

@flier probably fine to merge the runtime.KeepAlive() workaround for now (either just for the context wrapper or for all pointers), it seems to work fine. Because of the variable Go callback there's no clean and performant way of fixing this completely. Thanks again.

This is what I had so far:

index b488302..a22f10b 100644
--- a/hyperscan/internal.go
+++ b/hyperscan/internal.go
@@ -3,6 +3,7 @@ package hyperscan
 import (
        "errors"
        "fmt"
+       "runtime"
        "sort"
        "strings"
        "unsafe"
@@ -54,45 +55,44 @@ DEFINE_ALLOCTOR(Misc, misc);
 DEFINE_ALLOCTOR(Scratch, scratch);
 DEFINE_ALLOCTOR(Stream, stream);
 
-extern int hsMatchEventCallback(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, uintptr_t context);
+extern int hsMatchEventCallback(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void* context);
 
 static
-int hs_event_callback(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context) {
-       return hsMatchEventCallback(id, from, to, flags, (uintptr_t) context);
+int hs_event_callback(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void* context) {
+       return hsMatchEventCallback(id, from, to, flags, context);
 }
 
 static inline
-hs_error_t hs_scan_cgo(uintptr_t db, uintptr_t data, unsigned int length,
-                                          unsigned int flags, uintptr_t scratch, uintptr_t context) {
-       return hs_scan((const hs_database_t *) db, (const char *) data, length, flags, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
+hs_error_t hs_scan_cgo(const hs_database_t* db, const char* data, unsigned int length,
+                                          unsigned int flags, hs_scratch_t* scratch, uintptr_t context) {
+       return hs_scan(db, data, length, flags, scratch, hs_event_callback, (void*) context);
 }
 
 static inline
-hs_error_t hs_scan_vector_cgo(uintptr_t db, uintptr_t data, uintptr_t length, unsigned int count,
-                                                         unsigned int flags, uintptr_t scratch, uintptr_t context) {
-       return hs_scan_vector((const hs_database_t *) db, (const char *const *) data, (const unsigned int *) length, count,
-                                                 flags, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
+hs_error_t hs_scan_vector_cgo(const hs_database_t* db, const char* const* data, const unsigned int* length, unsigned int count,
+                                                       unsigned int flags, hs_scratch_t* scratch, uintptr_t context) {
+       return hs_scan_vector(db, data, length, count, flags, scratch, hs_event_callback, (void*) context);
 }
 
 static inline
-hs_error_t hs_scan_stream_cgo(uintptr_t id, uintptr_t data, unsigned int length,
-                                                         unsigned int flags, uintptr_t scratch, uintptr_t context) {
-       return hs_scan_stream((hs_stream_t *) id, (const char *) data, length, flags, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
+hs_error_t hs_scan_stream_cgo(hs_stream_t* id, const char* data, unsigned int length,
+                                                         unsigned int flags, hs_scratch_t* scratch, uintptr_t context) {
+       return hs_scan_stream(id, data, length, flags, scratch, hs_event_callback, (void*) context);
 }

 static inline
-hs_error_t hs_close_stream_cgo(uintptr_t id, uintptr_t scratch, uintptr_t context) {
-       return hs_close_stream((hs_stream_t *) id, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
+hs_error_t hs_close_stream_cgo(hs_stream_t* id, hs_scratch_t* scratch, uintptr_t context) {
+       return hs_close_stream(id, scratch, hs_event_callback, (void*) context);
 }
 
 static inline
-hs_error_t hs_reset_stream_cgo(uintptr_t id, unsigned int flags, uintptr_t scratch, uintptr_t context) {
-       return hs_reset_stream((hs_stream_t *) id, flags, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
+hs_error_t hs_reset_stream_cgo(hs_stream_t* id, unsigned int flags, hs_scratch_t* scratch, uintptr_t context) {
+       return hs_reset_stream(id, flags, scratch, hs_event_callback, (void*) context);
 }
 
 static inline
-hs_error_t hs_reset_and_copy_stream_cgo(uintptr_t to_id, uintptr_t from_id, uintptr_t scratch, uintptr_t context) {
-       return hs_reset_and_copy_stream((hs_stream_t *) to_id, (const hs_stream_t *) from_id, (hs_scratch_t *) scratch, hs_event_callback, (void *) context);
+hs_error_t hs_reset_and_copy_stream_cgo(hs_stream_t* to_id, hs_stream_t* from_id, hs_scratch_t* scratch, uintptr_t context) {
+       return hs_reset_and_copy_stream(to_id, from_id, scratch, hs_event_callback, (void*) context);
 }
 */
 import "C"
@@ -897,8 +897,8 @@ type hsMatchEventContext struct {
 }
 //export hsMatchEventCallback
-func hsMatchEventCallback(id C.uint, from, to C.ulonglong, flags C.uint, data C.uintptr_t) C.int {
-       ctxt := (*hsMatchEventContext)(unsafe.Pointer((uintptr(data))))
+func hsMatchEventCallback(id C.uint, from, to C.ulonglong, flags C.uint, data unsafe.Pointer) C.int {
+       ctxt := (*hsMatchEventContext)(data)
 
        if err := ctxt.handler(uint(id), uint64(from), uint64(to), uint(flags), ctxt.context); err != nil {
                return -1
@@ -914,8 +914,10 @@ func hsScan(db hsDatabase, data []byte, flags ScanFlag, scratch hsScratch, onEve
 
        ctxt := &hsMatchEventContext{onEvent, context}
 
-       ret := C.hs_scan_cgo(C.uintptr_t(uintptr(unsafe.Pointer(db))), C.uintptr_t(uintptr(unsafe.Pointer(&data[0]))), C.uint(len(data)),
-               C.uint(flags), C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       cdata := C.CString(string(data))
+       ret := C.hs_scan_cgo(db, (*C.char)(cdata), C.uint(len(data)), C.uint(flags), scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       C.free(unsafe.Pointer(cdata))
+       runtime.KeepAlive(ctxt)
 
        if ret != C.HS_SUCCESS {
                return HsError(ret)
@@ -929,22 +931,33 @@ func hsScanVector(db hsDatabase, data [][]byte, flags ScanFlag, scratch hsScratc
                return HsError(C.HS_INVALID)
        }
 
-       cdata := make([]uintptr, len(data))
+       cdata := make([]*C.char, len(data))
        clength := make([]C.uint, len(data))
 
        for i, d := range data {
                if len(d) == 0 {
+                       for j := 0; j <= i; j++ {
+                               if cdata[j] != nil {
+                                       C.free(unsafe.Pointer(cdata[j]))
+                               }
+                       }
                        return HsError(C.HS_INVALID)
                }
 
-               cdata[i] = uintptr(unsafe.Pointer(&d[0]))
+               cdata[i] = C.CString(string(d))
                clength[i] = C.uint(len(d))
        }
 
        ctxt := &hsMatchEventContext{onEvent, context}
 
-       ret := C.hs_scan_vector_cgo(C.uintptr_t(uintptr(unsafe.Pointer(db))), C.uintptr_t(uintptr(unsafe.Pointer(&cdata[0]))), C.uintptr_t(uintptr(unsafe.Pointer(&clength[0]))),
-               C.uint(len(data)), C.uint(flags), C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       ret := C.hs_scan_vector_cgo(db, (**C.char)(unsafe.Pointer(&cdata[0])), (*C.uint)(unsafe.Pointer(&clength[0])),
+               C.uint(len(data)), C.uint(flags), scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+
+       runtime.KeepAlive(ctxt)
+
+       for i, _ := range cdata {
+               C.free(unsafe.Pointer(cdata[i]))
+       }

        if ret != C.HS_SUCCESS {
                return HsError(ret)
@@ -970,8 +983,11 @@ func hsScanStream(stream hsStream, data []byte, flags ScanFlag, scratch hsScratc
 
        ctxt := &hsMatchEventContext{onEvent, context}
 
-       ret := C.hs_scan_stream_cgo(C.uintptr_t(uintptr(unsafe.Pointer(stream))), C.uintptr_t(uintptr(unsafe.Pointer(&data[0]))), C.uint(len(data)),
-               C.uint(flags), C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       cdata := C.CString(string(data))
+       ret := C.hs_scan_stream_cgo(stream, (*C.char)(cdata), C.uint(len(data)), C.uint(flags), scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       C.free(unsafe.Pointer(cdata))
+
+       runtime.KeepAlive(ctxt)
 
        if ret != C.HS_SUCCESS {
                return HsError(ret)
@@ -983,7 +999,9 @@ func hsScanStream(stream hsStream, data []byte, flags ScanFlag, scratch hsScratc
 func hsCloseStream(stream hsStream, scratch hsScratch, onEvent hsMatchEventHandler, context interface{}) error {
        ctxt := &hsMatchEventContext{onEvent, context}
 
-       ret := C.hs_close_stream_cgo(C.uintptr_t(uintptr(unsafe.Pointer(stream))), C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       ret := C.hs_close_stream_cgo(stream, scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+
+       runtime.KeepAlive(ctxt)
 
        if ret != C.HS_SUCCESS {
                return HsError(ret)
@@ -995,8 +1013,9 @@ func hsCloseStream(stream hsStream, scratch hsScratch, onEvent hsMatchEventHandl
 func hsResetStream(stream hsStream, flags ScanFlag, scratch hsScratch, onEvent hsMatchEventHandler, context interface{}) error {
        ctxt := &hsMatchEventContext{onEvent, context}
 
-       ret := C.hs_reset_stream_cgo(C.uintptr_t(uintptr(unsafe.Pointer(stream))), C.uint(flags),
-               C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       ret := C.hs_reset_stream_cgo(stream, C.uint(flags), scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+
+       runtime.KeepAlive(ctxt)
 
        if ret != C.HS_SUCCESS {
                return HsError(ret)
@@ -1018,8 +1037,9 @@ func hsCopyStream(stream hsStream) (hsStream, error) {
 func hsResetAndCopyStream(to, from hsStream, scratch hsScratch, onEvent hsMatchEventHandler, context interface{}) error {
        ctxt := &hsMatchEventContext{onEvent, context}
 
-       ret := C.hs_reset_and_copy_stream_cgo(C.uintptr_t(uintptr(unsafe.Pointer(to))), C.uintptr_t(uintptr(unsafe.Pointer(from))),
-               C.uintptr_t(uintptr(unsafe.Pointer(scratch))), C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+       ret := C.hs_reset_and_copy_stream_cgo(to, from, scratch, C.uintptr_t(uintptr(unsafe.Pointer(ctxt))))
+
+       runtime.KeepAlive(ctxt)
 
        if ret != C.HS_SUCCESS {
                return HsError(ret)

from gohs.

flier avatar flier commented on July 29, 2024

Sorry for the slow response.

Since we haven't a better workaround for those tricks, the develop branch be merged to master, thanks very much :)

from gohs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.