Go: do not store pointer to Go object.

To pass Go object references to C and back we use hack with casting to
unsafe and then to uintptr.  However, we should not store such references
because Go not guaratnee it will be available by the same address.
Introducing map with integer key helps to avoid dereference stored address.

This closes #253 and #309 issues on GitHub.
This commit is contained in:
Max Romanov
2019-09-18 18:31:14 +03:00
parent 4ea9ed309e
commit 84e4a6437f
2 changed files with 49 additions and 2 deletions

View File

@@ -135,7 +135,7 @@ func nxt_go_request_set_tls(go_req uintptr) {
//export nxt_go_request_handler
func nxt_go_request_handler(go_req uintptr, h uintptr) {
r := get_request(go_req)
handler := *(*http.Handler)(unsafe.Pointer(h))
handler := get_handler(h)
go func(r *request) {
handler.ServeHTTP(r.response(), &r.req)

View File

@@ -13,6 +13,7 @@ import "C"
import (
"fmt"
"net/http"
"sync"
"unsafe"
)
@@ -87,12 +88,58 @@ func nxt_go_warn(format string, args ...interface{}) {
C.nxt_cgo_warn(str_ref(str), C.uint32_t(len(str)))
}
type handler_registry struct {
sync.RWMutex
next uintptr
m map[uintptr]*http.Handler
}
var handler_registry_ handler_registry
func set_handler(handler *http.Handler) uintptr {
handler_registry_.Lock()
if handler_registry_.m == nil {
handler_registry_.m = make(map[uintptr]*http.Handler)
handler_registry_.next = 1
}
h := handler_registry_.next
handler_registry_.next += 1
handler_registry_.m[h] = handler
handler_registry_.Unlock()
return h
}
func get_handler(h uintptr) http.Handler {
handler_registry_.RLock()
defer handler_registry_.RUnlock()
return *handler_registry_.m[h]
}
func reset_handler(h uintptr) {
handler_registry_.Lock()
if handler_registry_.m != nil {
delete(handler_registry_.m, h)
}
handler_registry_.Unlock()
}
func ListenAndServe(addr string, handler http.Handler) error {
if handler == nil {
handler = http.DefaultServeMux
}
rc := C.nxt_cgo_run(C.uintptr_t(uintptr(unsafe.Pointer(&handler))))
h := set_handler(&handler)
rc := C.nxt_cgo_run(C.uintptr_t(h))
reset_handler(h)
if rc != 0 {
return http.ListenAndServe(addr, handler)