From: Ian Lance Taylor Date: Mon, 8 Oct 2018 14:21:30 +0000 (+0000) Subject: libgo: update to Go 1.11.1 release X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3cbb7cbb096134746588d08a469778b11ae6ac73;p=gcc.git libgo: update to Go 1.11.1 release Reviewed-on: https://go-review.googlesource.com/c/140277 From-SVN: r264932 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 2c7a860c8a8..6e783c96d6d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d0739c13ca3686df1f8d0fae7c6c5caaed058503 +a9da4d34a2f878a5058f7e7d2beef52aa62471a1 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/MERGE b/libgo/MERGE index 9b907987def..b2803e871c5 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -41e62b8c49d21659b48a95216e3062032285250f +26957168c4c0cdcc7ca4f0b19d0eb19474d224ac The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/VERSION b/libgo/VERSION index f3220fb7592..0ff4ff61d19 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.11 +go1.11.1 diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go index ebbd154f3e6..1060e779c1b 100644 --- a/libgo/go/cmd/go/alldocs.go +++ b/libgo/go/cmd/go/alldocs.go @@ -1449,6 +1449,12 @@ // The directory where the go command will write // temporary source files, packages, and binaries. // +// Each entry in the GOFLAGS list must be a standalone flag. +// Because the entries are space-separated, flag values must +// not contain spaces. In some cases, you can provide multiple flag +// values instead: for example, to set '-ldflags=-s -w' +// you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'. +// // Environment variables for use with cgo: // // CC diff --git a/libgo/go/cmd/go/internal/help/helpdoc.go b/libgo/go/cmd/go/internal/help/helpdoc.go index aff4ce12f6c..e2c4e61615b 100644 --- a/libgo/go/cmd/go/internal/help/helpdoc.go +++ b/libgo/go/cmd/go/internal/help/helpdoc.go @@ -507,6 +507,12 @@ General-purpose environment variables: The directory where the go command will write temporary source files, packages, and binaries. +Each entry in the GOFLAGS list must be a standalone flag. +Because the entries are space-separated, flag values must +not contain spaces. In some cases, you can provide multiple flag +values instead: for example, to set '-ldflags=-s -w' +you can use 'GOFLAGS=-ldflags=-s -ldflags=-w'. + Environment variables for use with cgo: CC diff --git a/libgo/go/cmd/go/internal/work/exec.go b/libgo/go/cmd/go/internal/work/exec.go index 84870e52ccc..8aba293dd34 100644 --- a/libgo/go/cmd/go/internal/work/exec.go +++ b/libgo/go/cmd/go/internal/work/exec.go @@ -224,7 +224,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { if len(p.SFiles) > 0 { fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags) } - fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc + // GO386, GOARM, GOMIPS, etc. + baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le") + fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch))) // TODO(rsc): Convince compiler team not to add more magic environment variables, // or perhaps restrict the environment variables passed to subprocesses. diff --git a/libgo/go/cmd/go/internal/work/security.go b/libgo/go/cmd/go/internal/work/security.go index d5d126123a4..2132c5f3e15 100644 --- a/libgo/go/cmd/go/internal/work/security.go +++ b/libgo/go/cmd/go/internal/work/security.go @@ -170,6 +170,7 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-Wl,-e[=,][a-zA-Z0-9]*`), re(`-Wl,--enable-new-dtags`), re(`-Wl,--end-group`), + re(`-Wl,--(no-)?export-dynamic`), re(`-Wl,-framework,[^,@\-][^,]+`), re(`-Wl,-headerpad_max_install_names`), re(`-Wl,--no-undefined`), diff --git a/libgo/go/cmd/go/script_test.go b/libgo/go/cmd/go/script_test.go index 9e958e0c635..6399faac0f4 100644 --- a/libgo/go/cmd/go/script_test.go +++ b/libgo/go/cmd/go/script_test.go @@ -635,6 +635,9 @@ func scriptMatch(ts *testScript, neg bool, args []string, text, name string) { text = string(data) } + // Matching against workdir would be misleading. + text = strings.Replace(text, ts.workdir, "$WORK", -1) + if neg { if re.MatchString(text) { if isGrep { diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 210db4c1d0e..0b75778a038 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -894,8 +894,8 @@ func validHostname(host string) bool { if c == '-' && j != 0 { continue } - if c == '_' { - // _ is not a valid character in hostnames, but it's commonly + if c == '_' || c == ':' { + // Not valid characters in hostnames, but commonly // found in deployments outside the WebPKI. continue } diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 76841458396..0e24d3b5da3 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -1881,6 +1881,7 @@ func TestValidHostname(t *testing.T) { {"foo.*.example.com", false}, {"exa_mple.com", true}, {"foo,bar", false}, + {"project-dev:us-central1:main", true}, } for _, tt := range tests { if got := validHostname(tt.host); got != tt.want { diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 0b29249218a..7d235087e60 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -672,6 +672,7 @@ func (d *decodeState) object(v reflect.Value) error { } var mapElem reflect.Value + originalErrorContext := d.errorContext for { // Read opening " of string key or closing }. @@ -832,8 +833,7 @@ func (d *decodeState) object(v reflect.Value) error { return errPhase } - d.errorContext.Struct = "" - d.errorContext.Field = "" + d.errorContext = originalErrorContext } return nil } @@ -991,7 +991,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) } - return &UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())} + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) case reflect.Interface: n, err := d.convertNumber(s) if err != nil { diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index ab83b81bb39..5746ddf9861 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -371,6 +371,10 @@ func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { return (*intWithMarshalText)(b).UnmarshalText(data) } +type mapStringToStringData struct { + Data map[string]string `json:"data"` +} + type unmarshalTest struct { in string ptr interface{} @@ -401,6 +405,7 @@ var unmarshalTests = []unmarshalTest{ {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, {in: "null", ptr: new(interface{}), out: nil}, {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}}, + {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, @@ -866,6 +871,18 @@ var unmarshalTests = []unmarshalTest{ err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, + // issue 26444 + // UnmarshalTypeError without field & struct values + { + in: `{"data":{"test1": "bob", "test2": 123}}`, + ptr: new(mapStringToStringData), + err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, + }, + { + in: `{"data":{"test1": 123, "test2": "bob"}}`, + ptr: new(mapStringToStringData), + err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, + }, } func TestMarshal(t *testing.T) { diff --git a/libgo/go/go/types/api_test.go b/libgo/go/go/types/api_test.go index d4ed400ea68..35050e1b9eb 100644 --- a/libgo/go/go/types/api_test.go +++ b/libgo/go/go/types/api_test.go @@ -262,6 +262,8 @@ func TestTypesInfo(t *testing.T) { {`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`}, {`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`}, {`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`}, + {`package x3; var x = panic("");`, `panic`, `func(interface{})`}, + {`package x4; func _() { panic("") }`, `panic`, `func(interface{})`}, } for _, test := range tests { diff --git a/libgo/go/go/types/builtins.go b/libgo/go/go/types/builtins.go index 05e032423ca..d3f0c4d40df 100644 --- a/libgo/go/go/types/builtins.go +++ b/libgo/go/go/types/builtins.go @@ -476,7 +476,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // panic(x) // record panic call if inside a function with result parameters // (for use in Checker.isTerminating) - if check.sig.results.Len() > 0 { + if check.sig != nil && check.sig.results.Len() > 0 { // function has result parameters p := check.isPanic if p == nil { diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index 6ec2f44b7cb..3b0293025d9 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -27,6 +27,20 @@ import ( "golang_org/x/net/dns/dnsmessage" ) +var ( + errLameReferral = errors.New("lame referral") + errCannotUnmarshalDNSMessage = errors.New("cannot unmarshal DNS message") + errCannotMarshalDNSMessage = errors.New("cannot marshal DNS message") + errServerMisbehaving = errors.New("server misbehaving") + errInvalidDNSResponse = errors.New("invalid DNS response") + errNoAnswerFromDNSServer = errors.New("no answer from DNS server") + + // errServerTemporarlyMisbehaving is like errServerMisbehaving, except + // that when it gets translated to a DNSError, the IsTemporary field + // gets set to true. + errServerTemporarlyMisbehaving = errors.New("server misbehaving") +) + func newRequest(q dnsmessage.Question) (id uint16, udpReq, tcpReq []byte, err error) { id = uint16(rand.Int()) ^ uint16(time.Now().UnixNano()) b := dnsmessage.NewBuilder(make([]byte, 2, 514), dnsmessage.Header{ID: id, RecursionDesired: true}) @@ -105,14 +119,14 @@ func dnsStreamRoundTrip(c Conn, id uint16, query dnsmessage.Question, b []byte) var p dnsmessage.Parser h, err := p.Start(b[:n]) if err != nil { - return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message") + return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage } q, err := p.Question() if err != nil { - return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot unmarshal DNS message") + return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotUnmarshalDNSMessage } if !checkResponse(id, query, h, q) { - return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response") + return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse } return p, h, nil } @@ -122,7 +136,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que q.Class = dnsmessage.ClassINET id, udpReq, tcpReq, err := newRequest(q) if err != nil { - return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("cannot marshal DNS message") + return dnsmessage.Parser{}, dnsmessage.Header{}, errCannotMarshalDNSMessage } for _, network := range []string{"udp", "tcp"} { ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout)) @@ -147,31 +161,31 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que return dnsmessage.Parser{}, dnsmessage.Header{}, mapErr(err) } if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone { - return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("invalid DNS response") + return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse } if h.Truncated { // see RFC 5966 continue } return p, h, nil } - return dnsmessage.Parser{}, dnsmessage.Header{}, errors.New("no answer from DNS server") + return dnsmessage.Parser{}, dnsmessage.Header{}, errNoAnswerFromDNSServer } // checkHeader performs basic sanity checks on the header. func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string) error { + if h.RCode == dnsmessage.RCodeNameError { + return errNoSuchHost + } + _, err := p.AnswerHeader() if err != nil && err != dnsmessage.ErrSectionDone { - return &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } + return errCannotUnmarshalDNSMessage } // libresolv continues to the next server when it receives // an invalid referral response. See golang.org/issue/15434. if h.RCode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone { - return &DNSError{Err: "lame referral", Name: name, Server: server} + return errLameReferral } if h.RCode != dnsmessage.RCodeSuccess && h.RCode != dnsmessage.RCodeNameError { @@ -180,11 +194,10 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header, name, server string) // a name error and we didn't get success, // the server is behaving incorrectly or // having temporary trouble. - err := &DNSError{Err: "server misbehaving", Name: name, Server: server} if h.RCode == dnsmessage.RCodeServerFailure { - err.IsTemporary = true + return errServerTemporarlyMisbehaving } - return err + return errServerMisbehaving } return nil @@ -194,28 +207,16 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type, name, server stri for { h, err := p.AnswerHeader() if err == dnsmessage.ErrSectionDone { - return &DNSError{ - Err: errNoSuchHost.Error(), - Name: name, - Server: server, - } + return errNoSuchHost } if err != nil { - return &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } + return errCannotUnmarshalDNSMessage } if h.Type == qtype { return nil } if err := p.SkipAnswer(); err != nil { - return &DNSError{ - Err: "cannot unmarshal DNS message", - Name: name, - Server: server, - } + return errCannotUnmarshalDNSMessage } } } @@ -229,7 +230,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, n, err := dnsmessage.NewName(name) if err != nil { - return dnsmessage.Parser{}, "", errors.New("cannot marshal DNS message") + return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage } q := dnsmessage.Question{ Name: n, @@ -243,38 +244,62 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, p, h, err := r.exchange(ctx, server, q, cfg.timeout) if err != nil { - lastErr = &DNSError{ + dnsErr := &DNSError{ Err: err.Error(), Name: name, Server: server, } if nerr, ok := err.(Error); ok && nerr.Timeout() { - lastErr.(*DNSError).IsTimeout = true + dnsErr.IsTimeout = true } // Set IsTemporary for socket-level errors. Note that this flag // may also be used to indicate a SERVFAIL response. if _, ok := err.(*OpError); ok { - lastErr.(*DNSError).IsTemporary = true + dnsErr.IsTemporary = true } + lastErr = dnsErr continue } - // The name does not exist, so trying another server won't help. - // - // TODO: indicate this in a more obvious way, such as a field on DNSError? - if h.RCode == dnsmessage.RCodeNameError { - return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server} - } - - lastErr = checkHeader(&p, h, name, server) - if lastErr != nil { + if err := checkHeader(&p, h, name, server); err != nil { + dnsErr := &DNSError{ + Err: err.Error(), + Name: name, + Server: server, + } + if err == errServerTemporarlyMisbehaving { + dnsErr.IsTemporary = true + } + if err == errNoSuchHost { + // The name does not exist, so trying + // another server won't help. + // + // TODO: indicate this in a more + // obvious way, such as a field on + // DNSError? + return p, server, dnsErr + } + lastErr = dnsErr continue } - lastErr = skipToAnswer(&p, qtype, name, server) - if lastErr == nil { + err = skipToAnswer(&p, qtype, name, server) + if err == nil { return p, server, nil } + lastErr = &DNSError{ + Err: err.Error(), + Name: name, + Server: server, + } + if err == errNoSuchHost { + // The name does not exist, so trying another + // server won't help. + // + // TODO: indicate this in a more obvious way, + // such as a field on DNSError? + return p, server, lastErr + } } } return dnsmessage.Parser{}, "", lastErr diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go index f1bb09d161e..8992480b6ac 100644 --- a/libgo/go/net/dnsclient_unix_test.go +++ b/libgo/go/net/dnsclient_unix_test.go @@ -1427,28 +1427,35 @@ func TestDNSGoroutineRace(t *testing.T) { } } +func lookupWithFake(fake fakeDNSServer, name string, typ dnsmessage.Type) error { + r := Resolver{PreferGo: true, Dial: fake.DialContext} + + resolvConf.mu.RLock() + conf := resolvConf.dnsConfig + resolvConf.mu.RUnlock() + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + _, _, err := r.tryOneName(ctx, conf, name, typ) + return err +} + // Issue 8434: verify that Temporary returns true on an error when rcode // is SERVFAIL func TestIssue8434(t *testing.T) { - msg := dnsmessage.Message{ - Header: dnsmessage.Header{ - RCode: dnsmessage.RCodeServerFailure, + err := lookupWithFake(fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + return dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.ID, + Response: true, + RCode: dnsmessage.RCodeServerFailure, + }, + Questions: q.Questions, + }, nil }, - } - b, err := msg.Pack() - if err != nil { - t.Fatal("Pack failed:", err) - } - var p dnsmessage.Parser - h, err := p.Start(b) - if err != nil { - t.Fatal("Start failed:", err) - } - if err := p.SkipAllQuestions(); err != nil { - t.Fatal("SkipAllQuestions failed:", err) - } - - err = checkHeader(&p, h, "golang.org", "foo:53") + }, "golang.org.", dnsmessage.TypeALL) if err == nil { t.Fatal("expected an error") } @@ -1464,50 +1471,76 @@ func TestIssue8434(t *testing.T) { } } -// Issue 12778: verify that NXDOMAIN without RA bit errors as -// "no such host" and not "server misbehaving" +// TestNoSuchHost verifies that tryOneName works correctly when the domain does +// not exist. +// +// Issue 12778: verify that NXDOMAIN without RA bit errors as "no such host" +// and not "server misbehaving" // // Issue 25336: verify that NXDOMAIN errors fail fast. -func TestIssue12778(t *testing.T) { - lookups := 0 - fake := fakeDNSServer{ - rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { - lookups++ - return dnsmessage.Message{ - Header: dnsmessage.Header{ - ID: q.ID, - Response: true, - RCode: dnsmessage.RCodeNameError, - RecursionAvailable: false, - }, - Questions: q.Questions, - }, nil +// +// Issue 27525: verify that empty answers fail fast. +func TestNoSuchHost(t *testing.T) { + tests := []struct { + name string + f func(string, string, dnsmessage.Message, time.Time) (dnsmessage.Message, error) + }{ + { + "NXDOMAIN", + func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + return dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.ID, + Response: true, + RCode: dnsmessage.RCodeNameError, + RecursionAvailable: false, + }, + Questions: q.Questions, + }, nil + }, + }, + { + "no answers", + func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + return dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + RecursionAvailable: false, + Authoritative: true, + }, + Questions: q.Questions, + }, nil + }, }, } - r := Resolver{PreferGo: true, Dial: fake.DialContext} - - resolvConf.mu.RLock() - conf := resolvConf.dnsConfig - resolvConf.mu.RUnlock() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - _, _, err := r.tryOneName(ctx, conf, ".", dnsmessage.TypeALL) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + lookups := 0 + err := lookupWithFake(fakeDNSServer{ + rh: func(n, s string, q dnsmessage.Message, d time.Time) (dnsmessage.Message, error) { + lookups++ + return test.f(n, s, q, d) + }, + }, ".", dnsmessage.TypeALL) - if lookups != 1 { - t.Errorf("got %d lookups, wanted 1", lookups) - } + if lookups != 1 { + t.Errorf("got %d lookups, wanted 1", lookups) + } - if err == nil { - t.Fatal("expected an error") - } - de, ok := err.(*DNSError) - if !ok { - t.Fatalf("err = %#v; wanted a *net.DNSError", err) - } - if de.Err != errNoSuchHost.Error() { - t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error()) + if err == nil { + t.Fatal("expected an error") + } + de, ok := err.(*DNSError) + if !ok { + t.Fatalf("err = %#v; wanted a *net.DNSError", err) + } + if de.Err != errNoSuchHost.Error() { + t.Fatalf("Err = %#v; wanted %q", de.Err, errNoSuchHost.Error()) + } + }) } } @@ -1535,3 +1568,56 @@ func TestDNSDialTCP(t *testing.T) { t.Fatal("exhange failed:", err) } } + +// Issue 27763: verify that two strings in one TXT record are concatenated. +func TestTXTRecordTwoStrings(t *testing.T) { + fake := fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + }, + Questions: q.Questions, + Answers: []dnsmessage.Resource{ + { + Header: dnsmessage.ResourceHeader{ + Name: q.Questions[0].Name, + Type: dnsmessage.TypeA, + Class: dnsmessage.ClassINET, + }, + Body: &dnsmessage.TXTResource{ + TXT: []string{"string1 ", "string2"}, + }, + }, + { + Header: dnsmessage.ResourceHeader{ + Name: q.Questions[0].Name, + Type: dnsmessage.TypeA, + Class: dnsmessage.ClassINET, + }, + Body: &dnsmessage.TXTResource{ + TXT: []string{"onestring"}, + }, + }, + }, + } + return r, nil + }, + } + r := Resolver{PreferGo: true, Dial: fake.DialContext} + txt, err := r.lookupTXT(context.Background(), "golang.org") + if err != nil { + t.Fatal("LookupTXT failed:", err) + } + if want := 2; len(txt) != want { + t.Fatalf("len(txt), got %d, want %d", len(txt), want) + } + if want := "string1 string2"; txt[0] != want { + t.Errorf("txt[0], got %q, want %q", txt[0], want) + } + if want := "onestring"; txt[1] != want { + t.Errorf("txt[1], got %q, want %q", txt[1], want) + } +} diff --git a/libgo/go/net/http/roundtrip_js.go b/libgo/go/net/http/roundtrip_js.go index 16b7b891c86..38e4f5573e6 100644 --- a/libgo/go/net/http/roundtrip_js.go +++ b/libgo/go/net/http/roundtrip_js.go @@ -116,7 +116,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { b := result.Get("body") var body io.ReadCloser - if b != js.Undefined() { + // The body is undefined when the browser does not support streaming response bodies (Firefox), + // and null in certain error cases, i.e. when the request is blocked because of CORS settings. + if b != js.Undefined() && b != js.Null() { body = &streamReader{stream: b.Call("getReader")} } else { // Fall back to using ArrayBuffer diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go index 76d6ae30f78..39e8b720076 100644 --- a/libgo/go/net/lookup_unix.go +++ b/libgo/go/net/lookup_unix.go @@ -299,11 +299,21 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) Server: server, } } + // Multiple strings in one TXT record need to be + // concatenated without separator to be consistent + // with previous Go resolver. + n := 0 + for _, s := range txt.TXT { + n += len(s) + } + txtJoin := make([]byte, 0, n) + for _, s := range txt.TXT { + txtJoin = append(txtJoin, s...) + } if len(txts) == 0 { - txts = txt.TXT - } else { - txts = append(txts, txt.TXT...) + txts = make([]string, 0, 1) } + txts = append(txts, string(txtJoin)) } return txts, nil } diff --git a/libgo/go/net/splice_test.go b/libgo/go/net/splice_test.go index 40ed19b8fa8..3be1c7e5de1 100644 --- a/libgo/go/net/splice_test.go +++ b/libgo/go/net/splice_test.go @@ -124,6 +124,7 @@ func testSpliceBig(t *testing.T) { func testSpliceHonorsLimitedReader(t *testing.T) { t.Run("stopsAfterN", testSpliceStopsAfterN) t.Run("updatesN", testSpliceUpdatesN) + t.Run("readerAtLimit", testSpliceReaderAtLimit) } func testSpliceStopsAfterN(t *testing.T) { @@ -210,7 +211,7 @@ func testSpliceUpdatesN(t *testing.T) { } } -func testSpliceReaderAtEOF(t *testing.T) { +func testSpliceReaderAtLimit(t *testing.T) { clientUp, serverUp, err := spliceTestSocketPair("tcp") if err != nil { t.Fatal(err) @@ -224,22 +225,64 @@ func testSpliceReaderAtEOF(t *testing.T) { defer clientDown.Close() defer serverDown.Close() - serverUp.Close() - _, err, handled := splice(serverDown.(*TCPConn).fd, serverUp) + lr := &io.LimitedReader{ + N: 0, + R: serverUp, + } + _, err, handled := splice(serverDown.(*TCPConn).fd, lr) if !handled { if serr, ok := err.(*os.SyscallError); ok && serr.Syscall == "pipe2" && serr.Err == syscall.ENOSYS { t.Skip("pipe2 not supported") } - t.Errorf("closed connection: got err = %v, handled = %t, want handled = true", err, handled) + t.Errorf("exhausted LimitedReader: got err = %v, handled = %t, want handled = true", err, handled) } - lr := &io.LimitedReader{ - N: 0, - R: serverUp, +} + +func testSpliceReaderAtEOF(t *testing.T) { + clientUp, serverUp, err := spliceTestSocketPair("tcp") + if err != nil { + t.Fatal(err) } - _, err, handled = splice(serverDown.(*TCPConn).fd, lr) - if !handled { - t.Errorf("exhausted LimitedReader: got err = %v, handled = %t, want handled = true", err, handled) + defer clientUp.Close() + clientDown, serverDown, err := spliceTestSocketPair("tcp") + if err != nil { + t.Fatal(err) + } + defer clientDown.Close() + + serverUp.Close() + + // We'd like to call net.splice here and check the handled return + // value, but we disable splice on old Linux kernels. + // + // In that case, poll.Splice and net.splice return a non-nil error + // and handled == false. We'd ideally like to see handled == true + // because the source reader is at EOF, but if we're running on an old + // kernel, and splice is disabled, we won't see EOF from net.splice, + // because we won't touch the reader at all. + // + // Trying to untangle the errors from net.splice and match them + // against the errors created by the poll package would be brittle, + // so this is a higher level test. + // + // The following ReadFrom should return immediately, regardless of + // whether splice is disabled or not. The other side should then + // get a goodbye signal. Test for the goodbye signal. + msg := "bye" + go func() { + serverDown.(*TCPConn).ReadFrom(serverUp) + io.WriteString(serverDown, msg) + serverDown.Close() + }() + + buf := make([]byte, 3) + _, err = io.ReadFull(clientDown, buf) + if err != nil { + t.Errorf("clientDown: %v", err) + } + if string(buf) != msg { + t.Errorf("clientDown got %q, want %q", buf, msg) } } diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index eb893e965d1..472988fe856 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -5864,7 +5864,7 @@ func clobber() { type funcLayoutTest struct { rcvr, t Type size, argsize, retOffset uintptr - stack []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized) + stack []byte // pointer bitmap: 1 is pointer, 0 is scalar gc []byte } @@ -5886,7 +5886,7 @@ func init() { 6 * PtrSize, 4 * PtrSize, 4 * PtrSize, - []byte{1, 0, 1}, + []byte{1, 0, 1, 0, 1}, []byte{1, 0, 1, 0, 1}, }) diff --git a/libgo/go/reflect/makefunc_ffi.go b/libgo/go/reflect/makefunc_ffi.go index 2acf7bb887a..9d9cbdec25d 100644 --- a/libgo/go/reflect/makefunc_ffi.go +++ b/libgo/go/reflect/makefunc_ffi.go @@ -33,7 +33,7 @@ func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc ap := params for _, rt := range ftyp.in { p := unsafe_New(rt) - memmove(p, *(*unsafe.Pointer)(ap), rt.size) + typedmemmove(rt, p, *(*unsafe.Pointer)(ap)) v := Value{rt, p, flag(rt.Kind()) | flagIndir} in = append(in, v) ap = (unsafe.Pointer)(uintptr(ap) + ptrSize) @@ -59,7 +59,7 @@ func FFICallbackGo(results unsafe.Pointer, params unsafe.Pointer, impl *makeFunc if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { *(*unsafe.Pointer)(addr) = v.ptr } else { - memmove(addr, v.ptr, typ.size) + typedmemmove(typ, addr, v.ptr) } off += typ.size } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 5ddd30d4d27..9f05744f8d1 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -323,7 +323,7 @@ var callGC bool // for testing; see TestCallMethodJump func (v Value) call(op string, in []Value) []Value { // Get function pointer, type. - t := v.typ + t := (*funcType)(unsafe.Pointer(v.typ)) var ( fn unsafe.Pointer rcvr Value @@ -472,7 +472,7 @@ func (v Value) call(op string, in []Value) []Value { // The return value rcvrtype gives the method's actual receiver type. // The return value t gives the method type signature (without the receiver). // The return value fn is a pointer to the method code. -func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn unsafe.Pointer) { +func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *rtype, t *funcType, fn unsafe.Pointer) { i := methodIndex if v.typ.Kind() == Interface { tt := (*interfaceType)(unsafe.Pointer(v.typ)) @@ -489,7 +489,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn } rcvrtype = iface.itab.typ fn = unsafe.Pointer(&iface.itab.fun[i]) - t = m.typ + t = (*funcType)(unsafe.Pointer(m.typ)) } else { rcvrtype = v.typ ms := v.typ.exportedMethods() @@ -501,7 +501,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn panic("reflect: " + op + " of unexported method") } fn = unsafe.Pointer(&m.tfn) - t = m.mtyp + t = (*funcType)(unsafe.Pointer(m.mtyp)) } return } @@ -2399,10 +2399,14 @@ func mapiternext(it unsafe.Pointer) //go:noescape func maplen(m unsafe.Pointer) int -func call(typ *rtype, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) +func call(typ *funcType, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) +// memmove copies size bytes to dst from src. No write barriers are used. +//go:noescape +func memmove(dst, src unsafe.Pointer, size uintptr) + // typedmemmove copies a value of type t to dst from src. //go:noescape func typedmemmove(t *rtype, dst, src unsafe.Pointer) @@ -2412,10 +2416,6 @@ func typedmemmove(t *rtype, dst, src unsafe.Pointer) //go:noescape func typedslicecopy(elemType *rtype, dst, src sliceHeader) int -//go:noescape -//extern memmove -func memmove(adst, asrc unsafe.Pointer, n uintptr) - // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that // the compiler cannot follow. diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go index 88a8944112b..cb369effb8c 100644 --- a/libgo/go/runtime/chan.go +++ b/libgo/go/runtime/chan.go @@ -102,7 +102,7 @@ func makechan(t *chantype, size int) *hchan { // Queue or element size is zero. c = (*hchan)(mallocgc(hchanSize, nil, true)) // Race detector uses this location for synchronization. - c.buf = unsafe.Pointer(c) + c.buf = c.raceaddr() case elem.kind&kindNoPointers != 0: // Elements do not contain pointers. // Allocate hchan and buf in one call. @@ -166,7 +166,7 @@ func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { } if raceenabled { - racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend)) + racereadpc(c.raceaddr(), callerpc, funcPC(chansend)) } // Fast path: check for failed non-blocking operation without acquiring the lock. @@ -352,8 +352,8 @@ func closechan(c *hchan) { if raceenabled { callerpc := getcallerpc() - racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan)) - racerelease(unsafe.Pointer(c)) + racewritepc(c.raceaddr(), callerpc, funcPC(closechan)) + racerelease(c.raceaddr()) } c.closed = 1 @@ -376,7 +376,7 @@ func closechan(c *hchan) { gp := sg.g gp.param = nil if raceenabled { - raceacquireg(gp, unsafe.Pointer(c)) + raceacquireg(gp, c.raceaddr()) } gp.schedlink.set(glist) glist = gp @@ -395,7 +395,7 @@ func closechan(c *hchan) { gp := sg.g gp.param = nil if raceenabled { - raceacquireg(gp, unsafe.Pointer(c)) + raceacquireg(gp, c.raceaddr()) } gp.schedlink.set(glist) glist = gp @@ -477,7 +477,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) if c.closed != 0 && c.qcount == 0 { if raceenabled { - raceacquire(unsafe.Pointer(c)) + raceacquire(c.raceaddr()) } unlock(&c.lock) if ep != nil { @@ -755,6 +755,15 @@ func (q *waitq) dequeue() *sudog { } } +func (c *hchan) raceaddr() unsafe.Pointer { + // Treat read-like and write-like operations on the channel to + // happen at this address. Avoid using the address of qcount + // or dataqsiz, because the len() and cap() builtins read + // those addresses, and we don't want them racing with + // operations like close(). + return unsafe.Pointer(&c.buf) +} + func racesync(c *hchan, sg *sudog) { racerelease(chanbuf(c, 0)) raceacquireg(sg.g, chanbuf(c, 0)) diff --git a/libgo/go/runtime/mbarrier.go b/libgo/go/runtime/mbarrier.go index 24e586551d8..48713157601 100644 --- a/libgo/go/runtime/mbarrier.go +++ b/libgo/go/runtime/mbarrier.go @@ -309,6 +309,19 @@ func typedmemclr(typ *_type, ptr unsafe.Pointer) { memclrNoHeapPointers(ptr, typ.size) } +//go:linkname reflect_typedmemclr reflect.typedmemclr +func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) { + typedmemclr(typ, ptr) +} + +//go:linkname reflect_typedmemclrpartial reflect.typedmemclrpartial +func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintptr) { + if typ.kind&kindNoPointers == 0 { + bulkBarrierPreWrite(uintptr(ptr), 0, size) + } + memclrNoHeapPointers(ptr, size) +} + // memclrHasPointers clears n bytes of typed memory starting at ptr. // The caller must ensure that the type of the object at ptr has // pointers, usually by checking typ.kind&kindNoPointers. However, ptr diff --git a/libgo/go/runtime/os_darwin.go b/libgo/go/runtime/os_darwin.go index 95976331017..235f7943f8d 100644 --- a/libgo/go/runtime/os_darwin.go +++ b/libgo/go/runtime/os_darwin.go @@ -34,6 +34,10 @@ func semacreate(mp *m) { //go:nosplit func semasleep(ns int64) int32 { + var start int64 + if ns >= 0 { + start = nanotime() + } mp := getg().m pthread_mutex_lock(&mp.mutex) for { @@ -43,8 +47,13 @@ func semasleep(ns int64) int32 { return 0 } if ns >= 0 { + spent := nanotime() - start + if spent >= ns { + pthread_mutex_unlock(&mp.mutex) + return -1 + } var t timespec - t.set_nsec(ns) + t.set_nsec(ns - spent) err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t) if err == _ETIMEDOUT { pthread_mutex_unlock(&mp.mutex) diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go index ea47e5cdc82..16a11926dda 100644 --- a/libgo/go/runtime/os_netbsd.go +++ b/libgo/go/runtime/os_netbsd.go @@ -29,15 +29,9 @@ func semacreate(mp *m) { //go:nosplit func semasleep(ns int64) int32 { _g_ := getg() - - // Compute sleep deadline. - var tsp *timespec - var ts timespec + var deadline int64 if ns >= 0 { - var nsec int32 - ts.set_sec(int64(timediv(ns, 1000000000, &nsec))) - ts.set_nsec(nsec) - tsp = &ts + deadline = nanotime() + ns } for { @@ -50,18 +44,21 @@ func semasleep(ns int64) int32 { } // Sleep until unparked by semawakeup or timeout. + var tsp *timespec + var ts timespec + if ns >= 0 { + wait := deadline - nanotime() + if wait <= 0 { + return -1 + } + var nsec int32 + ts.set_sec(timediv(wait, 1000000000, &nsec)) + ts.set_nsec(nsec) + tsp = &ts + } ret := lwp_park(_CLOCK_MONOTONIC, _TIMER_RELTIME, tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil) if ret == _ETIMEDOUT { return -1 - } else if ret == _EINTR && ns >= 0 { - // Avoid sleeping forever if we keep getting - // interrupted (for example by the profiling - // timer). It would be if tsp upon return had the - // remaining time to sleep, but this is good enough. - var nsec int32 - ns /= 2 - ts.set_sec(timediv(ns, 1000000000, &nsec)) - ts.set_nsec(nsec) } } } diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go index 39c12dae627..fb8373f53b5 100644 --- a/libgo/go/runtime/select.go +++ b/libgo/go/runtime/select.go @@ -426,7 +426,7 @@ rclose: typedmemclr(c.elemtype, cas.elem) } if raceenabled { - raceacquire(unsafe.Pointer(c)) + raceacquire(c.raceaddr()) } goto retc diff --git a/libgo/go/runtime/trace/annotation.go b/libgo/go/runtime/trace/annotation.go index 3545ef3bba5..d5a7d003fe2 100644 --- a/libgo/go/runtime/trace/annotation.go +++ b/libgo/go/runtime/trace/annotation.go @@ -24,13 +24,13 @@ type traceContextKey struct{} // If the end function is called multiple times, only the first // call is used in the latency measurement. // -// ctx, task := trace.NewTask(ctx, "awesome task") -// trace.WithRegion(ctx, prepWork) +// ctx, task := trace.NewTask(ctx, "awesomeTask") +// trace.WithRegion(ctx, "preparation", prepWork) // // preparation of the task // go func() { // continue processing the task in a separate goroutine. // defer task.End() -// trace.WithRegion(ctx, remainingWork) -// } +// trace.WithRegion(ctx, "remainingWork", remainingWork) +// }() func NewTask(pctx context.Context, taskType string) (ctx context.Context, task *Task) { pid := fromContext(pctx).id id := newID()