Fix a memory leak
This commit is contained in:
21
callback.go
21
callback.go
@@ -8,12 +8,13 @@ var cb struct {
|
|||||||
c int
|
c int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cb.m = make(map[int]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
func cbAdd(v interface{}) int {
|
func cbAdd(v interface{}) int {
|
||||||
cb.Lock()
|
cb.Lock()
|
||||||
defer cb.Unlock()
|
defer cb.Unlock()
|
||||||
if cb.m == nil {
|
|
||||||
cb.m = make(map[int]interface{})
|
|
||||||
}
|
|
||||||
cb.c++
|
cb.c++
|
||||||
cb.m[cb.c] = v
|
cb.m[cb.c] = v
|
||||||
return cb.c
|
return cb.c
|
||||||
@@ -22,9 +23,17 @@ func cbAdd(v interface{}) int {
|
|||||||
func cbGet(c int) interface{} {
|
func cbGet(c int) interface{} {
|
||||||
cb.Lock()
|
cb.Lock()
|
||||||
defer cb.Unlock()
|
defer cb.Unlock()
|
||||||
v := cb.m[c]
|
if v, ok := cb.m[c]; ok {
|
||||||
if v == nil {
|
return v
|
||||||
|
}
|
||||||
|
panic("Callback pointer not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func cbDelete(c int) {
|
||||||
|
cb.Lock()
|
||||||
|
defer cb.Unlock()
|
||||||
|
if _, ok := cb.m[c]; !ok {
|
||||||
panic("Callback pointer not found")
|
panic("Callback pointer not found")
|
||||||
}
|
}
|
||||||
return v
|
delete(cb.m, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ func TestCallback_001(t *testing.T) {
|
|||||||
if reflect.TypeOf(v) != reflect.TypeOf(TestCallback_001) {
|
if reflect.TypeOf(v) != reflect.TypeOf(TestCallback_001) {
|
||||||
t.Error("Received unexpected value")
|
t.Error("Received unexpected value")
|
||||||
}
|
}
|
||||||
|
cbDelete(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCallback_002(t *testing.T) {
|
func TestCallback_002(t *testing.T) {
|
||||||
@@ -21,3 +22,12 @@ func TestCallback_002(t *testing.T) {
|
|||||||
cbGet(c + 1)
|
cbGet(c + 1)
|
||||||
t.Error("Expected a panic")
|
t.Error("Expected a panic")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCallback_003(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
}()
|
||||||
|
c := cbAdd(TestCallback_003)
|
||||||
|
cbDelete(c + 1)
|
||||||
|
t.Error("Expected a panic")
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ func (f ConversationFunc) RespondPAM(s Style, msg string) (string, error) {
|
|||||||
|
|
||||||
// Constructs a new conversation object with a given handler and a newly
|
// Constructs a new conversation object with a given handler and a newly
|
||||||
// allocated pam_conv struct that uses this object as its appdata_ptr.
|
// allocated pam_conv struct that uses this object as its appdata_ptr.
|
||||||
func newConversation(handler ConversationHandler) (*C.struct_pam_conv, C.int) {
|
func newConversation(handler ConversationHandler) (*C.struct_pam_conv, int, C.int) {
|
||||||
c := cbAdd(handler)
|
c := cbAdd(handler)
|
||||||
conv := &C.struct_pam_conv{}
|
conv := &C.struct_pam_conv{}
|
||||||
C.init_pam_conv(conv, C.long(c))
|
C.init_pam_conv(conv, C.long(c))
|
||||||
return conv, C.PAM_SUCCESS
|
return conv, c, C.PAM_SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go-side function for processing a single conversational message. Ultimately
|
// Go-side function for processing a single conversational message. Ultimately
|
||||||
@@ -86,11 +86,13 @@ type Transaction struct {
|
|||||||
handle *C.pam_handle_t
|
handle *C.pam_handle_t
|
||||||
conv *C.struct_pam_conv
|
conv *C.struct_pam_conv
|
||||||
status C.int
|
status C.int
|
||||||
|
c int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize a PAM transaction.
|
// Finalize a PAM transaction.
|
||||||
func transactionFinalizer(t *Transaction) {
|
func transactionFinalizer(t *Transaction) {
|
||||||
C.pam_end(t.handle, t.status)
|
C.pam_end(t.handle, t.status)
|
||||||
|
cbDelete(t.c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start initiates a new PAM transaction. Service is treated identically to
|
// Start initiates a new PAM transaction. Service is treated identically to
|
||||||
@@ -100,10 +102,11 @@ func transactionFinalizer(t *Transaction) {
|
|||||||
// transaction provides an interface to the remainder of the API.
|
// transaction provides an interface to the remainder of the API.
|
||||||
func Start(service, user string, handler ConversationHandler) (*Transaction, error) {
|
func Start(service, user string, handler ConversationHandler) (*Transaction, error) {
|
||||||
t := &Transaction{}
|
t := &Transaction{}
|
||||||
t.conv, t.status = newConversation(handler)
|
t.conv, t.c, t.status = newConversation(handler)
|
||||||
if t.status != C.PAM_SUCCESS {
|
if t.status != C.PAM_SUCCESS {
|
||||||
return nil, t
|
return nil, t
|
||||||
}
|
}
|
||||||
|
runtime.SetFinalizer(t, transactionFinalizer)
|
||||||
s := C.CString(service)
|
s := C.CString(service)
|
||||||
defer C.free(unsafe.Pointer(s))
|
defer C.free(unsafe.Pointer(s))
|
||||||
var u *C.char
|
var u *C.char
|
||||||
@@ -115,7 +118,6 @@ func Start(service, user string, handler ConversationHandler) (*Transaction, err
|
|||||||
if t.status != C.PAM_SUCCESS {
|
if t.status != C.PAM_SUCCESS {
|
||||||
return nil, t
|
return nil, t
|
||||||
}
|
}
|
||||||
runtime.SetFinalizer(t, transactionFinalizer)
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user