summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Steinert <[email protected]>2015-12-04 09:03:39 -0600
committerMichael Steinert <[email protected]>2015-12-04 09:03:39 -0600
commita245f1098c428f046096700d36291689f7037bc4 (patch)
tree160a17ed7d5941b91a3d79c678ba20799a1a9a1a
parent8ec1202046731e0b8eaa52dc88ae9b831b5b39a7 (diff)
Fix a memory leak
-rw-r--r--callback.go21
-rw-r--r--callback_test.go10
-rw-r--r--transaction.go10
3 files changed, 31 insertions, 10 deletions
diff --git a/callback.go b/callback.go
index f2d7210..672a36e 100644
--- a/callback.go
+++ b/callback.go
@@ -8,12 +8,13 @@ var cb struct {
c int
}
+func init() {
+ cb.m = make(map[int]interface{})
+}
+
func cbAdd(v interface{}) int {
cb.Lock()
defer cb.Unlock()
- if cb.m == nil {
- cb.m = make(map[int]interface{})
- }
cb.c++
cb.m[cb.c] = v
return cb.c
@@ -22,9 +23,17 @@ func cbAdd(v interface{}) int {
func cbGet(c int) interface{} {
cb.Lock()
defer cb.Unlock()
- v := cb.m[c]
- if v == nil {
+ if v, ok := cb.m[c]; ok {
+ 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")
}
- return v
+ delete(cb.m, c)
}
diff --git a/callback_test.go b/callback_test.go
index ae1eefe..45a84be 100644
--- a/callback_test.go
+++ b/callback_test.go
@@ -11,6 +11,7 @@ func TestCallback_001(t *testing.T) {
if reflect.TypeOf(v) != reflect.TypeOf(TestCallback_001) {
t.Error("Received unexpected value")
}
+ cbDelete(c)
}
func TestCallback_002(t *testing.T) {
@@ -21,3 +22,12 @@ func TestCallback_002(t *testing.T) {
cbGet(c + 1)
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")
+}
diff --git a/transaction.go b/transaction.go
index f136abd..458804d 100644
--- a/transaction.go
+++ b/transaction.go
@@ -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
// 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)
conv := &C.struct_pam_conv{}
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
@@ -86,11 +86,13 @@ type Transaction struct {
handle *C.pam_handle_t
conv *C.struct_pam_conv
status C.int
+ c int
}
// Finalize a PAM transaction.
func transactionFinalizer(t *Transaction) {
C.pam_end(t.handle, t.status)
+ cbDelete(t.c)
}
// 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.
func Start(service, user string, handler ConversationHandler) (*Transaction, error) {
t := &Transaction{}
- t.conv, t.status = newConversation(handler)
+ t.conv, t.c, t.status = newConversation(handler)
if t.status != C.PAM_SUCCESS {
return nil, t
}
+ runtime.SetFinalizer(t, transactionFinalizer)
s := C.CString(service)
defer C.free(unsafe.Pointer(s))
var u *C.char
@@ -115,7 +118,6 @@ func Start(service, user string, handler ConversationHandler) (*Transaction, err
if t.status != C.PAM_SUCCESS {
return nil, t
}
- runtime.SetFinalizer(t, transactionFinalizer)
return t, nil
}