Skip to content

Commit 37f732a

Browse files
committed
Fix the Cred interface
This change adds Cred.Free() and finalizers to prevent memory leaks. It also makes the interface for Cred more idiomatic and return actual errors intead of ints.
1 parent 45097a8 commit 37f732a

File tree

2 files changed

+73
-21
lines changed

2 files changed

+73
-21
lines changed

credentials.go

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ package git
77
git_credtype_t _go_git_cred_credtype(git_cred *cred);
88
*/
99
import "C"
10-
import "unsafe"
10+
import (
11+
"runtime"
12+
"unsafe"
13+
)
1114

1215
type CredType uint
1316

@@ -22,6 +25,12 @@ type Cred struct {
2225
ptr *C.git_cred
2326
}
2427

28+
func newCred() *Cred {
29+
cred := &Cred{}
30+
runtime.SetFinalizer(cred, (*Cred).Free)
31+
return cred
32+
}
33+
2534
func (o *Cred) HasUsername() bool {
2635
if C.git_cred_has_username(o.ptr) == 1 {
2736
return true
@@ -33,24 +42,36 @@ func (o *Cred) Type() CredType {
3342
return (CredType)(C._go_git_cred_credtype(o.ptr))
3443
}
3544

36-
func credFromC(ptr *C.git_cred) *Cred {
37-
return &Cred{ptr}
45+
func (o *Cred) Free() {
46+
C.git_cred_free(o.ptr)
47+
runtime.SetFinalizer(o, nil)
48+
o.ptr = nil
3849
}
3950

40-
func NewCredUserpassPlaintext(username string, password string) (int, Cred) {
41-
cred := Cred{}
51+
func NewCredUserpassPlaintext(username string, password string) (*Cred, error) {
52+
runtime.LockOSThread()
53+
defer runtime.UnlockOSThread()
54+
55+
cred := newCred()
4256
cusername := C.CString(username)
4357
defer C.free(unsafe.Pointer(cusername))
4458
cpassword := C.CString(password)
4559
defer C.free(unsafe.Pointer(cpassword))
4660
ret := C.git_cred_userpass_plaintext_new(&cred.ptr, cusername, cpassword)
47-
return int(ret), cred
61+
if ret != 0 {
62+
cred.Free()
63+
return nil, MakeGitError(ret)
64+
}
65+
return cred, nil
4866
}
4967

5068
// NewCredSshKey creates new ssh credentials reading the public and private keys
5169
// from the file system.
52-
func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (int, Cred) {
53-
cred := Cred{}
70+
func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string, passphrase string) (*Cred, error) {
71+
runtime.LockOSThread()
72+
defer runtime.UnlockOSThread()
73+
74+
cred := newCred()
5475
cusername := C.CString(username)
5576
defer C.free(unsafe.Pointer(cusername))
5677
cpublickey := C.CString(publicKeyPath)
@@ -60,13 +81,20 @@ func NewCredSshKey(username string, publicKeyPath string, privateKeyPath string,
6081
cpassphrase := C.CString(passphrase)
6182
defer C.free(unsafe.Pointer(cpassphrase))
6283
ret := C.git_cred_ssh_key_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
63-
return int(ret), cred
84+
if ret != 0 {
85+
cred.Free()
86+
return nil, MakeGitError(ret)
87+
}
88+
return cred, nil
6489
}
6590

6691
// NewCredSshKeyFromMemory creates new ssh credentials using the publicKey and privateKey
6792
// arguments as the values for the public and private keys.
68-
func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (int, Cred) {
69-
cred := Cred{}
93+
func NewCredSshKeyFromMemory(username string, publicKey string, privateKey string, passphrase string) (*Cred, error) {
94+
runtime.LockOSThread()
95+
defer runtime.UnlockOSThread()
96+
97+
cred := newCred()
7098
cusername := C.CString(username)
7199
defer C.free(unsafe.Pointer(cusername))
72100
cpublickey := C.CString(publicKey)
@@ -76,19 +104,37 @@ func NewCredSshKeyFromMemory(username string, publicKey string, privateKey strin
76104
cpassphrase := C.CString(passphrase)
77105
defer C.free(unsafe.Pointer(cpassphrase))
78106
ret := C.git_cred_ssh_key_memory_new(&cred.ptr, cusername, cpublickey, cprivatekey, cpassphrase)
79-
return int(ret), cred
107+
if ret != 0 {
108+
cred.Free()
109+
return nil, MakeGitError(ret)
110+
}
111+
return cred, nil
80112
}
81113

82-
func NewCredSshKeyFromAgent(username string) (int, Cred) {
83-
cred := Cred{}
114+
func NewCredSshKeyFromAgent(username string) (*Cred, error) {
115+
runtime.LockOSThread()
116+
defer runtime.UnlockOSThread()
117+
118+
cred := newCred()
84119
cusername := C.CString(username)
85120
defer C.free(unsafe.Pointer(cusername))
86121
ret := C.git_cred_ssh_key_from_agent(&cred.ptr, cusername)
87-
return int(ret), cred
122+
if ret != 0 {
123+
cred.Free()
124+
return nil, MakeGitError(ret)
125+
}
126+
return cred, nil
88127
}
89128

90-
func NewCredDefault() (int, Cred) {
91-
cred := Cred{}
129+
func NewCredDefault() (*Cred, error) {
130+
runtime.LockOSThread()
131+
defer runtime.UnlockOSThread()
132+
133+
cred := newCred()
92134
ret := C.git_cred_default_new(&cred.ptr)
93-
return int(ret), cred
135+
if ret != 0 {
136+
cred.Free()
137+
return nil, MakeGitError(ret)
138+
}
139+
return cred, nil
94140
}

remote.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ const (
5151

5252
type TransportMessageCallback func(str string) ErrorCode
5353
type CompletionCallback func(RemoteCompletion) ErrorCode
54-
type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (ErrorCode, *Cred)
54+
type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (*Cred, error)
5555
type TransferProgressCallback func(stats TransferProgress) ErrorCode
5656
type UpdateTipsCallback func(refname string, a *Oid, b *Oid) ErrorCode
5757
type CertificateCheckCallback func(cert *Certificate, valid bool, hostname string) ErrorCode
@@ -246,11 +246,17 @@ func credentialsCallback(_cred **C.git_cred, _url *C.char, _username_from_url *C
246246
}
247247
url := C.GoString(_url)
248248
username_from_url := C.GoString(_username_from_url)
249-
ret, cred := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
249+
cred, err := callbacks.CredentialsCallback(url, username_from_url, (CredType)(allowed_types))
250+
if err != nil {
251+
if gitError, ok := err.(*GitError); ok {
252+
return int(gitError.Code)
253+
}
254+
return C.GIT_EUSER
255+
}
250256
if cred != nil {
251257
*_cred = cred.ptr
252258
}
253-
return int(ret)
259+
return 0
254260
}
255261

256262
//export transferProgressCallback

0 commit comments

Comments
 (0)