Skip to content

Commit 544d29e

Browse files
committed
remote: add keep-alive and references to the repository
Especially in 1.8, the garbage collector can decide to finalize an object even as we are in one of its methods. This means it can free a remote while we're in one of its calls, as we're referencing the pointer inside the object, rather than the `Remote` itself.
1 parent daee43b commit 544d29e

File tree

1 file changed

+39
-12
lines changed

1 file changed

+39
-12
lines changed

remote.go

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ type ProxyOptions struct {
144144
type Remote struct {
145145
ptr *C.git_remote
146146
callbacks RemoteCallbacks
147+
repo *Repository
147148
}
148149

149150
type CertificateKind uint
@@ -370,6 +371,7 @@ func RemoteIsValidName(name string) bool {
370371
func (r *Remote) Free() {
371372
runtime.SetFinalizer(r, nil)
372373
C.git_remote_free(r.ptr)
374+
r.ptr = nil
373375
}
374376

375377
type RemoteCollection struct {
@@ -383,6 +385,7 @@ func (c *RemoteCollection) List() ([]string, error) {
383385
defer runtime.UnlockOSThread()
384386

385387
ecode := C.git_remote_list(&r, c.repo.ptr)
388+
runtime.KeepAlive(c.repo)
386389
if ecode < 0 {
387390
return nil, MakeGitError(ecode)
388391
}
@@ -393,7 +396,7 @@ func (c *RemoteCollection) List() ([]string, error) {
393396
}
394397

395398
func (c *RemoteCollection) Create(name string, url string) (*Remote, error) {
396-
remote := &Remote{}
399+
remote := &Remote{repo: c.repo}
397400

398401
cname := C.CString(name)
399402
defer C.free(unsafe.Pointer(cname))
@@ -419,14 +422,15 @@ func (c *RemoteCollection) Delete(name string) error {
419422
defer runtime.UnlockOSThread()
420423

421424
ret := C.git_remote_delete(c.repo.ptr, cname)
425+
runtime.KeepAlive(c.repo)
422426
if ret < 0 {
423427
return MakeGitError(ret)
424428
}
425429
return nil
426430
}
427431

428432
func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch string) (*Remote, error) {
429-
remote := &Remote{}
433+
remote := &Remote{repo: c.repo}
430434

431435
cname := C.CString(name)
432436
defer C.free(unsafe.Pointer(cname))
@@ -447,7 +451,7 @@ func (c *RemoteCollection) CreateWithFetchspec(name string, url string, fetch st
447451
}
448452

449453
func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
450-
remote := &Remote{}
454+
remote := &Remote{repo: c.repo}
451455

452456
curl := C.CString(url)
453457
defer C.free(unsafe.Pointer(curl))
@@ -464,7 +468,7 @@ func (c *RemoteCollection) CreateAnonymous(url string) (*Remote, error) {
464468
}
465469

466470
func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
467-
remote := &Remote{}
471+
remote := &Remote{repo: c.repo}
468472

469473
cname := C.CString(name)
470474
defer C.free(unsafe.Pointer(cname))
@@ -481,15 +485,21 @@ func (c *RemoteCollection) Lookup(name string) (*Remote, error) {
481485
}
482486

483487
func (o *Remote) Name() string {
484-
return C.GoString(C.git_remote_name(o.ptr))
488+
s := C.git_remote_name(o.ptr)
489+
runtime.KeepAlive(o)
490+
return C.GoString(s)
485491
}
486492

487493
func (o *Remote) Url() string {
488-
return C.GoString(C.git_remote_url(o.ptr))
494+
s := C.git_remote_url(o.ptr)
495+
runtime.KeepAlive(o)
496+
return C.GoString(s)
489497
}
490498

491499
func (o *Remote) PushUrl() string {
492-
return C.GoString(C.git_remote_pushurl(o.ptr))
500+
s := C.git_remote_pushurl(o.ptr)
501+
runtime.KeepAlive(o)
502+
return C.GoString(s)
493503
}
494504

495505
func (c *RemoteCollection) Rename(remote, newname string) ([]string, error) {
@@ -504,6 +514,7 @@ func (c *RemoteCollection) Rename(remote, newname string) ([]string, error) {
504514
defer runtime.UnlockOSThread()
505515

506516
ret := C.git_remote_rename(&cproblems, c.repo.ptr, cremote, cnewname)
517+
runtime.KeepAlive(c.repo)
507518
if ret < 0 {
508519
return []string{}, MakeGitError(ret)
509520
}
@@ -522,6 +533,7 @@ func (c *RemoteCollection) SetUrl(remote, url string) error {
522533
defer runtime.UnlockOSThread()
523534

524535
ret := C.git_remote_set_url(c.repo.ptr, cremote, curl)
536+
runtime.KeepAlive(c.repo)
525537
if ret < 0 {
526538
return MakeGitError(ret)
527539
}
@@ -538,6 +550,7 @@ func (c *RemoteCollection) SetPushUrl(remote, url string) error {
538550
defer runtime.UnlockOSThread()
539551

540552
ret := C.git_remote_set_pushurl(c.repo.ptr, cremote, curl)
553+
runtime.KeepAlive(c.repo)
541554
if ret < 0 {
542555
return MakeGitError(ret)
543556
}
@@ -554,6 +567,7 @@ func (c *RemoteCollection) AddFetch(remote, refspec string) error {
554567
defer runtime.UnlockOSThread()
555568

556569
ret := C.git_remote_add_fetch(c.repo.ptr, cremote, crefspec)
570+
runtime.KeepAlive(c.repo)
557571
if ret < 0 {
558572
return MakeGitError(ret)
559573
}
@@ -605,6 +619,7 @@ func (o *Remote) FetchRefspecs() ([]string, error) {
605619
defer runtime.UnlockOSThread()
606620

607621
ret := C.git_remote_get_fetch_refspecs(&crefspecs, o.ptr)
622+
runtime.KeepAlive(o)
608623
if ret < 0 {
609624
return nil, MakeGitError(ret)
610625
}
@@ -624,6 +639,7 @@ func (c *RemoteCollection) AddPush(remote, refspec string) error {
624639
defer runtime.UnlockOSThread()
625640

626641
ret := C.git_remote_add_push(c.repo.ptr, cremote, crefspec)
642+
runtime.KeepAlive(c.repo)
627643
if ret < 0 {
628644
return MakeGitError(ret)
629645
}
@@ -641,12 +657,16 @@ func (o *Remote) PushRefspecs() ([]string, error) {
641657
return nil, MakeGitError(ret)
642658
}
643659
defer C.git_strarray_free(&crefspecs)
660+
runtime.KeepAlive(o)
661+
644662
refspecs := makeStringsFromCStrings(crefspecs.strings, int(crefspecs.count))
645663
return refspecs, nil
646664
}
647665

648666
func (o *Remote) RefspecCount() uint {
649-
return uint(C.git_remote_refspec_count(o.ptr))
667+
count := C.git_remote_refspec_count(o.ptr)
668+
runtime.KeepAlive(o)
669+
return uint(count)
650670
}
651671

652672
func populateFetchOptions(options *C.git_fetch_options, opts *FetchOptions) {
@@ -706,6 +726,7 @@ func (o *Remote) Fetch(refspecs []string, opts *FetchOptions, msg string) error
706726
defer runtime.UnlockOSThread()
707727

708728
ret := C.git_remote_fetch(o.ptr, &crefspecs, coptions, cmsg)
729+
runtime.KeepAlive(o)
709730
if ret < 0 {
710731
return MakeGitError(ret)
711732
}
@@ -734,17 +755,18 @@ func (o *Remote) Connect(direction ConnectDirection, callbacks *RemoteCallbacks,
734755
var cproxy C.git_proxy_options
735756
populateProxyOptions(&cproxy, proxyOpts)
736757
defer freeProxyOptions(&cproxy)
737-
758+
738759
cheaders := C.git_strarray{}
739760
cheaders.count = C.size_t(len(headers))
740761
cheaders.strings = makeCStringsFromStrings(headers)
741762
defer freeStrarray(&cheaders)
742763

743-
744764
runtime.LockOSThread()
745765
defer runtime.UnlockOSThread()
746766

747-
if ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders); ret != 0 {
767+
ret := C.git_remote_connect(o.ptr, C.git_direction(direction), &ccallbacks, &cproxy, &cheaders)
768+
runtime.KeepAlive(o)
769+
if ret != 0 {
748770
return MakeGitError(ret)
749771
}
750772
return nil
@@ -755,6 +777,7 @@ func (o *Remote) Disconnect() {
755777
defer runtime.UnlockOSThread()
756778

757779
C.git_remote_disconnect(o.ptr)
780+
runtime.KeepAlive(o)
758781
}
759782

760783
func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
@@ -765,7 +788,9 @@ func (o *Remote) Ls(filterRefs ...string) ([]RemoteHead, error) {
765788
runtime.LockOSThread()
766789
defer runtime.UnlockOSThread()
767790

768-
if ret := C.git_remote_ls(&refs, &length, o.ptr); ret != 0 {
791+
ret := C.git_remote_ls(&refs, &length, o.ptr)
792+
runtime.KeepAlive(o)
793+
if ret != 0 {
769794
return nil, MakeGitError(ret)
770795
}
771796

@@ -820,6 +845,7 @@ func (o *Remote) Push(refspecs []string, opts *PushOptions) error {
820845
defer runtime.UnlockOSThread()
821846

822847
ret := C.git_remote_push(o.ptr, &crefspecs, coptions)
848+
runtime.KeepAlive(o)
823849
if ret < 0 {
824850
return MakeGitError(ret)
825851
}
@@ -838,6 +864,7 @@ func (o *Remote) Prune(callbacks *RemoteCallbacks) error {
838864
defer runtime.UnlockOSThread()
839865

840866
ret := C.git_remote_prune(o.ptr, &ccallbacks)
867+
runtime.KeepAlive(o)
841868
if ret < 0 {
842869
return MakeGitError(ret)
843870
}

0 commit comments

Comments
 (0)