From 9bf54c938ab8ab79a92a5f354686e103d66f1a1a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 5 Mar 2019 20:49:21 +0000 Subject: sysinfo: add Flags to Statfs_t if not already there If there is no f_flags field in statfs_t then rename one of the f_spare fields, as happened in Linux kernel version 2.6.36. This fixes the build on CentOS 5.11. The CentOS kernel will hopefully not fill in the f_spare field, so the resulting flags will be zero. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/165417 From-SVN: r269401 --- libgo/mksysinfo.sh | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'libgo') diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh index 1273d9b..e0ae30f 100755 --- a/libgo/mksysinfo.sh +++ b/libgo/mksysinfo.sh @@ -1113,7 +1113,11 @@ grep '^const _FALLOC_' gen-sysinfo.go | # The statfs struct. # Prefer largefile variant if available. +# CentOS 5 does not have f_flags, so pull from f_spare. statfs=`grep '^type _statfs64 ' gen-sysinfo.go || true` +if ! echo "$statfs" | grep f_flags; then + statfs=`echo "$statfs" | sed -e 's/f_spare \[4+1\]\([^ ;]*\)/f_flags \1; f_spare [3+1]\1/'` +fi if test "$statfs" != ""; then grep '^type _statfs64 ' gen-sysinfo.go else -- cgit v1.1 From b211cd1b4639a0ee3be5f643bde10b1c1683bb58 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 5 Mar 2019 22:40:21 +0000 Subject: cmd/go: pass -X64 to ar on aix/ppc64 On aix/ppc64, ar tool must always have -X64 argument if it aims to create 64 bits archives. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/165317 From-SVN: r269404 --- libgo/go/cmd/go/internal/work/gccgo.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'libgo') diff --git a/libgo/go/cmd/go/internal/work/gccgo.go b/libgo/go/cmd/go/internal/work/gccgo.go index cb7d560..a0eb2d3 100644 --- a/libgo/go/cmd/go/internal/work/gccgo.go +++ b/libgo/go/cmd/go/internal/work/gccgo.go @@ -278,6 +278,13 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string return nil } + var arArgs []string + if cfg.Goos == "aix" && cfg.Goarch == "ppc64" { + // AIX puts both 32-bit and 64-bit objects in the same archive. + // Tell the AIX "ar" command to only care about 64-bit objects. + arArgs = []string{"-X64"} + } + newID := 0 readAndRemoveCgoFlags := func(archive string) (string, error) { newID++ @@ -293,11 +300,11 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string b.Showcmd("", "ar d %s _cgo_flags", newArchive) return "", nil } - err := b.run(root, root.Objdir, desc, nil, tools.ar(), "x", newArchive, "_cgo_flags") + err := b.run(root, root.Objdir, desc, nil, tools.ar(), arArgs, "x", newArchive, "_cgo_flags") if err != nil { return "", err } - err = b.run(root, ".", desc, nil, tools.ar(), "d", newArchive, "_cgo_flags") + err = b.run(root, ".", desc, nil, tools.ar(), arArgs, "d", newArchive, "_cgo_flags") if err != nil { return "", err } @@ -516,7 +523,7 @@ func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string switch buildmode { case "c-archive": - if err := b.run(root, ".", desc, nil, tools.ar(), "rc", realOut, out); err != nil { + if err := b.run(root, ".", desc, nil, tools.ar(), arArgs, "rc", realOut, out); err != nil { return err } } -- cgit v1.1 From 03ac8302a60099632ea1f95af14db5dfd83f2970 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 5 Mar 2019 23:05:38 +0000 Subject: runtime: enable precise GC checks when using stack maps In the runtime there are bad pointer checks that currently don't work with the concervative collector. With stack maps, the GC is precise and the checks should work. Enable them. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/153871 From-SVN: r269406 --- libgo/go/runtime/mgcmark.go | 4 ++-- libgo/go/runtime/mgcsweep.go | 6 ++++-- libgo/go/runtime/runtime1.go | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'libgo') diff --git a/libgo/go/runtime/mgcmark.go b/libgo/go/runtime/mgcmark.go index 9da881e..dc5e797 100644 --- a/libgo/go/runtime/mgcmark.go +++ b/libgo/go/runtime/mgcmark.go @@ -1106,9 +1106,9 @@ func scanstackblockwithmap(pc, b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) { // Preemption must be disabled. //go:nowritebarrier func shade(b uintptr) { - if obj, span, objIndex := findObject(b, 0, 0, true); obj != 0 { + if obj, span, objIndex := findObject(b, 0, 0, !usestackmaps); obj != 0 { gcw := &getg().m.p.ptr().gcw - greyobject(obj, 0, 0, span, gcw, objIndex, true) + greyobject(obj, 0, 0, span, gcw, objIndex, !usestackmaps) } } diff --git a/libgo/go/runtime/mgcsweep.go b/libgo/go/runtime/mgcsweep.go index fb5ee6a..bc53de4 100644 --- a/libgo/go/runtime/mgcsweep.go +++ b/libgo/go/runtime/mgcsweep.go @@ -342,8 +342,10 @@ func (s *mspan) sweep(preserve bool) bool { // it is not otherwise a problem. So we disable the test for gccgo. nfreedSigned := int(nfreed) if nalloc > s.allocCount { - // print("runtime: nelems=", s.nelems, " nalloc=", nalloc, " previous allocCount=", s.allocCount, " nfreed=", nfreed, "\n") - // throw("sweep increased allocation count") + if usestackmaps { + print("runtime: nelems=", s.nelems, " nalloc=", nalloc, " previous allocCount=", s.allocCount, " nfreed=", nfreed, "\n") + throw("sweep increased allocation count") + } // For gccgo, adjust the freed count as a signed number. nfreedSigned = int(s.allocCount) - int(nalloc) diff --git a/libgo/go/runtime/runtime1.go b/libgo/go/runtime/runtime1.go index 66091ff..e2567b3 100644 --- a/libgo/go/runtime/runtime1.go +++ b/libgo/go/runtime/runtime1.go @@ -362,7 +362,9 @@ func parsedebugvars() { // At that point, if debug.invalidptr is set, we crash. // This is not a problem, assuming that M1 really is dead and // the pointer we discovered to it will not be used. - // debug.invalidptr = 1 + if usestackmaps { + debug.invalidptr = 1 + } for p := gogetenv("GODEBUG"); p != ""; { field := "" -- cgit v1.1 From 0e1a6d27009cf81ff7114f8ca4b8c71f122774b4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 6 Mar 2019 14:19:56 +0000 Subject: mksysinfo: actually use modified Statfs_t value Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/165737 From-SVN: r269424 --- libgo/mksysinfo.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'libgo') diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh index e0ae30f..418ba2c 100755 --- a/libgo/mksysinfo.sh +++ b/libgo/mksysinfo.sh @@ -1115,14 +1115,13 @@ grep '^const _FALLOC_' gen-sysinfo.go | # Prefer largefile variant if available. # CentOS 5 does not have f_flags, so pull from f_spare. statfs=`grep '^type _statfs64 ' gen-sysinfo.go || true` +if test "$statfs" == ""; then + statfs=`grep '^type _statfs ' gen-sysinfo.go || true` +fi if ! echo "$statfs" | grep f_flags; then statfs=`echo "$statfs" | sed -e 's/f_spare \[4+1\]\([^ ;]*\)/f_flags \1; f_spare [3+1]\1/'` fi -if test "$statfs" != ""; then - grep '^type _statfs64 ' gen-sysinfo.go -else - grep '^type _statfs ' gen-sysinfo.go -fi | sed -e 's/type _statfs64/type Statfs_t/' \ +echo "$statfs" | sed -e 's/type _statfs64/type Statfs_t/' \ -e 's/type _statfs/type Statfs_t/' \ -e 's/f_type/Type/' \ -e 's/f_bsize/Bsize/' \ -- cgit v1.1 From ee973155b2fd00dfe0ef6a3563c9623512f6632e Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 9 Mar 2019 02:10:22 +0000 Subject: re PR go/89447 (libgo largefile support is incomplete and inconsistent) PR go/89447 syscall, internal/syscall: adjust use of largefile functions Consistently call __go_openat for openat. Use fstatat64, creat64, sendfile64, and getdents64 where needed. Based on patch by Rainer Orth. Fixes https://gcc.gnu.org/PR89447 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/166420 From-SVN: r269521 --- libgo/go/internal/syscall/unix/at.go | 5 +---- libgo/go/internal/syscall/unix/at_largefile.go | 14 ++++++++++++++ libgo/go/internal/syscall/unix/at_regfile.go | 18 ++++++++++++++++++ libgo/go/syscall/libcall_bsd.go | 2 -- libgo/go/syscall/libcall_bsd_largefile.go | 10 ++++++++++ libgo/go/syscall/libcall_bsd_regfile.go | 10 ++++++++++ libgo/go/syscall/libcall_posix.go | 3 --- libgo/go/syscall/libcall_posix_largefile.go | 3 +++ libgo/go/syscall/libcall_posix_regfile.go | 3 +++ libgo/go/syscall/libcall_solaris.go | 12 ------------ libgo/go/syscall/libcall_solaris_largefile.go | 14 ++++++++++++++ libgo/go/syscall/libcall_solaris_regfile.go | 14 ++++++++++++++ 12 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 libgo/go/internal/syscall/unix/at_largefile.go create mode 100644 libgo/go/internal/syscall/unix/at_regfile.go create mode 100644 libgo/go/syscall/libcall_bsd_largefile.go create mode 100644 libgo/go/syscall/libcall_bsd_regfile.go delete mode 100644 libgo/go/syscall/libcall_solaris.go create mode 100644 libgo/go/syscall/libcall_solaris_largefile.go create mode 100644 libgo/go/syscall/libcall_solaris_regfile.go (limited to 'libgo') diff --git a/libgo/go/internal/syscall/unix/at.go b/libgo/go/internal/syscall/unix/at.go index b57b791..a602d3a 100644 --- a/libgo/go/internal/syscall/unix/at.go +++ b/libgo/go/internal/syscall/unix/at.go @@ -13,12 +13,9 @@ import ( //extern unlinkat func unlinkat(int32, *byte, int32) int32 -//extern openat +//extern __go_openat func openat(int32, *byte, int32, syscall.Mode_t) int32 -//extern fstatat -func fstatat(int32, *byte, *syscall.Stat_t, int32) int32 - func Unlinkat(dirfd int, path string, flags int) error { var p *byte p, err := syscall.BytePtrFromString(path) diff --git a/libgo/go/internal/syscall/unix/at_largefile.go b/libgo/go/internal/syscall/unix/at_largefile.go new file mode 100644 index 0000000..5318d23 --- /dev/null +++ b/libgo/go/internal/syscall/unix/at_largefile.go @@ -0,0 +1,14 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix hurd linux solaris,386 solaris,sparc + +package unix + +import ( + "syscall" +) + +//extern fstatat64 +func fstatat(int32, *byte, *syscall.Stat_t, int32) int32 diff --git a/libgo/go/internal/syscall/unix/at_regfile.go b/libgo/go/internal/syscall/unix/at_regfile.go new file mode 100644 index 0000000..004c801 --- /dev/null +++ b/libgo/go/internal/syscall/unix/at_regfile.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !aix +// +build !hurd +// +build !linux +// +build !solaris !386 +// +build !solaris !sparc + +package unix + +import ( + "syscall" +) + +//extern fstatat +func fstatat(int32, *byte, *syscall.Stat_t, int32) int32 diff --git a/libgo/go/syscall/libcall_bsd.go b/libgo/go/syscall/libcall_bsd.go index 9a4b2d6..93f5710 100644 --- a/libgo/go/syscall/libcall_bsd.go +++ b/libgo/go/syscall/libcall_bsd.go @@ -13,8 +13,6 @@ import ( "unsafe" ) -//sys sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error) -//sendfile(outfd _C_int, infd _C_int, offset *Offset_t, count Size_t) Ssize_t func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { if race.Enabled { race.ReleaseMerge(unsafe.Pointer(&ioSync)) diff --git a/libgo/go/syscall/libcall_bsd_largefile.go b/libgo/go/syscall/libcall_bsd_largefile.go new file mode 100644 index 0000000..c6a336c --- /dev/null +++ b/libgo/go/syscall/libcall_bsd_largefile.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris,386 solaris,sparc + +package syscall + +//sys sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error) +//sendfile64(outfd _C_int, infd _C_int, offset *Offset_t, count Size_t) Ssize_t diff --git a/libgo/go/syscall/libcall_bsd_regfile.go b/libgo/go/syscall/libcall_bsd_regfile.go new file mode 100644 index 0000000..388c8a7 --- /dev/null +++ b/libgo/go/syscall/libcall_bsd_regfile.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd solaris,amd64 solaris,sparc64 + +package syscall + +//sys sendfile(outfd int, infd int, offset *Offset_t, count int) (written int, err error) +//sendfile(outfd _C_int, infd _C_int, offset *Offset_t, count Size_t) Ssize_t diff --git a/libgo/go/syscall/libcall_posix.go b/libgo/go/syscall/libcall_posix.go index d2fa0d9..31d6bf1 100644 --- a/libgo/go/syscall/libcall_posix.go +++ b/libgo/go/syscall/libcall_posix.go @@ -184,9 +184,6 @@ func FDZero(set *FdSet) { //sys Close(fd int) (err error) //close(fd _C_int) _C_int -//sys Creat(path string, mode uint32) (fd int, err error) -//creat(path *byte, mode Mode_t) _C_int - //sysnb Dup(oldfd int) (fd int, err error) //dup(oldfd _C_int) _C_int diff --git a/libgo/go/syscall/libcall_posix_largefile.go b/libgo/go/syscall/libcall_posix_largefile.go index 57a7f5e..bf0f9fe 100644 --- a/libgo/go/syscall/libcall_posix_largefile.go +++ b/libgo/go/syscall/libcall_posix_largefile.go @@ -8,6 +8,9 @@ package syscall +//sys Creat(path string, mode uint32) (fd int, err error) +//creat64(path *byte, mode Mode_t) _C_int + //sys Fstat(fd int, stat *Stat_t) (err error) //fstat64(fd _C_int, stat *Stat_t) _C_int diff --git a/libgo/go/syscall/libcall_posix_regfile.go b/libgo/go/syscall/libcall_posix_regfile.go index 5dc6eb6..8ff7213 100644 --- a/libgo/go/syscall/libcall_posix_regfile.go +++ b/libgo/go/syscall/libcall_posix_regfile.go @@ -13,6 +13,9 @@ package syscall +//sys Creat(path string, mode uint32) (fd int, err error) +//creat(path *byte, mode Mode_t) _C_int + //sys Fstat(fd int, stat *Stat_t) (err error) //fstat(fd _C_int, stat *Stat_t) _C_int diff --git a/libgo/go/syscall/libcall_solaris.go b/libgo/go/syscall/libcall_solaris.go deleted file mode 100644 index a026614..0000000 --- a/libgo/go/syscall/libcall_solaris.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -//sys Getdents(fd int, buf []byte) (n int, err error) -//getdents(fd _C_int, buf *byte, nbyte Size_t) _C_int - -func ReadDirent(fd int, buf []byte) (n int, err error) { - return Getdents(fd, buf) -} diff --git a/libgo/go/syscall/libcall_solaris_largefile.go b/libgo/go/syscall/libcall_solaris_largefile.go new file mode 100644 index 0000000..757b229 --- /dev/null +++ b/libgo/go/syscall/libcall_solaris_largefile.go @@ -0,0 +1,14 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris,386 solaris,sparc + +package syscall + +//sys Getdents(fd int, buf []byte) (n int, err error) +//getdents64(fd _C_int, buf *byte, nbyte Size_t) _C_int + +func ReadDirent(fd int, buf []byte) (n int, err error) { + return Getdents(fd, buf) +} diff --git a/libgo/go/syscall/libcall_solaris_regfile.go b/libgo/go/syscall/libcall_solaris_regfile.go new file mode 100644 index 0000000..fa5dd8c --- /dev/null +++ b/libgo/go/syscall/libcall_solaris_regfile.go @@ -0,0 +1,14 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build solaris,amd64 solaris,sparc64 + +package syscall + +//sys Getdents(fd int, buf []byte) (n int, err error) +//getdents(fd _C_int, buf *byte, nbyte Size_t) _C_int + +func ReadDirent(fd int, buf []byte) (n int, err error) { + return Getdents(fd, buf) +} -- cgit v1.1 From a8b58d84bf4fd9c925a835ba39c1c552383bc61b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 18 Mar 2019 20:27:59 +0000 Subject: libgo: update to Go 1.12.1 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/167749 From-SVN: r269780 --- libgo/MERGE | 2 +- libgo/VERSION | 2 +- libgo/go/cmd/cgo/ast.go | 12 --- libgo/go/cmd/cgo/gcc.go | 64 +++---------- libgo/go/cmd/cgo/main.go | 4 +- libgo/go/cmd/go/internal/cache/default.go | 7 +- libgo/go/cmd/go/internal/load/test.go | 10 ++ libgo/go/cmd/go/internal/modfetch/coderepo.go | 100 ++++++++++++++------ libgo/go/cmd/go/internal/modfetch/coderepo_test.go | 9 ++ libgo/go/internal/fmtsort/sort.go | 2 +- libgo/go/internal/fmtsort/sort_test.go | 42 ++++++++- libgo/go/os/removeall_at.go | 3 +- libgo/go/os/removeall_test.go | 30 ++++++ libgo/go/path/filepath/path.go | 11 +-- libgo/go/path/filepath/path_test.go | 103 ++++++++++++++++++++- libgo/go/path/filepath/symlink.go | 10 +- libgo/go/runtime/testdata/testprog/gc.go | 23 +++++ libgo/go/text/template/exec.go | 7 ++ libgo/go/text/template/exec_test.go | 49 ++++++---- libgo/misc/cgo/test/testdata/issue30527.go | 14 +++ libgo/misc/cgo/test/testdata/issue30527/a.go | 19 ++++ libgo/misc/cgo/test/testdata/issue30527/b.go | 11 +++ 22 files changed, 397 insertions(+), 137 deletions(-) create mode 100644 libgo/misc/cgo/test/testdata/issue30527.go create mode 100644 libgo/misc/cgo/test/testdata/issue30527/a.go create mode 100644 libgo/misc/cgo/test/testdata/issue30527/b.go (limited to 'libgo') diff --git a/libgo/MERGE b/libgo/MERGE index 1f0d2d4..d456361 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -05e77d41914d247a1e7caf37d7125ccaa5a53505 +0380c9ad38843d523d9c9804fe300cb7edd7cd3c 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 18a48c3..f325447 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.12 +go1.12.1 diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go index 83d727a..54d6bc2 100644 --- a/libgo/go/cmd/cgo/ast.go +++ b/libgo/go/cmd/cgo/ast.go @@ -200,18 +200,6 @@ func (f *File) saveExprs(x interface{}, context astContext) { } case *ast.CallExpr: f.saveCall(x, context) - case *ast.GenDecl: - if x.Tok == token.CONST { - for _, spec := range x.Specs { - vs := spec.(*ast.ValueSpec) - if vs.Type == nil { - for _, name := range spec.(*ast.ValueSpec).Names { - consts[name.Name] = true - } - } - } - } - } } diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index 7db702f..e56207a 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -915,21 +915,16 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) { needsUnsafe = true } - // Explicitly convert untyped constants to the - // parameter type, to avoid a type mismatch. - if p.isConst(f, arg) { - ptype := p.rewriteUnsafe(param.Go) + // Use "var x T = ..." syntax to explicitly convert untyped + // constants to the parameter type, to avoid a type mismatch. + ptype := p.rewriteUnsafe(param.Go) + + if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer { if ptype != param.Go { needsUnsafe = true } - arg = &ast.CallExpr{ - Fun: ptype, - Args: []ast.Expr{arg}, - } - } - - if !p.needsPointerCheck(f, param.Go, args[i]) { - fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos())) + fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i, + gofmtLine(ptype), gofmtPos(arg, origArg.Pos())) continue } @@ -1272,47 +1267,6 @@ func (p *Package) isType(t ast.Expr) bool { return false } -// isConst reports whether x is an untyped constant expression. -func (p *Package) isConst(f *File, x ast.Expr) bool { - switch x := x.(type) { - case *ast.BasicLit: - return true - case *ast.SelectorExpr: - id, ok := x.X.(*ast.Ident) - if !ok || id.Name != "C" { - return false - } - name := f.Name[x.Sel.Name] - if name != nil { - return name.IsConst() - } - case *ast.Ident: - return x.Name == "nil" || - strings.HasPrefix(x.Name, "_Ciconst_") || - strings.HasPrefix(x.Name, "_Cfconst_") || - strings.HasPrefix(x.Name, "_Csconst_") || - consts[x.Name] - case *ast.UnaryExpr: - return p.isConst(f, x.X) - case *ast.BinaryExpr: - return p.isConst(f, x.X) && p.isConst(f, x.Y) - case *ast.ParenExpr: - return p.isConst(f, x.X) - case *ast.CallExpr: - // Calling the builtin function complex on two untyped - // constants returns an untyped constant. - // TODO: It's possible to construct a case that will - // erroneously succeed if there is a local function - // named "complex", shadowing the builtin, that returns - // a numeric type. I can't think of any cases that will - // erroneously fail. - if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 { - return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1]) - } - } - return false -} - // isVariable reports whether x is a variable, possibly with field references. func (p *Package) isVariable(x ast.Expr) bool { switch x := x.(type) { @@ -2533,13 +2487,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { // Treat this typedef as a uintptr. s := *sub s.Go = c.uintptr + s.BadPointer = true sub = &s // Make sure we update any previously computed type. if oldType := typedef[name.Name]; oldType != nil { oldType.Go = sub.Go + oldType.BadPointer = true } } t.Go = name + t.BadPointer = sub.BadPointer if unionWithPointer[sub.Go] { unionWithPointer[t.Go] = true } @@ -2549,6 +2506,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { if oldType == nil { tt := *t tt.Go = sub.Go + tt.BadPointer = sub.BadPointer typedef[name.Name] = &tt } diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go index 4a5c0ca..80f3568 100644 --- a/libgo/go/cmd/cgo/main.go +++ b/libgo/go/cmd/cgo/main.go @@ -71,9 +71,6 @@ type File struct { Edit *edit.Buffer } -// Untyped constants in the current package. -var consts = make(map[string]bool) - func (f *File) offset(p token.Pos) int { return fset.Position(p).Offset } @@ -154,6 +151,7 @@ type Type struct { Go ast.Expr EnumValues map[string]int64 Typedef string + BadPointer bool } // A FuncType collects information about a function type in both the C and Go worlds. diff --git a/libgo/go/cmd/go/internal/cache/default.go b/libgo/go/cmd/go/internal/cache/default.go index f545c14..7d389c3 100644 --- a/libgo/go/cmd/go/internal/cache/default.go +++ b/libgo/go/cmd/go/internal/cache/default.go @@ -37,7 +37,7 @@ See golang.org to learn more about Go. // the first time Default is called. func initDefaultCache() { dir := DefaultDir() - if dir == "off" || dir == "" { + if dir == "off" { if defaultDirErr != nil { base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr) } @@ -74,7 +74,12 @@ func DefaultDir() string { defaultDirOnce.Do(func() { defaultDir = os.Getenv("GOCACHE") + if filepath.IsAbs(defaultDir) || defaultDir == "off" { + return + } if defaultDir != "" { + defaultDir = "off" + defaultDirErr = fmt.Errorf("GOCACHE is not an absolute path") return } diff --git a/libgo/go/cmd/go/internal/load/test.go b/libgo/go/cmd/go/internal/load/test.go index 5f9daa4..c0e0667 100644 --- a/libgo/go/cmd/go/internal/load/test.go +++ b/libgo/go/cmd/go/internal/load/test.go @@ -129,6 +129,7 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac ptest.Internal.Imports = append(imports, p.Internal.Imports...) ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports) ptest.Internal.ForceLibrary = true + ptest.Internal.BuildInfo = "" ptest.Internal.Build = new(build.Package) *ptest.Internal.Build = *p.Internal.Build m := map[string][]token.Position{} @@ -186,6 +187,7 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac }, Internal: PackageInternal{ Build: &build.Package{Name: "main"}, + BuildInfo: p.Internal.BuildInfo, Asmflags: p.Internal.Asmflags, Gcflags: p.Internal.Gcflags, Ldflags: p.Internal.Ldflags, @@ -352,6 +354,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) { copy(p1.Imports, p.Imports) p = p1 p.Target = "" + p.Internal.BuildInfo = "" } // Update p.Internal.Imports to use test copies. @@ -361,6 +364,13 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) { p.Internal.Imports[i] = p1 } } + + // Don't compile build info from a main package. This can happen + // if -coverpkg patterns include main packages, since those packages + // are imported by pmain. + if p.Internal.BuildInfo != "" && p != pmain { + split() + } } } diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo.go b/libgo/go/cmd/go/internal/modfetch/coderepo.go index 5018b6d..da9f63f 100644 --- a/libgo/go/cmd/go/internal/modfetch/coderepo.go +++ b/libgo/go/cmd/go/internal/modfetch/coderepo.go @@ -23,55 +23,99 @@ import ( type codeRepo struct { modPath string - code codehost.Repo + // code is the repository containing this module. + code codehost.Repo + // codeRoot is the import path at the root of code. codeRoot string - codeDir string + // codeDir is the directory (relative to root) at which we expect to find the module. + // If pathMajor is non-empty and codeRoot is not the full modPath, + // then we look in both codeDir and codeDir+modPath + codeDir string - path string - pathPrefix string - pathMajor string + // pathMajor is the suffix of modPath that indicates its major version, + // or the empty string if modPath is at major version 0 or 1. + // + // pathMajor is typically of the form "/vN", but possibly ".vN", or + // ".vN-unstable" for modules resolved using gopkg.in. + pathMajor string + // pathPrefix is the prefix of modPath that excludes pathMajor. + // It is used only for logging. + pathPrefix string + + // pseudoMajor is the major version prefix to use when generating + // pseudo-versions for this module, derived from the module path. + // + // TODO(golang.org/issue/29262): We can't distinguish v0 from v1 using the + // path alone: we have to compute it by examining the tags at a particular + // revision. pseudoMajor string } -func newCodeRepo(code codehost.Repo, root, path string) (Repo, error) { - if !hasPathPrefix(path, root) { - return nil, fmt.Errorf("mismatched repo: found %s for %s", root, path) +// newCodeRepo returns a Repo that reads the source code for the module with the +// given path, from the repo stored in code, with the root of the repo +// containing the path given by codeRoot. +func newCodeRepo(code codehost.Repo, codeRoot, path string) (Repo, error) { + if !hasPathPrefix(path, codeRoot) { + return nil, fmt.Errorf("mismatched repo: found %s for %s", codeRoot, path) } pathPrefix, pathMajor, ok := module.SplitPathVersion(path) if !ok { return nil, fmt.Errorf("invalid module path %q", path) } + if codeRoot == path { + pathPrefix = path + } pseudoMajor := "v0" if pathMajor != "" { pseudoMajor = pathMajor[1:] } + // Compute codeDir = bar, the subdirectory within the repo + // corresponding to the module root. + // // At this point we might have: - // codeRoot = github.com/rsc/foo // path = github.com/rsc/foo/bar/v2 + // codeRoot = github.com/rsc/foo // pathPrefix = github.com/rsc/foo/bar // pathMajor = /v2 // pseudoMajor = v2 // - // Compute codeDir = bar, the subdirectory within the repo - // corresponding to the module root. - codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, root), "/") - if strings.HasPrefix(path, "gopkg.in/") { - // But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot. - // For example we might have: - // codeRoot = gopkg.in/yaml.v2 - // pathPrefix = gopkg.in/yaml - // pathMajor = .v2 - // pseudoMajor = v2 - // codeDir = pathPrefix (because codeRoot is not a prefix of pathPrefix) - // Clear codeDir - the module root is the repo root for gopkg.in repos. - codeDir = "" + // which gives + // codeDir = bar + // + // We know that pathPrefix is a prefix of path, and codeRoot is a prefix of + // path, but codeRoot may or may not be a prefix of pathPrefix, because + // codeRoot may be the entire path (in which case codeDir should be empty). + // That occurs in two situations. + // + // One is when a go-import meta tag resolves the complete module path, + // including the pathMajor suffix: + // path = nanomsg.org/go/mangos/v2 + // codeRoot = nanomsg.org/go/mangos/v2 + // pathPrefix = nanomsg.org/go/mangos + // pathMajor = /v2 + // pseudoMajor = v2 + // + // The other is similar: for gopkg.in only, the major version is encoded + // with a dot rather than a slash, and thus can't be in a subdirectory. + // path = gopkg.in/yaml.v2 + // codeRoot = gopkg.in/yaml.v2 + // pathPrefix = gopkg.in/yaml + // pathMajor = .v2 + // pseudoMajor = v2 + // + codeDir := "" + if codeRoot != path { + if !hasPathPrefix(pathPrefix, codeRoot) { + return nil, fmt.Errorf("repository rooted at %s cannot contain module %s", codeRoot, path) + } + codeDir = strings.Trim(pathPrefix[len(codeRoot):], "/") } r := &codeRepo{ modPath: path, code: code, - codeRoot: root, + codeRoot: codeRoot, codeDir: codeDir, pathPrefix: pathPrefix, pathMajor: pathMajor, @@ -149,9 +193,6 @@ func (r *codeRepo) Stat(rev string) (*RevInfo, error) { return r.Latest() } codeRev := r.revToRev(rev) - if semver.IsValid(codeRev) && r.codeDir != "" { - codeRev = r.codeDir + "/" + codeRev - } info, err := r.code.Stat(codeRev) if err != nil { return nil, err @@ -290,7 +331,7 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e found1 := err1 == nil && isMajor(mpath1, r.pathMajor) var file2 string - if r.pathMajor != "" && !strings.HasPrefix(r.pathMajor, ".") { + if r.pathMajor != "" && r.codeRoot != r.modPath && !strings.HasPrefix(r.pathMajor, ".") { // Suppose pathMajor is "/v2". // Either go.mod should claim v2 and v2/go.mod should not exist, // or v2/go.mod should exist and claim v2. Not both. @@ -298,6 +339,9 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e // because of replacement modules. This might be a fork of // the real module, found at a different path, usable only in // a replace directive. + // + // TODO(bcmills): This doesn't seem right. Investigate futher. + // (Notably: why can't we replace foo/v2 with fork-of-foo/v3?) dir2 := path.Join(r.codeDir, r.pathMajor[1:]) file2 = path.Join(dir2, "go.mod") gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod) @@ -418,7 +462,7 @@ func (r *codeRepo) Zip(dst io.Writer, version string) error { } defer dl.Close() if actualDir != "" && !hasPathPrefix(dir, actualDir) { - return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir) + return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.modPath, rev, dir, actualDir) } subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/") diff --git a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go index c93d8db..7a41957 100644 --- a/libgo/go/cmd/go/internal/modfetch/coderepo_test.go +++ b/libgo/go/cmd/go/internal/modfetch/coderepo_test.go @@ -323,6 +323,15 @@ var codeRepoTests = []struct { time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC), gomod: "module gopkg.in/natefinch/lumberjack.v2\n", }, + { + path: "nanomsg.org/go/mangos/v2", + rev: "v2.0.2", + version: "v2.0.2", + name: "63f66a65137b9a648ac9f7bf0160b4a4d17d7999", + short: "63f66a65137b", + time: time.Date(2018, 12, 1, 15, 7, 40, 0, time.UTC), + gomod: "module nanomsg.org/go/mangos/v2\n\nrequire (\n\tgithub.com/Microsoft/go-winio v0.4.11\n\tgithub.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da\n\tgithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect\n\tgithub.com/gorilla/websocket v1.4.0\n\tgithub.com/jtolds/gls v4.2.1+incompatible // indirect\n\tgithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect\n\tgithub.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c\n\tgolang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect\n)\n", + }, } func TestCodeRepo(t *testing.T) { diff --git a/libgo/go/internal/fmtsort/sort.go b/libgo/go/internal/fmtsort/sort.go index c959cbe..70a305a 100644 --- a/libgo/go/internal/fmtsort/sort.go +++ b/libgo/go/internal/fmtsort/sort.go @@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int { if c, ok := nilCompare(aVal, bVal); ok { return c } - c := compare(reflect.ValueOf(aType), reflect.ValueOf(bType)) + c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type())) if c != 0 { return c } diff --git a/libgo/go/internal/fmtsort/sort_test.go b/libgo/go/internal/fmtsort/sort_test.go index 6b10c77..e060d4b 100644 --- a/libgo/go/internal/fmtsort/sort_test.go +++ b/libgo/go/internal/fmtsort/sort_test.go @@ -126,10 +126,6 @@ var sortTests = []sortTest{ map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"}, "[3 4]:34 [7 1]:71 [7 2]:72", }, - { - map[interface{}]string{7: "7", 4: "4", 3: "3", nil: "nil"}, - ":nil 3:3 4:4 7:7", - }, } func sprint(data interface{}) string { @@ -210,3 +206,41 @@ func TestOrder(t *testing.T) { } } } + +func TestInterface(t *testing.T) { + // A map containing multiple concrete types should be sorted by type, + // then value. However, the relative ordering of types is unspecified, + // so test this by checking the presence of sorted subgroups. + m := map[interface{}]string{ + [2]int{1, 0}: "", + [2]int{0, 1}: "", + true: "", + false: "", + 3.1: "", + 2.1: "", + 1.1: "", + math.NaN(): "", + 3: "", + 2: "", + 1: "", + "c": "", + "b": "", + "a": "", + struct{ x, y int }{1, 0}: "", + struct{ x, y int }{0, 1}: "", + } + got := sprint(m) + typeGroups := []string{ + "NaN: 1.1: 2.1: 3.1:", // float64 + "false: true:", // bool + "1: 2: 3:", // int + "a: b: c:", // string + "[0 1]: [1 0]:", // [2]int + "{0 1}: {1 0}:", // struct{ x int; y int } + } + for _, g := range typeGroups { + if !strings.Contains(got, g) { + t.Errorf("sorted map should contain %q", g) + } + } +} diff --git a/libgo/go/os/removeall_at.go b/libgo/go/os/removeall_at.go index abdcb66..512a891 100644 --- a/libgo/go/os/removeall_at.go +++ b/libgo/go/os/removeall_at.go @@ -92,7 +92,8 @@ func removeAllFrom(parent *File, path string) error { if IsNotExist(err) { return nil } - return err + recurseErr = err + break } names, readErr := file.Readdirnames(request) diff --git a/libgo/go/os/removeall_test.go b/libgo/go/os/removeall_test.go index 9dab0d4..21371d8 100644 --- a/libgo/go/os/removeall_test.go +++ b/libgo/go/os/removeall_test.go @@ -372,3 +372,33 @@ func TestRemoveAllButReadOnly(t *testing.T) { } } } + +func TestRemoveUnreadableDir(t *testing.T) { + switch runtime.GOOS { + case "nacl", "js", "windows": + t.Skipf("skipping test on %s", runtime.GOOS) + } + + if Getuid() == 0 { + t.Skip("skipping test when running as root") + } + + t.Parallel() + + tempDir, err := ioutil.TempDir("", "TestRemoveAllButReadOnly-") + if err != nil { + t.Fatal(err) + } + defer RemoveAll(tempDir) + + target := filepath.Join(tempDir, "d0", "d1", "d2") + if err := MkdirAll(target, 0755); err != nil { + t.Fatal(err) + } + if err := Chmod(target, 0300); err != nil { + t.Fatal(err) + } + if err := RemoveAll(filepath.Join(tempDir, "d0")); err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index bbb9030..aba1717 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -96,19 +96,14 @@ func Clean(path string) string { } return originalPath + "." } - - n := len(path) - if volLen > 2 && n == 1 && os.IsPathSeparator(path[0]) { - // UNC volume name with trailing slash. - return FromSlash(originalPath[:volLen]) - } rooted := os.IsPathSeparator(path[0]) // Invariants: // reading from path; r is index of next byte to process. - // writing to out; w is index of next byte to write. - // dotdot is index in out where .. must stop, either because + // writing to buf; w is index of next byte to write. + // dotdot is index in buf where .. must stop, either because // it is the leading slash or it is a leading ../../.. prefix. + n := len(path) out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} r, dotdot := 0, 0 if rooted { diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index deeb47e..22632a0 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -93,9 +93,6 @@ var wincleantests = []PathTest{ {`//host/share/foo/../baz`, `\\host\share\baz`}, {`\\a\b\..\c`, `\\a\b\c`}, {`\\a\b`, `\\a\b`}, - {`\\a\b\`, `\\a\b`}, - {`\\folder\share\foo`, `\\folder\share\foo`}, - {`\\folder\share\foo\`, `\\folder\share\foo`}, } func TestClean(t *testing.T) { @@ -1417,3 +1414,103 @@ func TestIssue29372(t *testing.T) { } } } + +// Issue 30520 part 1. +func TestEvalSymlinksAboveRoot(t *testing.T) { + testenv.MustHaveSymlink(t) + + t.Parallel() + + tmpDir, err := ioutil.TempDir("", "TestEvalSymlinksAboveRoot") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + evalTmpDir, err := filepath.EvalSymlinks(tmpDir) + if err != nil { + t.Fatal(err) + } + + if err := os.Mkdir(filepath.Join(evalTmpDir, "a"), 0777); err != nil { + t.Fatal(err) + } + if err := os.Symlink(filepath.Join(evalTmpDir, "a"), filepath.Join(evalTmpDir, "b")); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(filepath.Join(evalTmpDir, "a", "file"), nil, 0666); err != nil { + t.Fatal(err) + } + + // Count the number of ".." elements to get to the root directory. + vol := filepath.VolumeName(evalTmpDir) + c := strings.Count(evalTmpDir[len(vol):], string(os.PathSeparator)) + var dd []string + for i := 0; i < c+2; i++ { + dd = append(dd, "..") + } + + wantSuffix := strings.Join([]string{"a", "file"}, string(os.PathSeparator)) + + // Try different numbers of "..". + for _, i := range []int{c, c + 1, c + 2} { + check := strings.Join([]string{evalTmpDir, strings.Join(dd[:i], string(os.PathSeparator)), evalTmpDir[len(vol)+1:], "b", "file"}, string(os.PathSeparator)) + if resolved, err := filepath.EvalSymlinks(check); err != nil { + t.Errorf("EvalSymlinks(%q) failed: %v", check, err) + } else if !strings.HasSuffix(resolved, wantSuffix) { + t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix) + } else { + t.Logf("EvalSymlinks(%q) = %q", check, resolved) + } + } +} + +// Issue 30520 part 2. +func TestEvalSymlinksAboveRootChdir(t *testing.T) { + testenv.MustHaveSymlink(t) + + tmpDir, err := ioutil.TempDir("", "TestEvalSymlinksAboveRootChdir") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + defer os.Chdir(wd) + + if err := os.Chdir(tmpDir); err != nil { + t.Fatal(err) + } + + subdir := filepath.Join("a", "b") + if err := os.MkdirAll(subdir, 0777); err != nil { + t.Fatal(err) + } + if err := os.Symlink(subdir, "c"); err != nil { + t.Fatal(err) + } + if err := ioutil.WriteFile(filepath.Join(subdir, "file"), nil, 0666); err != nil { + t.Fatal(err) + } + + subdir = filepath.Join("d", "e", "f") + if err := os.MkdirAll(subdir, 0777); err != nil { + t.Fatal(err) + } + if err := os.Chdir(subdir); err != nil { + t.Fatal(err) + } + + check := filepath.Join("..", "..", "..", "c", "file") + wantSuffix := filepath.Join("a", "b", "file") + if resolved, err := filepath.EvalSymlinks(check); err != nil { + t.Errorf("EvalSymlinks(%q) failed: %v", check, err) + } else if !strings.HasSuffix(resolved, wantSuffix) { + t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix) + } else { + t.Logf("EvalSymlinks(%q) = %q", check, resolved) + } +} diff --git a/libgo/go/path/filepath/symlink.go b/libgo/go/path/filepath/symlink.go index 4b41039..de043c1 100644 --- a/libgo/go/path/filepath/symlink.go +++ b/libgo/go/path/filepath/symlink.go @@ -44,18 +44,26 @@ func walkSymlinks(path string) (string, error) { } else if path[start:end] == ".." { // Back up to previous component if possible. // Note that volLen includes any leading slash. + + // Set r to the index of the last slash in dest, + // after the volume. var r int for r = len(dest) - 1; r >= volLen; r-- { if os.IsPathSeparator(dest[r]) { break } } - if r < volLen { + if r < volLen || dest[r+1:] == ".." { + // Either path has no slashes + // (it's empty or just "C:") + // or it ends in a ".." we had to keep. + // Either way, keep this "..". if len(dest) > volLen { dest += pathSeparator } dest += ".." } else { + // Discard everything since the last slash. dest = dest[:r] } continue diff --git a/libgo/go/runtime/testdata/testprog/gc.go b/libgo/go/runtime/testdata/testprog/gc.go index 6b308e0..629cf2f 100644 --- a/libgo/go/runtime/testdata/testprog/gc.go +++ b/libgo/go/runtime/testdata/testprog/gc.go @@ -18,6 +18,7 @@ func init() { register("GCFairness2", GCFairness2) register("GCSys", GCSys) register("GCPhys", GCPhys) + register("DeferLiveness", DeferLiveness) } func GCSys() { @@ -210,3 +211,25 @@ func GCPhys() { fmt.Println("OK") runtime.KeepAlive(saved) } + +// Test that defer closure is correctly scanned when the stack is scanned. +func DeferLiveness() { + var x [10]int + escape(&x) + fn := func() { + if x[0] != 42 { + panic("FAIL") + } + } + defer fn() + + x[0] = 42 + runtime.GC() + runtime.GC() + runtime.GC() +} + +//go:noinline +func escape(x interface{}) { sink2 = x; sink2 = nil } + +var sink2 interface{} diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go index d29721b..8d39e34 100644 --- a/libgo/go/text/template/exec.go +++ b/libgo/go/text/template/exec.go @@ -578,6 +578,13 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, } typ := receiver.Type() receiver, isNil := indirect(receiver) + if receiver.Kind() == reflect.Interface && isNil { + // Calling a method on a nil interface can't work. The + // MethodByName method call below would panic. + s.errorf("nil pointer evaluating %s.%s", typ, fieldName) + return zero + } + // Unless it's an interface, need to get to a value of type *T to guarantee // we see all methods of T and *T. ptr := receiver diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go index 085f7c4..3cf9496 100644 --- a/libgo/go/text/template/exec_test.go +++ b/libgo/go/text/template/exec_test.go @@ -58,8 +58,10 @@ type T struct { Empty3 interface{} Empty4 interface{} // Non-empty interfaces. - NonEmptyInterface I - NonEmptyInterfacePtS *I + NonEmptyInterface I + NonEmptyInterfacePtS *I + NonEmptyInterfaceNil I + NonEmptyInterfaceTypedNil I // Stringer. Str fmt.Stringer Err error @@ -141,24 +143,25 @@ var tVal = &T{ {"one": 1, "two": 2}, {"eleven": 11, "twelve": 12}, }, - Empty1: 3, - Empty2: "empty2", - Empty3: []int{7, 8}, - Empty4: &U{"UinEmpty"}, - NonEmptyInterface: &T{X: "x"}, - NonEmptyInterfacePtS: &siVal, - Str: bytes.NewBuffer([]byte("foozle")), - Err: errors.New("erroozle"), - PI: newInt(23), - PS: newString("a string"), - PSI: newIntSlice(21, 22, 23), - BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) }, - VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") }, - VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") }, - NilOKFunc: func(s *int) bool { return s == nil }, - ErrFunc: func() (string, error) { return "bla", nil }, - PanicFunc: func() string { panic("test panic") }, - Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X + Empty1: 3, + Empty2: "empty2", + Empty3: []int{7, 8}, + Empty4: &U{"UinEmpty"}, + NonEmptyInterface: &T{X: "x"}, + NonEmptyInterfacePtS: &siVal, + NonEmptyInterfaceTypedNil: (*T)(nil), + Str: bytes.NewBuffer([]byte("foozle")), + Err: errors.New("erroozle"), + PI: newInt(23), + PS: newString("a string"), + PSI: newIntSlice(21, 22, 23), + BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) }, + VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") }, + VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") }, + NilOKFunc: func(s *int) bool { return s == nil }, + ErrFunc: func() (string, error) { return "bla", nil }, + PanicFunc: func() string { panic("test panic") }, + Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X } var tSliceOfNil = []*T{nil} @@ -365,6 +368,7 @@ var execTests = []execTest{ {".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true}, {".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true}, {"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true}, + {"method on typed nil interface value", "{{.NonEmptyInterfaceTypedNil.Method0}}", "M0", tVal, true}, // Function call builtin. {".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true}, @@ -1492,6 +1496,11 @@ func TestExecutePanicDuringCall(t *testing.T) { "{{call .PanicFunc}}", tVal, `template: t:1:2: executing "t" at : error calling call: test panic`, }, + { + "method call on nil interface", + "{{.NonEmptyInterfaceNil.Method0}}", tVal, + `template: t:1:23: executing "t" at <.NonEmptyInterfaceNil.Method0>: nil pointer evaluating template.I.Method0`, + }, } for _, tc := range tests { b := new(bytes.Buffer) diff --git a/libgo/misc/cgo/test/testdata/issue30527.go b/libgo/misc/cgo/test/testdata/issue30527.go new file mode 100644 index 0000000..4ea7d31 --- /dev/null +++ b/libgo/misc/cgo/test/testdata/issue30527.go @@ -0,0 +1,14 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 30527: function call rewriting casts untyped +// constants to int because of ":=" usage. + +package cgotest + +import "cgotest/issue30527" + +func issue30527G() { + issue30527.G(nil) +} diff --git a/libgo/misc/cgo/test/testdata/issue30527/a.go b/libgo/misc/cgo/test/testdata/issue30527/a.go new file mode 100644 index 0000000..eb50147 --- /dev/null +++ b/libgo/misc/cgo/test/testdata/issue30527/a.go @@ -0,0 +1,19 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue30527 + +import "math" + +/* +#include + +static void issue30527F(char **p, uint64_t mod, uint32_t unused) {} +*/ +import "C" + +func G(p **C.char) { + C.issue30527F(p, math.MaxUint64, 1) + C.issue30527F(p, 1<<64-1, Z) +} diff --git a/libgo/misc/cgo/test/testdata/issue30527/b.go b/libgo/misc/cgo/test/testdata/issue30527/b.go new file mode 100644 index 0000000..87e8255 --- /dev/null +++ b/libgo/misc/cgo/test/testdata/issue30527/b.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue30527 + +const ( + X = 1 << iota + Y + Z +) -- cgit v1.1