Closed
Description
The following program hangs most times I run it (but not always):
package main
import (
"log"
git "gopkg.in/libgit2/git2go.v24"
)
// mirror does a clone --mirror of url into dest.
func mirror(url, dest string) (*git.Repository, error) {
log.Printf("starting clone of %s into %s", url, dest)
repo, err := git.Clone(url, dest, &git.CloneOptions{Bare: true})
if err != nil {
log.Printf("clone of %s into %s failed: %v", url, dest, err)
return nil, err
}
log.Printf("finished clone of %s into %s", url, dest)
cfg, err := repo.Config()
if err != nil {
return nil, err
}
remotes, err := repo.Remotes.List()
if err != nil || len(remotes) == 0 || remotes[0] != "origin" {
return nil, err
}
log.Printf("converting remote origin to mirror")
cfg.SetBool("remote.origin.mirror", true)
cfg.SetString("remote.origin.fetch", "+refs/*:refs/*")
remote, err := repo.Remotes.Lookup("origin")
if err != nil {
return nil, err
}
log.Printf("starting mirror fetch of %s into %s", url, dest)
err = remote.Fetch(nil, &git.FetchOptions{}, "")
if err != nil {
log.Printf("mirror fetch of %s into %s failed: %v", url, dest, err)
return nil, err
}
log.Printf("finished mirror fetch of %s into %s", url, dest)
return repo, nil
}
func main() {
dest := "/tmp/review_clone_go"
url := "https://go.googlesource.com/review"
_, err := mirror(url, dest)
if err != nil {
log.Printf("fail: %v", err)
return
}
log.Print("success")
}
It hangs during the call to remote.Fetch. Sample run, killed manually by SIGQUIT when it hung:
$ go run bug.go
2016/12/02 16:22:39 starting clone of https://go.googlesource.com/review into /tmp/review_clone_go
2016/12/02 16:22:41 finished clone of https://go.googlesource.com/review into /tmp/review_clone_go
2016/12/02 16:22:41 converting remote origin to mirror
2016/12/02 16:22:41 starting mirror fetch of https://go.googlesource.com/review into /tmp/review_clone_go
^\SIGQUIT: quit
PC=0x7fffc1f20f4e m=0
signal arrived during cgo execution
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x40f7e80, 0xc420051be8, 0xc400000000)
/Users/josh/go/1.7/src/runtime/cgocall.go:131 +0x110 fp=0xc420051bb8 sp=0xc420051b78
gopkg.in/libgit2/git2go%2ev24._Cfunc_git_remote_fetch(0x4612b40, 0x0, 0x4616a20, 0x0, 0x0)
??:0 +0x4d fp=0xc420051be8 sp=0xc420051bb8
gopkg.in/libgit2/git2go%2ev24.(*Remote).Fetch(0xc420014320, 0x0, 0x0, 0x0, 0xc42001a200, 0x0, 0x0, 0x0, 0x0)
/Users/josh/src/gopkg.in/libgit2/git2go.v24/remote.go:655 +0x308 fp=0xc420051c78 sp=0xc420051be8
main.mirror(0x41486f0, 0x22, 0x41456c5, 0x14, 0x0, 0x0, 0x0)
/Users/josh/src/foggy.co/gopath/bug.go:38 +0x7ef fp=0xc420051ed0 sp=0xc420051c78
main.main()
/Users/josh/src/foggy.co/gopath/bug.go:51 +0x4f fp=0xc420051f48 sp=0xc420051ed0
runtime.main()
/Users/josh/go/1.7/src/runtime/proc.go:183 +0x1f4 fp=0xc420051fa0 sp=0xc420051f48
runtime.goexit()
/Users/josh/go/1.7/src/runtime/asm_amd64.s:2086 +0x1 fp=0xc420051fa8 sp=0xc420051fa0
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
/Users/josh/go/1.7/src/runtime/asm_amd64.s:2086 +0x1
rax 0x4
rbx 0x0
rcx 0x7fff5fbff018
rdx 0x7fff5fbff0a0
rdi 0x7
rsi 0x7fff5fbff120
rbp 0x7fff5fbff1d0
rsp 0x7fff5fbff018
r8 0x0
r9 0x80ee
r10 0x7fff5fbff020
r11 0x283
r12 0x7fff5fbff1e8
r13 0xf32b
r14 0x5
r15 0x480a400
rip 0x7fffc1f20f4e
rflags 0x283
cs 0x7
fs 0x0
gs 0x0
exit status 2
Reproduced with both Go 1.7.4 and Go 1.8 beta 1.
Doing some horrible manual symbol resolution, I managed to tease out this backtrace:
* thread #1: tid = 0x54e8c, 0x00007fffc1f20f4e, stop reason = signal SIGSTOP
* frame #0: 0x00007fffc1f20f4e
frame #1: 0x0000000004368fa9 libgit2.24.dylib`curls_read + 41
frame #2: 0x00000000043bfe2b libgit2.24.dylib`read_cb + 40
frame #3: 0x00007fffb2ec541f
frame #4: 0x00007fffb2e56f07
frame #5: 0x00007fffb2e5a856
frame #6: 0x00000000043c00bb libgit2.24.dylib`stransport_read + 21
frame #7: 0x0000000004392cf9 libgit2.24.dylib`recv_stream + 30
frame #8: 0x00000000043cd9a9 libgit2.24.dylib`http_stream_read + 438
frame #9: 0x00000000043cf617 libgit2.24.dylib`git_smart__recv_cb + 53
frame #10: 0x00000000043d168d libgit2.24.dylib`recv_pkt + 94
frame #11: 0x00000000043d1808 libgit2.24.dylib`git_smart__download_pack + 313
frame #12: 0x00000000043b0af0 libgit2.24.dylib`git_remote_download + 556
frame #13: 0x00000000043b0d74 libgit2.24.dylib`git_remote_fetch + 155
frame #14: 0x00000000040fb719
frame #15: 0x000000000404ed20
frame #16: 0x00000000040ebecd
frame #17: 0x00000000040f43cc
frame #18: 0x00000000040f1db2
frame #19: 0x00000000040f69be
frame #20: 0x00000000040f6df0
frame #21: 0x00000000040f6f34
frame #22: 0x000000000402af6a
Frames 14 to 22 are all in Go world and are uninteresting. I believe that the pcs in the 0x00007fff... range correspond to assertion failures.
libgit2 itself does not appear to be the problem. The following equivalent C program always works successfully.
#include <git2.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
git_libgit2_init();
git_repository *repo = NULL;
const char *url = "https://go.googlesource.com/review";
const char *dest = "/tmp/review_clone_c";
git_clone_options clone_opts;
git_clone_init_options(&clone_opts, GIT_CLONE_OPTIONS_VERSION);
clone_opts.bare = 1;
int err = git_clone(&repo, url, dest, &clone_opts);
if (err != 0) {
printf("clone err: %d\n", err);
return 1;
}
git_remote *remote = NULL;
err = git_remote_lookup(&remote, repo, "origin");
if (err != 0) {
printf("remote lookup err: %d\n", err);
return 1;
}
git_config *cfg;
err = git_repository_config(&cfg, repo);
if (err != 0) {
printf("config err: %d\n", err);
return 1;
}
err = git_config_set_bool(cfg, "remote.origin.mirror", 1);
if (err != 0) {
printf("config bool err: %d\n", err);
return 1;
}
err = git_config_set_string(cfg, "remote.origin.fetch", "+refs/*:refs/*");
if (err != 0) {
printf("config str err: %d\n", err);
return 1;
}
git_fetch_options fetch_opts;
err = git_fetch_init_options(&fetch_opts, GIT_FETCH_OPTIONS_VERSION);
if (err != 0) {
printf("fetch options init err: %d\n", err);
return 1;
}
err = git_remote_fetch(remote, NULL, &fetch_opts, NULL);
if (err != 0) {
printf("fetch err: %d\n", err);
return 1;
}
printf("success\n");
return 0;
}
This smells like memory corruption due to a race somewhere, but I don't see where/how. Running under the Go race detector yields no complaints. I'm running darwin, not linux, so I can't test with -msan
.
Metadata
Metadata
Assignees
Labels
No labels