diff options
-rw-r--r-- | src/cmd/internal/src/pos.go | 5 | ||||
-rw-r--r-- | src/cmd/internal/src/pos_test.go | 14 | ||||
-rw-r--r-- | src/cmd/objdump/objdump_test.go | 3 | ||||
-rw-r--r-- | src/crypto/x509/parser.go | 4 | ||||
-rw-r--r-- | src/crypto/x509/x509_test.go | 48 | ||||
-rw-r--r-- | src/net/dial_test.go | 6 | ||||
-rw-r--r-- | src/net/http/httptest/server.go | 29 | ||||
-rw-r--r-- | src/net/http/httptest/server_test.go | 54 | ||||
-rw-r--r-- | src/runtime/signal_unix.go | 4 | ||||
-rw-r--r-- | src/sync/waitgroup_test.go | 126 | ||||
-rw-r--r-- | src/syscall/exec_linux_test.go | 25 | ||||
-rw-r--r-- | src/syscall/syscall_linux.go | 2 |
12 files changed, 149 insertions, 171 deletions
diff --git a/src/cmd/internal/src/pos.go b/src/cmd/internal/src/pos.go index b6816a56e0..373a22a7f2 100644 --- a/src/cmd/internal/src/pos.go +++ b/src/cmd/internal/src/pos.go @@ -389,9 +389,12 @@ func makeBogusLico() lico { } func makeLico(line, col uint) lico { - if line > lineMax { + if line >= lineMax { // cannot represent line, use max. line so we have some information line = lineMax + // Drop column information if line number saturates. + // Ensures line+col is monotonic. See issue 51193. + col = 0 } if col > colMax { // cannot represent column, use max. column so we have some information diff --git a/src/cmd/internal/src/pos_test.go b/src/cmd/internal/src/pos_test.go index d4cd0e7ff1..cdf4ab4081 100644 --- a/src/cmd/internal/src/pos_test.go +++ b/src/cmd/internal/src/pos_test.go @@ -140,8 +140,8 @@ func TestLico(t *testing.T) { {makeLico(1, 0), ":1", 1, 0}, {makeLico(1, 1), ":1:1", 1, 1}, {makeLico(2, 3), ":2:3", 2, 3}, - {makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, - {makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, // line too large, stick with max. line + {makeLico(lineMax, 1), fmt.Sprintf(":%d", lineMax), lineMax, 1}, + {makeLico(lineMax+1, 1), fmt.Sprintf(":%d", lineMax), lineMax, 1}, // line too large, stick with max. line {makeLico(1, colMax), ":1", 1, colMax}, {makeLico(1, colMax+1), ":1", 1, 0}, // column too large {makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax), lineMax, 0}, @@ -170,8 +170,8 @@ func TestIsStmt(t *testing.T) { {makeLico(1, 1), ":1:1" + def, 1, 1}, {makeLico(1, 1).withIsStmt(), ":1:1" + is, 1, 1}, {makeLico(1, 1).withNotStmt(), ":1:1" + not, 1, 1}, - {makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax) + def, lineMax, 1}, - {makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax) + def, lineMax, 1}, // line too large, stick with max. line + {makeLico(lineMax, 1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 1}, + {makeLico(lineMax+1, 1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 1}, // line too large, stick with max. line {makeLico(1, colMax), ":1" + def, 1, colMax}, {makeLico(1, colMax+1), ":1" + def, 1, 0}, // column too large {makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax) + def, lineMax, 0}, @@ -214,9 +214,9 @@ func TestLogue(t *testing.T) { {makeLico(1, 1).withXlogue(PosPrologueEnd), ":1:1" + defs + pro, 1, 1}, {makeLico(1, 1).withXlogue(PosEpilogueBegin), ":1:1" + defs + epi, 1, 1}, - {makeLico(lineMax, 1).withXlogue(PosDefaultLogue), fmt.Sprintf(":%d:1", lineMax) + defs + defp, lineMax, 1}, - {makeLico(lineMax, 1).withXlogue(PosPrologueEnd), fmt.Sprintf(":%d:1", lineMax) + defs + pro, lineMax, 1}, - {makeLico(lineMax, 1).withXlogue(PosEpilogueBegin), fmt.Sprintf(":%d:1", lineMax) + defs + epi, lineMax, 1}, + {makeLico(lineMax, 1).withXlogue(PosDefaultLogue), fmt.Sprintf(":%d", lineMax) + defs + defp, lineMax, 1}, + {makeLico(lineMax, 1).withXlogue(PosPrologueEnd), fmt.Sprintf(":%d", lineMax) + defs + pro, lineMax, 1}, + {makeLico(lineMax, 1).withXlogue(PosEpilogueBegin), fmt.Sprintf(":%d", lineMax) + defs + epi, lineMax, 1}, } { x := test.x if got := formatstr("", x.Line(), x.Col(), true) + fmt.Sprintf(":%d:%d", x.IsStmt(), x.Xlogue()); got != test.string { diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index f231a7c6e0..1ce21c46ab 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -106,6 +106,9 @@ var ppcGnuNeed = []string{ } func mustHaveDisasm(t *testing.T) { + if strings.HasPrefix(testenv.Builder(), "darwin-arm64") { + t.Skipf("builder %q has an incompatible version of XCode installed, see go.dev/issue/49700", testenv.Builder()) + } switch runtime.GOARCH { case "mips", "mipsle", "mips64", "mips64le": t.Skipf("skipping on %s, issue 12559", runtime.GOARCH) diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go index 9a500a8098..635e74bd89 100644 --- a/src/crypto/x509/parser.go +++ b/src/crypto/x509/parser.go @@ -941,10 +941,10 @@ func parseCertificate(der []byte) (*Certificate, error) { } if cert.Version > 1 { - if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).Constructed().ContextSpecific()) { + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { return nil, errors.New("x509: malformed issuerUniqueID") } - if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).Constructed().ContextSpecific()) { + if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { return nil, errors.New("x509: malformed subjectUniqueID") } if cert.Version == 3 { diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 449379fbb1..f32dc7d9bf 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -3311,3 +3311,51 @@ func TestLargeOID(t *testing.T) { t.Fatalf("ParseCertificate to failed to parse certificate with large OID: %s", err) } } + +const uniqueIDPEM = `-----BEGIN CERTIFICATE----- +MIIFsDCCBJigAwIBAgIIrOyC1ydafZMwDQYJKoZIhvcNAQEFBQAwgY4xgYswgYgG +A1UEAx6BgABNAGkAYwByAG8AcwBvAGYAdAAgAEYAbwByAGUAZgByAG8AbgB0ACAA +VABNAEcAIABIAFQAVABQAFMAIABJAG4AcwBwAGUAYwB0AGkAbwBuACAAQwBlAHIA +dABpAGYAaQBjAGEAdABpAG8AbgAgAEEAdQB0AGgAbwByAGkAdAB5MB4XDTE0MDEx +ODAwNDEwMFoXDTE1MTExNTA5Mzc1NlowgZYxCzAJBgNVBAYTAklEMRAwDgYDVQQI +EwdqYWthcnRhMRIwEAYDVQQHEwlJbmRvbmVzaWExHDAaBgNVBAoTE3N0aG9ub3Jl +aG90ZWxyZXNvcnQxHDAaBgNVBAsTE3N0aG9ub3JlaG90ZWxyZXNvcnQxJTAjBgNV +BAMTHG1haWwuc3Rob25vcmVob3RlbHJlc29ydC5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCvuu0qpI+Ko2X84Twkf84cRD/rgp6vpgc5Ebejx/D4 +PEVON5edZkazrMGocK/oQqIlRxx/lefponN/chlGcllcVVPWTuFjs8k+Aat6T1qp +4iXxZekAqX+U4XZMIGJD3PckPL6G2RQSlF7/LhGCsRNRdKpMWSTbou2Ma39g52Kf +gsl3SK/GwLiWpxpcSkNQD1hugguEIsQYLxbeNwpcheXZtxbBGguPzQ7rH8c5vuKU +BkMOzaiNKLzHbBdFSrua8KWwCJg76Vdq/q36O9GlW6YgG3i+A4pCJjXWerI1lWwX +Ktk5V+SvUHGey1bkDuZKJ6myMk2pGrrPWCT7jP7WskChAgMBAAGBCQBCr1dgEleo +cKOCAfswggH3MIHDBgNVHREEgbswgbiCHG1haWwuc3Rob25vcmVob3RlbHJlc29y +dC5jb22CIGFzaGNoc3ZyLnN0aG9ub3JlaG90ZWxyZXNvcnQuY29tgiRBdXRvRGlz +Y292ZXIuc3Rob25vcmVob3RlbHJlc29ydC5jb22CHEF1dG9EaXNjb3Zlci5ob3Rl +bHJlc29ydC5jb22CCEFTSENIU1ZSghdzdGhvbm9yZWhvdGVscmVzb3J0LmNvbYIP +aG90ZWxyZXNvcnQuY29tMCEGCSsGAQQBgjcUAgQUHhIAVwBlAGIAUwBlAHIAdgBl +AHIwHQYDVR0OBBYEFMAC3UR4FwAdGekbhMgnd6lMejtbMAsGA1UdDwQEAwIFoDAT +BgNVHSUEDDAKBggrBgEFBQcDATAJBgNVHRMEAjAAMIG/BgNVHQEEgbcwgbSAFGfF +6xihk+gJJ5TfwvtWe1UFnHLQoYGRMIGOMYGLMIGIBgNVBAMegYAATQBpAGMAcgBv +AHMAbwBmAHQAIABGAG8AcgBlAGYAcgBvAG4AdAAgAFQATQBHACAASABUAFQAUABT +ACAASQBuAHMAcABlAGMAdABpAG8AbgAgAEMAZQByAHQAaQBmAGkAYwBhAHQAaQBv +AG4AIABBAHUAdABoAG8AcgBpAHQAeYIIcKhXEmBXr0IwDQYJKoZIhvcNAQEFBQAD +ggEBABlSxyCMr3+ANr+WmPSjyN5YCJBgnS0IFCwJAzIYP87bcTye/U8eQ2+E6PqG +Q7Huj7nfHEw9qnGo+HNyPp1ad3KORzXDb54c6xEoi+DeuPzYHPbn4c3hlH49I0aQ +eWW2w4RslSWpLvO6Y7Lboyz2/Thk/s2kd4RHxkkWpH2ltPqJuYYg3X6oM5+gIFHJ +WGnh+ojZ5clKvS5yXh3Wkj78M6sb32KfcBk0Hx6NkCYPt60ODYmWtvqwtw6r73u5 +TnTYWRNvo2svX69TriL+CkHY9O1Hkwf2It5zHl3gNiKTJVaak8AuEz/CKWZneovt +yYLwhUhg3PX5Co1VKYE+9TxloiE= +-----END CERTIFICATE-----` + +func TestParseUniqueID(t *testing.T) { + b, _ := pem.Decode([]byte(uniqueIDPEM)) + if b == nil { + t.Fatalf("couldn't decode test certificate") + } + cert, err := ParseCertificate(b.Bytes) + if err != nil { + t.Fatalf("ParseCertificate to failed to parse certificate with unique identifier id: %s", err) + } + if len(cert.Extensions) != 7 { + t.Fatalf("unexpected number of extensions (probably because the extension section was not parsed): got %d, want 7", len(cert.Extensions)) + } +} diff --git a/src/net/dial_test.go b/src/net/dial_test.go index 723038c7a2..8f6dd714db 100644 --- a/src/net/dial_test.go +++ b/src/net/dial_test.go @@ -751,6 +751,12 @@ func TestDialerKeepAlive(t *testing.T) { func TestDialCancel(t *testing.T) { mustHaveExternalNetwork(t) + if strings.HasPrefix(testenv.Builder(), "darwin-arm64") { + // The darwin-arm64 machines run in an environment that's not + // compatible with this test. + t.Skipf("builder %q gives no route to host for 198.18.0.0", testenv.Builder()) + } + blackholeIPPort := JoinHostPort(slowDst4, "1234") if !supportsIPv4() { blackholeIPPort = JoinHostPort(slowDst6, "1234") diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go index 4f85ff55d8..1c0c0f6987 100644 --- a/src/net/http/httptest/server.go +++ b/src/net/http/httptest/server.go @@ -317,21 +317,17 @@ func (s *Server) wrap() { s.mu.Lock() defer s.mu.Unlock() - // Keep Close from returning until the user's ConnState hook - // (if any) finishes. Without this, the call to forgetConn - // below might send the count to 0 before we run the hook. - s.wg.Add(1) - defer s.wg.Done() - switch cs { case http.StateNew: - s.wg.Add(1) if _, exists := s.conns[c]; exists { panic("invalid state transition") } if s.conns == nil { s.conns = make(map[net.Conn]http.ConnState) } + // Add c to the set of tracked conns and increment it to the + // waitgroup. + s.wg.Add(1) s.conns[c] = cs if s.closed { // Probably just a socket-late-binding dial from @@ -358,7 +354,14 @@ func (s *Server) wrap() { s.closeConn(c) } case http.StateHijacked, http.StateClosed: - s.forgetConn(c) + // Remove c from the set of tracked conns and decrement it from the + // waitgroup, unless it was previously removed. + if _, ok := s.conns[c]; ok { + delete(s.conns, c) + // Keep Close from returning until the user's ConnState hook + // (if any) finishes. + defer s.wg.Done() + } } if oldHook != nil { oldHook(c, cs) @@ -378,13 +381,3 @@ func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) { done <- struct{}{} } } - -// forgetConn removes c from the set of tracked conns and decrements it from the -// waitgroup, unless it was previously removed. -// s.mu must be held. -func (s *Server) forgetConn(c net.Conn) { - if _, ok := s.conns[c]; ok { - delete(s.conns, c) - s.wg.Done() - } -} diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go index 39568b358c..5313f65456 100644 --- a/src/net/http/httptest/server_test.go +++ b/src/net/http/httptest/server_test.go @@ -9,6 +9,7 @@ import ( "io" "net" "net/http" + "sync" "testing" ) @@ -203,6 +204,59 @@ func TestServerZeroValueClose(t *testing.T) { ts.Close() // tests that it doesn't panic } +// Issue 51799: test hijacking a connection and then closing it +// concurrently with closing the server. +func TestCloseHijackedConnection(t *testing.T) { + hijacked := make(chan net.Conn) + ts := NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer close(hijacked) + hj, ok := w.(http.Hijacker) + if !ok { + t.Fatal("failed to hijack") + } + c, _, err := hj.Hijack() + if err != nil { + t.Fatal(err) + } + hijacked <- c + })) + + var wg sync.WaitGroup + wg.Add(1) + go func() { + defer wg.Done() + req, err := http.NewRequest("GET", ts.URL, nil) + if err != nil { + t.Log(err) + } + // Use a client not associated with the Server. + var c http.Client + resp, err := c.Do(req) + if err != nil { + t.Log(err) + return + } + resp.Body.Close() + }() + + wg.Add(1) + conn := <-hijacked + go func(conn net.Conn) { + defer wg.Done() + // Close the connection and then inform the Server that + // we closed it. + conn.Close() + ts.Config.ConnState(conn, http.StateClosed) + }(conn) + + wg.Add(1) + go func() { + defer wg.Done() + ts.Close() + }() + wg.Wait() +} + func TestTLSServerWithHTTP2(t *testing.T) { modes := []struct { name string diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 6096760b50..33c3f2ee65 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -1151,6 +1151,7 @@ func unminitSignals() { // blockableSig reports whether sig may be blocked by the signal mask. // We never want to block the signals marked _SigUnblock; // these are the synchronous signals that turn into a Go panic. +// We never want to block the preemption signal if it is being used. // In a Go program--not a c-archive/c-shared--we never want to block // the signals marked _SigKill or _SigThrow, as otherwise it's possible // for all running threads to block them and delay their delivery until @@ -1161,6 +1162,9 @@ func blockableSig(sig uint32) bool { if flags&_SigUnblock != 0 { return false } + if sig == sigPreempt && preemptMSupported && debug.asyncpreemptoff == 0 { + return false + } if isarchive || islibrary { return true } diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go index c569e0faa2..4ded218d2d 100644 --- a/src/sync/waitgroup_test.go +++ b/src/sync/waitgroup_test.go @@ -5,8 +5,6 @@ package sync_test import ( - "internal/race" - "runtime" . "sync" "sync/atomic" "testing" @@ -48,12 +46,6 @@ func TestWaitGroup(t *testing.T) { } } -func knownRacy(t *testing.T) { - if race.Enabled { - t.Skip("skipping known-racy test under the race detector") - } -} - func TestWaitGroupMisuse(t *testing.T) { defer func() { err := recover() @@ -68,124 +60,6 @@ func TestWaitGroupMisuse(t *testing.T) { t.Fatal("Should panic") } -// pollUntilEqual blocks until v, loaded atomically, is -// equal to the target. -func pollUntilEqual(v *uint32, target uint32) { - for { - for i := 0; i < 1e3; i++ { - if atomic.LoadUint32(v) == target { - return - } - } - // yield to avoid deadlock with the garbage collector - // see issue #20072 - runtime.Gosched() - } -} - -func TestWaitGroupMisuse2(t *testing.T) { - knownRacy(t) - if runtime.NumCPU() <= 4 { - t.Skip("NumCPU<=4, skipping: this test requires parallelism") - } - defer func() { - err := recover() - if err != "sync: negative WaitGroup counter" && - err != "sync: WaitGroup misuse: Add called concurrently with Wait" && - err != "sync: WaitGroup is reused before previous Wait has returned" { - t.Fatalf("Unexpected panic: %#v", err) - } - }() - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - done := make(chan interface{}, 2) - // The detection is opportunistic, so we want it to panic - // at least in one run out of a million. - for i := 0; i < 1e6; i++ { - var wg WaitGroup - var here uint32 - wg.Add(1) - go func() { - defer func() { - done <- recover() - }() - atomic.AddUint32(&here, 1) - pollUntilEqual(&here, 3) - wg.Wait() - }() - go func() { - defer func() { - done <- recover() - }() - atomic.AddUint32(&here, 1) - pollUntilEqual(&here, 3) - wg.Add(1) // This is the bad guy. - wg.Done() - }() - atomic.AddUint32(&here, 1) - pollUntilEqual(&here, 3) - wg.Done() - for j := 0; j < 2; j++ { - if err := <-done; err != nil { - panic(err) - } - } - } - t.Fatal("Should panic") -} - -func TestWaitGroupMisuse3(t *testing.T) { - knownRacy(t) - if runtime.NumCPU() <= 1 { - t.Skip("NumCPU==1, skipping: this test requires parallelism") - } - defer func() { - err := recover() - if err != "sync: negative WaitGroup counter" && - err != "sync: WaitGroup misuse: Add called concurrently with Wait" && - err != "sync: WaitGroup is reused before previous Wait has returned" { - t.Fatalf("Unexpected panic: %#v", err) - } - }() - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - done := make(chan interface{}, 3) - // The detection is opportunistically, so we want it to panic - // at least in one run out of a million. - for i := 0; i < 1e6; i++ { - var wg WaitGroup - wg.Add(1) - go func() { - defer func() { - done <- recover() - }() - wg.Done() - }() - go func() { - defer func() { - done <- recover() - }() - wg.Wait() - // Start reusing the wg before waiting for the Wait below to return. - wg.Add(1) - go func() { - wg.Done() - }() - wg.Wait() - }() - go func() { - defer func() { - done <- recover() - }() - wg.Wait() - }() - for j := 0; j < 3; j++ { - if err := <-done; err != nil { - panic(err) - } - } - } - t.Fatal("Should panic") -} - func TestWaitGroupRace(t *testing.T) { // Run this test for about 1ms. for i := 0; i < 1000; i++ { diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index 85b59ad00d..d62b80b017 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -275,12 +275,14 @@ func TestGroupCleanup(t *testing.T) { t.Fatalf("Cmd failed with err %v, output: %s", err, out) } strOut := strings.TrimSpace(string(out)) + t.Logf("id: %s", strOut) + expected := "uid=0(root) gid=0(root)" // Just check prefix because some distros reportedly output a // context parameter; see https://golang.org/issue/16224. // Alpine does not output groups; see https://golang.org/issue/19938. if !strings.HasPrefix(strOut, expected) { - t.Errorf("id command output: %q, expected prefix: %q", strOut, expected) + t.Errorf("expected prefix: %q", expected) } } @@ -309,23 +311,14 @@ func TestGroupCleanupUserNamespace(t *testing.T) { t.Fatalf("Cmd failed with err %v, output: %s", err, out) } strOut := strings.TrimSpace(string(out)) + t.Logf("id: %s", strOut) - // Strings we've seen in the wild. - expected := []string{ - "uid=0(root) gid=0(root) groups=0(root)", - "uid=0(root) gid=0(root) groups=0(root),65534(nobody)", - "uid=0(root) gid=0(root) groups=0(root),65534(nogroup)", - "uid=0(root) gid=0(root) groups=0(root),65534", - "uid=0(root) gid=0(root) groups=0(root),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody)", // Alpine; see https://golang.org/issue/19938 - "uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023", // CentOS with SELinux context, see https://golang.org/issue/34547 - "uid=0(root) gid=0(root) groups=0(root),65534(nobody) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023", // Fedora with SElinux context, see https://golang.org/issue/46752 - } - for _, e := range expected { - if strOut == e { - return - } + // As in TestGroupCleanup, just check prefix. + // The actual groups and contexts seem to vary from one distro to the next. + expected := "uid=0(root) gid=0(root) groups=0(root)" + if !strings.HasPrefix(strOut, expected) { + t.Errorf("expected prefix: %q", expected) } - t.Errorf("id command output: %q, expected one of %q", strOut, expected) } // TestUnshareHelperProcess isn't a real test. It's used as a helper process diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index dfce3d0a4b..3387f3bdc2 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -109,7 +109,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { gid = Getgid() } - if uint32(gid) == st.Gid || isGroupMember(gid) { + if uint32(gid) == st.Gid || isGroupMember(int(st.Gid)) { fmode = (st.Mode >> 3) & 7 } else { fmode = st.Mode & 7 |