libgo: update to Go 1.10.3 release
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 13 Jun 2018 13:51:23 +0000 (13:51 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 13 Jun 2018 13:51:23 +0000 (13:51 +0000)
    Reviewed-on: https://go-review.googlesource.com/118495

From-SVN: r261549

31 files changed:
gcc/go/gofrontend/MERGE
libgo/MERGE
libgo/VERSION
libgo/go/cmd/go/internal/get/discovery.go
libgo/go/cmd/go/internal/get/get.go
libgo/go/cmd/go/internal/get/pkg_test.go
libgo/go/cmd/go/internal/list/list.go
libgo/go/cmd/go/internal/load/icfg.go [deleted file]
libgo/go/cmd/go/internal/load/pkg.go
libgo/go/cmd/go/internal/test/test.go
libgo/go/cmd/go/internal/work/build.go
libgo/go/cmd/go/internal/work/security.go
libgo/go/cmd/go/internal/work/security_test.go
libgo/go/cmd/go/testdata/modlegacy/src/new/go.mod [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/new.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/p1/p1.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/p2/p2.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/sub/go.mod [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/old/p1/p1.go [new file with mode: 0644]
libgo/go/cmd/go/testdata/modlegacy/src/old/p2/p2.go [new file with mode: 0644]
libgo/go/cmd/go/vendor_test.go
libgo/go/crypto/x509/name_constraints_test.go
libgo/go/crypto/x509/root_windows.go
libgo/go/crypto/x509/verify.go
libgo/go/strings/strings.go
libgo/go/strings/strings_test.go
libgo/misc/cgo/testcshared/main2.c
libgo/misc/cgo/testcshared/src/libgo2/libgo2.go

index 0b28a5bd21f860421f632a84af3f2a4ada72c624..e904f7c07ec6d321f45cfa91cb9cbce5221ebffc 100644 (file)
@@ -1,4 +1,4 @@
-bfe3a9b26c8b2e1b9ef34a7232a2d1529e639bbf
+6743db0ed81e313acf66c00a4ed0e2dcaaca2c9f
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 6f31fab2265ac6f1fae341f7541a63a9bffab357..c54da0dcac138fb14958dd400a07bab0114c0d4c 100644 (file)
@@ -1,4 +1,4 @@
-71bdbf431b79dff61944f22c25c7e085ccfc25d5
+fe8a0d12b14108cbe2408b417afcaab722b0727c
 
 The first line of this file holds the git revision number of the
 last merge done from the master library sources.
index 98736c7cde066677a1e9093df736db72d765e37d..038f0b9313a806d9e57f1570291a82e42d8c7070 100644 (file)
@@ -1 +1 @@
-go1.10.2
+go1.10.3
index b2918dbb4f31aaa4488856e68113fee8efecdf2c..97aa1d7e8d6344d2061c01f1de48966ffc24f000 100644 (file)
@@ -55,6 +55,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
                        continue
                }
                if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+                       // Ignore VCS type "mod", which is new Go modules.
+                       // This code is for old go get and must ignore the new mod lines.
+                       // Otherwise matchGoImport will complain about two
+                       // different metaImport lines for the same Prefix.
+                       if f[1] == "mod" {
+                               continue
+                       }
                        imports = append(imports, metaImport{
                                Prefix:   f[0],
                                VCS:      f[1],
index 733116eca04d83d8c5d1267d6931c1e33c32a67b..5bfeac387cc6b76addb4956e2e1c273e65ef4c2d 100644 (file)
@@ -209,7 +209,7 @@ var downloadRootCache = map[string]bool{}
 // download runs the download half of the get command
 // for the package named by the argument.
 func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
-       if mode&load.UseVendor != 0 {
+       if mode&load.ResolveImport != 0 {
                // Caller is responsible for expanding vendor paths.
                panic("internal error: download mode has useVendor set")
        }
@@ -217,7 +217,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
                if parent == nil {
                        return load.LoadPackage(path, stk)
                }
-               return load.LoadImport(path, parent.Dir, parent, stk, nil, mode)
+               return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
        }
 
        p := load1(arg, mode)
@@ -346,12 +346,12 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
                                base.Errorf("%s", err)
                                continue
                        }
-                       // If this is a test import, apply vendor lookup now.
-                       // We cannot pass useVendor to download, because
+                       // If this is a test import, apply module and vendor lookup now.
+                       // We cannot pass ResolveImport to download, because
                        // download does caching based on the value of path,
                        // so it must be the fully qualified path already.
                        if i >= len(p.Imports) {
-                               path = load.VendoredImportPath(p, path)
+                               path = load.ResolveImportPath(p, path)
                        }
                        download(path, p, stk, 0)
                }
index b8937a57ec9122d036edfe559c297c9ca4e9c8dc..1179d86693acee898af4fb29fe989565f1107ac0 100644 (file)
@@ -47,6 +47,20 @@ var parseMetaGoImportsTests = []struct {
                        {"baz/quux", "git", "http://github.com/rsc/baz/quux"},
                },
        },
+       {
+               `<meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
+               <meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">`,
+               []metaImport{
+                       {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+               },
+       },
+       {
+               `<meta name="go-import" content="foo/bar mod http://github.com/rsc/baz/quux">
+               <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">`,
+               []metaImport{
+                       {"foo/bar", "git", "https://github.com/rsc/foo/bar"},
+               },
+       },
        {
                `<head>
                <meta name="go-import" content="foo/bar git https://github.com/rsc/foo/bar">
index 7435273000421cabbe44e4526ebefb2d9e4a9180..16e7f70d73151cb27fbee094f0353149b49bd2a0 100644 (file)
@@ -218,8 +218,8 @@ func runList(cmd *base.Command, args []string) {
 
        for _, pkg := range pkgs {
                // Show vendor-expanded paths in listing
-               pkg.TestImports = pkg.Vendored(pkg.TestImports)
-               pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
+               pkg.TestImports = pkg.Resolve(pkg.TestImports)
+               pkg.XTestImports = pkg.Resolve(pkg.XTestImports)
 
                do(&pkg.PackagePublic)
        }
diff --git a/libgo/go/cmd/go/internal/load/icfg.go b/libgo/go/cmd/go/internal/load/icfg.go
deleted file mode 100644 (file)
index d8dd664..0000000
+++ /dev/null
@@ -1,78 +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 load
-
-import (
-       "bytes"
-       "encoding/json"
-       "errors"
-       "io/ioutil"
-)
-
-// DebugDeprecatedImportcfg is installed as the undocumented -debug-deprecated-importcfg build flag.
-// It is useful for debugging subtle problems in the go command logic but not something
-// we want users to depend on. The hope is that the "deprecated" will make that clear.
-// We intend to remove this flag in Go 1.11.
-var DebugDeprecatedImportcfg debugDeprecatedImportcfgFlag
-
-type debugDeprecatedImportcfgFlag struct {
-       enabled bool
-       Import  map[string]string
-       Pkg     map[string]*debugDeprecatedImportcfgPkg
-}
-
-type debugDeprecatedImportcfgPkg struct {
-       Dir    string
-       Import map[string]string
-}
-
-var (
-       debugDeprecatedImportcfgMagic = []byte("# debug-deprecated-importcfg\n")
-       errImportcfgSyntax            = errors.New("malformed syntax")
-)
-
-func (f *debugDeprecatedImportcfgFlag) String() string { return "" }
-
-func (f *debugDeprecatedImportcfgFlag) Set(x string) error {
-       if x == "" {
-               *f = debugDeprecatedImportcfgFlag{}
-               return nil
-       }
-       data, err := ioutil.ReadFile(x)
-       if err != nil {
-               return err
-       }
-
-       if !bytes.HasPrefix(data, debugDeprecatedImportcfgMagic) {
-               return errImportcfgSyntax
-       }
-       data = data[len(debugDeprecatedImportcfgMagic):]
-
-       f.Import = nil
-       f.Pkg = nil
-       if err := json.Unmarshal(data, &f); err != nil {
-               return errImportcfgSyntax
-       }
-       f.enabled = true
-       return nil
-}
-
-func (f *debugDeprecatedImportcfgFlag) lookup(parent *Package, path string) (dir, newPath string) {
-       newPath = path
-       if p := f.Import[path]; p != "" {
-               newPath = p
-       }
-       if parent != nil {
-               if p1 := f.Pkg[parent.ImportPath]; p1 != nil {
-                       if p := p1.Import[path]; p != "" {
-                               newPath = p
-                       }
-               }
-       }
-       if p2 := f.Pkg[newPath]; p2 != nil {
-               return p2.Dir, newPath
-       }
-       return "", ""
-}
index 882b86d148fe3ba976142248c37906c9727920a9..dfb1ff63afeb8dd5cbf7597cb016434dde000e8d 100644 (file)
@@ -6,6 +6,7 @@
 package load
 
 import (
+       "bytes"
        "fmt"
        "go/build"
        "go/token"
@@ -14,6 +15,7 @@ import (
        pathpkg "path"
        "path/filepath"
        "sort"
+       "strconv"
        "strings"
        "unicode"
        "unicode/utf8"
@@ -168,7 +170,7 @@ func (e *NoGoError) Error() string {
        return "no Go files in " + e.Package.Dir
 }
 
-// Vendored returns the vendor-resolved version of imports,
+// Resolve returns the resolved version of imports,
 // which should be p.TestImports or p.XTestImports, NOT p.Imports.
 // The imports in p.TestImports and p.XTestImports are not recursively
 // loaded during the initial load of p, so they list the imports found in
@@ -178,14 +180,14 @@ func (e *NoGoError) Error() string {
 // can produce better error messages if it starts with the original paths.
 // The initial load of p loads all the non-test imports and rewrites
 // the vendored paths, so nothing should ever call p.vendored(p.Imports).
-func (p *Package) Vendored(imports []string) []string {
+func (p *Package) Resolve(imports []string) []string {
        if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
-               panic("internal error: p.vendored(p.Imports) called")
+               panic("internal error: p.Resolve(p.Imports) called")
        }
        seen := make(map[string]bool)
        var all []string
        for _, path := range imports {
-               path = VendoredImportPath(p, path)
+               path = ResolveImportPath(p, path)
                if !seen[path] {
                        seen[path] = true
                        all = append(all, path)
@@ -380,16 +382,20 @@ func makeImportValid(r rune) rune {
 
 // Mode flags for loadImport and download (in get.go).
 const (
-       // UseVendor means that loadImport should do vendor expansion
-       // (provided the vendoring experiment is enabled).
-       // That is, useVendor means that the import path came from
-       // a source file and has not been vendor-expanded yet.
-       // Every import path should be loaded initially with useVendor,
-       // and then the expanded version (with the /vendor/ in it) gets
-       // recorded as the canonical import path. At that point, future loads
-       // of that package must not pass useVendor, because
+       // ResolveImport means that loadImport should do import path expansion.
+       // That is, ResolveImport means that the import path came from
+       // a source file and has not been expanded yet to account for
+       // vendoring or possible module adjustment.
+       // Every import path should be loaded initially with ResolveImport,
+       // and then the expanded version (for example with the /vendor/ in it)
+       // gets recorded as the canonical import path. At that point, future loads
+       // of that package must not pass ResolveImport, because
        // disallowVendor will reject direct use of paths containing /vendor/.
-       UseVendor = 1 << iota
+       ResolveImport = 1 << iota
+
+       // ResolveModule is for download (part of "go get") and indicates
+       // that the module adjustment should be done, but not vendor adjustment.
+       ResolveModule
 
        // GetTestDeps is for download (part of "go get") and indicates
        // that test dependencies should be fetched too.
@@ -412,20 +418,17 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
        importPath := path
        origPath := path
        isLocal := build.IsLocalImport(path)
-       var debugDeprecatedImportcfgDir string
        if isLocal {
                importPath = dirToImportPath(filepath.Join(srcDir, path))
-       } else if DebugDeprecatedImportcfg.enabled {
-               if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" {
-                       debugDeprecatedImportcfgDir = d
-                       importPath = i
-               }
-       } else if mode&UseVendor != 0 {
-               // We do our own vendor resolution, because we want to
+       } else if mode&ResolveImport != 0 {
+               // We do our own path resolution, because we want to
                // find out the key to use in packageCache without the
                // overhead of repeated calls to buildContext.Import.
                // The code is also needed in a few other places anyway.
-               path = VendoredImportPath(parent, path)
+               path = ResolveImportPath(parent, path)
+               importPath = path
+       } else if mode&ResolveModule != 0 {
+               path = ModuleImportPath(parent, path)
                importPath = path
        }
 
@@ -441,26 +444,17 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
                // Load package.
                // Import always returns bp != nil, even if an error occurs,
                // in order to return partial information.
-               var bp *build.Package
-               var err error
-               if debugDeprecatedImportcfgDir != "" {
-                       bp, err = cfg.BuildContext.ImportDir(debugDeprecatedImportcfgDir, 0)
-               } else if DebugDeprecatedImportcfg.enabled {
-                       bp = new(build.Package)
-                       err = fmt.Errorf("unknown import path %q: not in import cfg", importPath)
-               } else {
-                       buildMode := build.ImportComment
-                       if mode&UseVendor == 0 || path != origPath {
-                               // Not vendoring, or we already found the vendored path.
-                               buildMode |= build.IgnoreVendor
-                       }
-                       bp, err = cfg.BuildContext.Import(path, srcDir, buildMode)
+               buildMode := build.ImportComment
+               if mode&ResolveImport == 0 || path != origPath {
+                       // Not vendoring, or we already found the vendored path.
+                       buildMode |= build.IgnoreVendor
                }
+               bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
                bp.ImportPath = importPath
                if cfg.GOBIN != "" {
                        bp.BinDir = cfg.GOBIN
                }
-               if debugDeprecatedImportcfgDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+               if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
                        !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
                        err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
                }
@@ -469,7 +463,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
                        p = setErrorPos(p, importPos)
                }
 
-               if debugDeprecatedImportcfgDir == "" && origPath != cleanImport(origPath) {
+               if origPath != cleanImport(origPath) {
                        p.Error = &PackageError{
                                ImportStack: stk.Copy(),
                                Err:         fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
@@ -482,7 +476,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
        if perr := disallowInternal(srcDir, p, stk); perr != p {
                return setErrorPos(perr, importPos)
        }
-       if mode&UseVendor != 0 {
+       if mode&ResolveImport != 0 {
                if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
                        return setErrorPos(perr, importPos)
                }
@@ -541,31 +535,31 @@ func isDir(path string) bool {
        return result
 }
 
-// VendoredImportPath returns the expansion of path when it appears in parent.
-// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
-// x/vendor/path, vendor/path, or else stay path if none of those exist.
-// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
-func VendoredImportPath(parent *Package, path string) (found string) {
-       if DebugDeprecatedImportcfg.enabled {
-               if d, i := DebugDeprecatedImportcfg.lookup(parent, path); d != "" {
-                       return i
-               }
-               return path
-       }
-
-       if parent == nil || parent.Root == "" {
-               return path
-       }
+// ResolveImportPath returns the true meaning of path when it appears in parent.
+// There are two different resolutions applied.
+// First, there is Go 1.5 vendoring (golang.org/s/go15vendor).
+// If vendor expansion doesn't trigger, then the path is also subject to
+// Go 1.11 vgo legacy conversion (golang.org/issue/25069).
+func ResolveImportPath(parent *Package, path string) (found string) {
+       found = VendoredImportPath(parent, path)
+       if found != path {
+               return found
+       }
+       return ModuleImportPath(parent, path)
+}
 
-       dir := filepath.Clean(parent.Dir)
-       root := filepath.Join(parent.Root, "src")
-       if !str.HasFilePathPrefix(dir, root) || parent.ImportPath != "command-line-arguments" && filepath.Join(root, parent.ImportPath) != dir {
+// dirAndRoot returns the source directory and workspace root
+// for the package p, guaranteeing that root is a path prefix of dir.
+func dirAndRoot(p *Package) (dir, root string) {
+       dir = filepath.Clean(p.Dir)
+       root = filepath.Join(p.Root, "src")
+       if !str.HasFilePathPrefix(dir, root) || p.ImportPath != "command-line-arguments" && filepath.Join(root, p.ImportPath) != dir {
                // Look for symlinks before reporting error.
                dir = expandPath(dir)
                root = expandPath(root)
        }
 
-       if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || parent.ImportPath != "command-line-arguments" && !parent.Internal.Local && filepath.Join(root, parent.ImportPath) != dir {
+       if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || p.ImportPath != "command-line-arguments" && !p.Internal.Local && filepath.Join(root, p.ImportPath) != dir {
                base.Fatalf("unexpected directory layout:\n"+
                        "       import path: %s\n"+
                        "       root: %s\n"+
@@ -573,14 +567,28 @@ func VendoredImportPath(parent *Package, path string) (found string) {
                        "       expand root: %s\n"+
                        "       expand dir: %s\n"+
                        "       separator: %s",
-                       parent.ImportPath,
-                       filepath.Join(parent.Root, "src"),
-                       filepath.Clean(parent.Dir),
+                       p.ImportPath,
+                       filepath.Join(p.Root, "src"),
+                       filepath.Clean(p.Dir),
                        root,
                        dir,
                        string(filepath.Separator))
        }
 
+       return dir, root
+}
+
+// VendoredImportPath returns the vendor-expansion of path when it appears in parent.
+// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
+// x/vendor/path, vendor/path, or else stay path if none of those exist.
+// VendoredImportPath returns the expanded path or, if no expansion is found, the original.
+func VendoredImportPath(parent *Package, path string) (found string) {
+       if parent == nil || parent.Root == "" {
+               return path
+       }
+
+       dir, root := dirAndRoot(parent)
+
        vpath := "vendor/" + path
        for i := len(dir); i >= len(root); i-- {
                if i < len(dir) && dir[i] != filepath.Separator {
@@ -623,6 +631,164 @@ func VendoredImportPath(parent *Package, path string) (found string) {
        return path
 }
 
+var (
+       modulePrefix   = []byte("\nmodule ")
+       goModPathCache = make(map[string]string)
+)
+
+// goModPath returns the module path in the go.mod in dir, if any.
+func goModPath(dir string) (path string) {
+       path, ok := goModPathCache[dir]
+       if ok {
+               return path
+       }
+       defer func() {
+               goModPathCache[dir] = path
+       }()
+
+       data, err := ioutil.ReadFile(filepath.Join(dir, "go.mod"))
+       if err != nil {
+               return ""
+       }
+       var i int
+       if bytes.HasPrefix(data, modulePrefix[1:]) {
+               i = 0
+       } else {
+               i = bytes.Index(data, modulePrefix)
+               if i < 0 {
+                       return ""
+               }
+               i++
+       }
+       line := data[i:]
+
+       // Cut line at \n, drop trailing \r if present.
+       if j := bytes.IndexByte(line, '\n'); j >= 0 {
+               line = line[:j]
+       }
+       if line[len(line)-1] == '\r' {
+               line = line[:len(line)-1]
+       }
+       line = line[len("module "):]
+
+       // If quoted, unquote.
+       path = strings.TrimSpace(string(line))
+       if path != "" && path[0] == '"' {
+               s, err := strconv.Unquote(path)
+               if err != nil {
+                       return ""
+               }
+               path = s
+       }
+       return path
+}
+
+// findVersionElement returns the slice indices of the final version element /vN in path.
+// If there is no such element, it returns -1, -1.
+func findVersionElement(path string) (i, j int) {
+       j = len(path)
+       for i = len(path) - 1; i >= 0; i-- {
+               if path[i] == '/' {
+                       if isVersionElement(path[i:j]) {
+                               return i, j
+                       }
+                       j = i
+               }
+       }
+       return -1, -1
+}
+
+// isVersionElement reports whether s is a well-formed path version element:
+// v2, v3, v10, etc, but not v0, v05, v1.
+func isVersionElement(s string) bool {
+       if len(s) < 3 || s[0] != '/' || s[1] != 'v' || s[2] == '0' || s[2] == '1' && len(s) == 3 {
+               return false
+       }
+       for i := 2; i < len(s); i++ {
+               if s[i] < '0' || '9' < s[i] {
+                       return false
+               }
+       }
+       return true
+}
+
+// ModuleImportPath translates import paths found in go modules
+// back down to paths that can be resolved in ordinary builds.
+//
+// Define “new” code as code with a go.mod file in the same directory
+// or a parent directory. If an import in new code says x/y/v2/z but
+// x/y/v2/z does not exist and x/y/go.mod says “module x/y/v2”,
+// then go build will read the import as x/y/z instead.
+// See golang.org/issue/25069.
+func ModuleImportPath(parent *Package, path string) (found string) {
+       if parent == nil || parent.Root == "" {
+               return path
+       }
+
+       // If there are no vN elements in path, leave it alone.
+       // (The code below would do the same, but only after
+       // some other file system accesses that we can avoid
+       // here by returning early.)
+       if i, _ := findVersionElement(path); i < 0 {
+               return path
+       }
+
+       dir, root := dirAndRoot(parent)
+
+       // Consider dir and parents, up to and including root.
+       for i := len(dir); i >= len(root); i-- {
+               if i < len(dir) && dir[i] != filepath.Separator {
+                       continue
+               }
+               if goModPath(dir[:i]) != "" {
+                       goto HaveGoMod
+               }
+       }
+       // This code is not in a tree with a go.mod,
+       // so apply no changes to the path.
+       return path
+
+HaveGoMod:
+       // This import is in a tree with a go.mod.
+       // Allow it to refer to code in GOPATH/src/x/y/z as x/y/v2/z
+       // if GOPATH/src/x/y/go.mod says module "x/y/v2",
+
+       // If x/y/v2/z exists, use it unmodified.
+       if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" {
+               return path
+       }
+
+       // Otherwise look for a go.mod supplying a version element.
+       // Some version-like elements may appear in paths but not
+       // be module versions; we skip over those to look for module
+       // versions. For example the module m/v2 might have a
+       // package m/v2/api/v1/foo.
+       limit := len(path)
+       for limit > 0 {
+               i, j := findVersionElement(path[:limit])
+               if i < 0 {
+                       return path
+               }
+               if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" {
+                       if mpath := goModPath(bp.Dir); mpath != "" {
+                               // Found a valid go.mod file, so we're stopping the search.
+                               // If the path is m/v2/p and we found m/go.mod that says
+                               // "module m/v2", then we return "m/p".
+                               if mpath == path[:j] {
+                                       return path[:i] + path[j:]
+                               }
+                               // Otherwise just return the original path.
+                               // We didn't find anything worth rewriting,
+                               // and the go.mod indicates that we should
+                               // not consider parent directories.
+                               return path
+                       }
+               }
+               limit = i
+       }
+       return path
+}
+
 // hasGoFiles reports whether dir contains any files with names ending in .go.
 // For a vendor check we must exclude directories that contain no .go files.
 // Otherwise it is not possible to vendor just a/b/c and still import the
@@ -1087,7 +1253,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
                if path == "C" {
                        continue
                }
-               p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], UseVendor)
+               p1 := LoadImport(path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
                if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
                        p.Error = &PackageError{
                                ImportStack: stk.Copy(),
@@ -1598,7 +1764,7 @@ func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err
        stk.Push(p.ImportPath + " (test)")
        rawTestImports := str.StringList(p.TestImports)
        for i, path := range p.TestImports {
-               p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], UseVendor)
+               p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.TestImportPos[path], ResolveImport)
                if p1.Error != nil {
                        return nil, nil, p1.Error
                }
@@ -1626,7 +1792,7 @@ func GetTestPackagesFor(p *Package, forceTest bool) (ptest, pxtest *Package, err
        pxtestNeedsPtest := false
        rawXTestImports := str.StringList(p.XTestImports)
        for i, path := range p.XTestImports {
-               p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], UseVendor)
+               p1 := LoadImport(path, p.Dir, p, &stk, p.Internal.Build.XTestImportPos[path], ResolveImport)
                if p1.Error != nil {
                        return nil, nil, p1.Error
                }
index 72415ccd095062aa9bebb212ec7310c663b7f834..5adb7df7c482fe9b33282a8ecc6933d994428bf0 100644 (file)
@@ -606,10 +606,10 @@ func runTest(cmd *base.Command, args []string) {
                        for _, path := range p.Imports {
                                deps[path] = true
                        }
-                       for _, path := range p.Vendored(p.TestImports) {
+                       for _, path := range p.Resolve(p.TestImports) {
                                deps[path] = true
                        }
-                       for _, path := range p.Vendored(p.XTestImports) {
+                       for _, path := range p.Resolve(p.XTestImports) {
                                deps[path] = true
                        }
                }
index 57b7b00879121a6ca1acf919ff773e23a3bb1c9b..25dfe58d4bf90fa7e90a3dcd63ad5bfccc8d56e7 100644 (file)
@@ -229,7 +229,6 @@ func AddBuildFlags(cmd *base.Command) {
 
        // Undocumented, unstable debugging flags.
        cmd.Flag.StringVar(&cfg.DebugActiongraph, "debug-actiongraph", "", "")
-       cmd.Flag.Var(&load.DebugDeprecatedImportcfg, "debug-deprecated-importcfg", "")
 }
 
 // fileExtSplit expects a filename and returns the name
index 5c67aa945eff71d0fd926adf2b35240c8df89e5f..1b82af9c97cad4fe14a69ea634bf2bd827dcafce 100644 (file)
@@ -41,43 +41,57 @@ var re = regexp.MustCompile
 
 var validCompilerFlags = []*regexp.Regexp{
        re(`-D([A-Za-z_].*)`),
+       re(`-F([^@\-].*)`),
        re(`-I([^@\-].*)`),
        re(`-O`),
        re(`-O([^@\-].*)`),
        re(`-W`),
        re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
        re(`-Wa,-mbig-obj`),
+       re(`-Wp,-D([A-Za-z_].*)`),
        re(`-ansi`),
+       re(`-f(no-)?asynchronous-unwind-tables`),
        re(`-f(no-)?blocks`),
+       re(`-f(no-)builtin-[a-zA-Z0-9_]*`),
        re(`-f(no-)?common`),
        re(`-f(no-)?constant-cfstrings`),
        re(`-fdiagnostics-show-note-include-stack`),
+       re(`-f(no-)?eliminate-unused-debug-types`),
        re(`-f(no-)?exceptions`),
+       re(`-f(no-)?fast-math`),
        re(`-f(no-)?inline-functions`),
        re(`-finput-charset=([^@\-].*)`),
        re(`-f(no-)?fat-lto-objects`),
+       re(`-f(no-)?keep-inline-dllexport`),
        re(`-f(no-)?lto`),
        re(`-fmacro-backtrace-limit=(.+)`),
        re(`-fmessage-length=(.+)`),
        re(`-f(no-)?modules`),
        re(`-f(no-)?objc-arc`),
+       re(`-f(no-)?objc-nonfragile-abi`),
+       re(`-f(no-)?objc-legacy-dispatch`),
        re(`-f(no-)?omit-frame-pointer`),
        re(`-f(no-)?openmp(-simd)?`),
        re(`-f(no-)?permissive`),
        re(`-f(no-)?(pic|PIC|pie|PIE)`),
+       re(`-f(no-)?plt`),
        re(`-f(no-)?rtti`),
        re(`-f(no-)?split-stack`),
        re(`-f(no-)?stack-(.+)`),
        re(`-f(no-)?strict-aliasing`),
        re(`-f(un)signed-char`),
        re(`-f(no-)?use-linker-plugin`), // safe if -B is not used; we don't permit -B
+       re(`-f(no-)?visibility-inlines-hidden`),
        re(`-fsanitize=(.+)`),
        re(`-ftemplate-depth-(.+)`),
        re(`-fvisibility=(.+)`),
        re(`-g([^@\-].*)?`),
        re(`-m32`),
        re(`-m64`),
-       re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
+       re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
+       re(`-marm`),
+       re(`-mfloat-abi=([^@\-].*)`),
+       re(`-mfpmath=[0-9a-z,+]*`),
        re(`-m(no-)?avx[0-9a-z.]*`),
        re(`-m(no-)?ms-bitfields`),
        re(`-m(no-)?stack-(.+)`),
@@ -86,12 +100,16 @@ var validCompilerFlags = []*regexp.Regexp{
        re(`-miphoneos-version-min=(.+)`),
        re(`-mnop-fun-dllimport`),
        re(`-m(no-)?sse[0-9.]*`),
+       re(`-mthumb(-interwork)?`),
+       re(`-mthreads`),
        re(`-mwindows`),
+       re(`--param=ssp-buffer-size=[0-9]*`),
        re(`-pedantic(-errors)?`),
        re(`-pipe`),
        re(`-pthread`),
        re(`-?-std=([^@\-].*)`),
        re(`-?-stdlib=([^@\-].*)`),
+       re(`--sysroot=([^@\-].*)`),
        re(`-w`),
        re(`-x([^@\-].*)`),
 }
@@ -115,15 +133,20 @@ var validLinkerFlags = []*regexp.Regexp{
        re(`-O`),
        re(`-O([^@\-].*)`),
        re(`-f(no-)?(pic|PIC|pie|PIE)`),
+       re(`-f(no-)?openmp(-simd)?`),
        re(`-fsanitize=([^@\-].*)`),
        re(`-g([^@\-].*)?`),
-       re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
+       re(`-headerpad_max_install_names`),
+       re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`),
+       re(`-mfloat-abi=([^@\-].*)`),
        re(`-mmacosx-(.+)`),
        re(`-mios-simulator-version-min=(.+)`),
        re(`-miphoneos-version-min=(.+)`),
+       re(`-mthreads`),
        re(`-mwindows`),
        re(`-(pic|PIC|pie|PIE)`),
        re(`-pthread`),
+       re(`-rdynamic`),
        re(`-shared`),
        re(`-?-static([-a-z0-9+]*)`),
        re(`-?-stdlib=([^@\-].*)`),
@@ -134,22 +157,27 @@ var validLinkerFlags = []*regexp.Regexp{
        // in a wildcard would allow tunnelling arbitrary additional
        // linker arguments through one of these.
        re(`-Wl,--(no-)?allow-multiple-definition`),
+       re(`-Wl,--(no-)?allow-shlib-undefined`),
        re(`-Wl,--(no-)?as-needed`),
        re(`-Wl,-Bdynamic`),
        re(`-Wl,-Bstatic`),
+       re(`-WL,-O([^@,\-][^,]*)?`),
        re(`-Wl,-d[ny]`),
        re(`-Wl,--disable-new-dtags`),
+       re(`-Wl,-e[=,][a-zA-Z0-9]*`),
        re(`-Wl,--enable-new-dtags`),
        re(`-Wl,--end-group`),
        re(`-Wl,-framework,[^,@\-][^,]+`),
        re(`-Wl,-headerpad_max_install_names`),
        re(`-Wl,--no-undefined`),
-       re(`-Wl,-rpath[=,]([^,@\-][^,]+)`),
+       re(`-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)`),
+       re(`-Wl,-s`),
        re(`-Wl,-search_paths_first`),
        re(`-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)`),
        re(`-Wl,--start-group`),
        re(`-Wl,-?-static`),
-       re(`-Wl,--subsystem,(native|windows|console|posix|xbox)`),
+       re(`-Wl,-?-subsystem,(native|windows|console|posix|xbox)`),
+       re(`-Wl,-syslibroot[=,]([^,@\-][^,]+)`),
        re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
        re(`-Wl,-?-unresolved-symbols=[^,]+`),
        re(`-Wl,--(no-)?warn-([^,]+)`),
@@ -157,6 +185,7 @@ var validLinkerFlags = []*regexp.Regexp{
        re(`-Wl,-z,relro`),
 
        re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
+       re(`\./.*\.(a|o|obj|dll|dylib|so)`),
 }
 
 var validLinkerFlagsWithNextArg = []string{
index bd898c9de6c17dabd670df76d5799363235753cb..c3a61b8e70b0ae446497c629863d76e2c71810dc 100644 (file)
@@ -12,6 +12,7 @@ import (
 var goodCompilerFlags = [][]string{
        {"-DFOO"},
        {"-Dfoo=bar"},
+       {"-F/Qt"},
        {"-I/"},
        {"-I/etc/passwd"},
        {"-I."},
@@ -62,6 +63,8 @@ var goodCompilerFlags = [][]string{
 var badCompilerFlags = [][]string{
        {"-D@X"},
        {"-D-X"},
+       {"-F@dir"},
+       {"-F-dir"},
        {"-I@dir"},
        {"-I-dir"},
        {"-O@1"},
@@ -125,6 +128,7 @@ var goodLinkerFlags = [][]string{
        {"-Wl,--no-warn-error"},
        {"foo.so"},
        {"_世界.dll"},
+       {"./x.o"},
        {"libcgosotest.dylib"},
        {"-F", "framework"},
        {"-l", "."},
@@ -191,6 +195,7 @@ var badLinkerFlags = [][]string{
        {"-x", "--c"},
        {"-x", "@obj"},
        {"-Wl,-rpath,@foo"},
+       {"../x.o"},
 }
 
 func TestCheckLinkerFlags(t *testing.T) {
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/go.mod b/libgo/go/cmd/go/testdata/modlegacy/src/new/go.mod
new file mode 100644 (file)
index 0000000..d0dd46d
--- /dev/null
@@ -0,0 +1 @@
+module "new/v2"
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/new.go b/libgo/go/cmd/go/testdata/modlegacy/src/new/new.go
new file mode 100644 (file)
index 0000000..e99c47a
--- /dev/null
@@ -0,0 +1,3 @@
+package new
+
+import _ "new/v2/p2"
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/p1/p1.go b/libgo/go/cmd/go/testdata/modlegacy/src/new/p1/p1.go
new file mode 100644 (file)
index 0000000..4539f40
--- /dev/null
@@ -0,0 +1,7 @@
+package p1
+
+import _ "old/p2"
+import _ "new/v2"
+import _ "new/v2/p2"
+import _ "new/sub/v2/x/v1/y" // v2 is module, v1 is directory in module
+import _ "new/sub/inner/x"   // new/sub/inner/go.mod overrides new/sub/go.mod
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/p2/p2.go b/libgo/go/cmd/go/testdata/modlegacy/src/new/p2/p2.go
new file mode 100644 (file)
index 0000000..9b9052f
--- /dev/null
@@ -0,0 +1 @@
+package p2
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/go.mod b/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/go.mod
new file mode 100644 (file)
index 0000000..484d20c
--- /dev/null
@@ -0,0 +1 @@
+module new/sub/v2
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod b/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/inner/go.mod
new file mode 100644 (file)
index 0000000..ba39345
--- /dev/null
@@ -0,0 +1 @@
+module new/sub/inner
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go b/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/inner/x/x.go
new file mode 100644 (file)
index 0000000..823aafd
--- /dev/null
@@ -0,0 +1 @@
+package x
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go b/libgo/go/cmd/go/testdata/modlegacy/src/new/sub/x/v1/y/y.go
new file mode 100644 (file)
index 0000000..789ca71
--- /dev/null
@@ -0,0 +1 @@
+package y
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/old/p1/p1.go b/libgo/go/cmd/go/testdata/modlegacy/src/old/p1/p1.go
new file mode 100644 (file)
index 0000000..9052748
--- /dev/null
@@ -0,0 +1,5 @@
+package p1
+
+import _ "old/p2"
+import _ "new/p1"
+import _ "new"
diff --git a/libgo/go/cmd/go/testdata/modlegacy/src/old/p2/p2.go b/libgo/go/cmd/go/testdata/modlegacy/src/old/p2/p2.go
new file mode 100644 (file)
index 0000000..9b9052f
--- /dev/null
@@ -0,0 +1 @@
+package p2
index 4f21a510a3cff765fd502b6b7df2dde0ac0f96cd..0e7a633240b72d51ec8087df8cafdcfd0334bee3 100644 (file)
@@ -10,6 +10,7 @@ import (
        "bytes"
        "fmt"
        "internal/testenv"
+       "os"
        "path/filepath"
        "regexp"
        "strings"
@@ -328,3 +329,75 @@ func TestVendor12156(t *testing.T) {
        tg.grepStderrNot("panic", "panicked")
        tg.grepStderr(`cannot find package "x"`, "wrong error")
 }
+
+// Module legacy support does path rewriting very similar to vendoring.
+
+func TestModLegacy(t *testing.T) {
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy"))
+       tg.run("list", "-f", "{{.Imports}}", "old/p1")
+       tg.grepStdout("new/p1", "old/p1 should import new/p1")
+       tg.run("list", "-f", "{{.Imports}}", "new/p1")
+       tg.grepStdout("new/p2", "new/p1 should import new/p2 (not new/v2/p2)")
+       tg.grepStdoutNot("new/v2", "new/p1 should NOT import new/v2*")
+       tg.grepStdout("new/sub/x/v1/y", "new/p1 should import new/sub/x/v1/y (not new/sub/v2/x/v1/y)")
+       tg.grepStdoutNot("new/sub/v2", "new/p1 should NOT import new/sub/v2*")
+       tg.grepStdout("new/sub/inner/x", "new/p1 should import new/sub/inner/x (no rewrites)")
+       tg.run("build", "old/p1", "new/p1")
+}
+
+func TestModLegacyGet(t *testing.T) {
+       testenv.MustHaveExternalNetwork(t)
+
+       tg := testgo(t)
+       defer tg.cleanup()
+       tg.makeTempdir()
+       tg.setenv("GOPATH", tg.path("d1"))
+       tg.run("get", "vcs-test.golang.org/git/modlegacy1-old.git/p1")
+       tg.run("list", "-f", "{{.Deps}}", "vcs-test.golang.org/git/modlegacy1-old.git/p1")
+       tg.grepStdout("new.git/p2", "old/p1 should depend on new/p2")
+       tg.grepStdoutNot("new.git/v2/p2", "old/p1 should NOT depend on new/v2/p2")
+       tg.run("build", "vcs-test.golang.org/git/modlegacy1-old.git/p1", "vcs-test.golang.org/git/modlegacy1-new.git/p1")
+
+       tg.setenv("GOPATH", tg.path("d2"))
+
+       tg.must(os.RemoveAll(tg.path("d2")))
+       tg.run("get", "github.com/rsc/vgotest5")
+       tg.run("get", "github.com/rsc/vgotest4")
+       tg.run("get", "github.com/myitcv/vgo_example_compat")
+
+       if testing.Short() {
+               return
+       }
+
+       tg.must(os.RemoveAll(tg.path("d2")))
+       tg.run("get", "github.com/rsc/vgotest4")
+       tg.run("get", "github.com/rsc/vgotest5")
+       tg.run("get", "github.com/myitcv/vgo_example_compat")
+
+       tg.must(os.RemoveAll(tg.path("d2")))
+       tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5")
+       tg.run("get", "github.com/myitcv/vgo_example_compat")
+
+       tg.must(os.RemoveAll(tg.path("d2")))
+       tg.run("get", "github.com/rsc/vgotest5", "github.com/rsc/vgotest4")
+       tg.run("get", "github.com/myitcv/vgo_example_compat")
+
+       tg.must(os.RemoveAll(tg.path("d2")))
+       tg.run("get", "github.com/myitcv/vgo_example_compat")
+       tg.run("get", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5")
+
+       pkgs := []string{"github.com/myitcv/vgo_example_compat", "github.com/rsc/vgotest4", "github.com/rsc/vgotest5"}
+       for i := 0; i < 3; i++ {
+               for j := 0; j < 3; j++ {
+                       for k := 0; k < 3; k++ {
+                               if i == j || i == k || k == j {
+                                       continue
+                               }
+                               tg.must(os.RemoveAll(tg.path("d2")))
+                               tg.run("get", pkgs[i], pkgs[j], pkgs[k])
+                       }
+               }
+       }
+}
index bad488f89fb47958276a7fbacd81e083a7b16183..95d55fd7619b4f5ab3310b4fcfbd40e8e4179037 100644 (file)
@@ -1222,8 +1222,9 @@ var nameConstraintsTests = []nameConstraintsTest{
                },
        },
 
-       // #63: A specified key usage in an intermediate forbids other usages
-       // in the leaf.
+       // #63: An intermediate with enumerated EKUs causes a failure if we
+       // test for an EKU not in that set. (ServerAuth is required by
+       // default.)
        nameConstraintsTest{
                roots: []constraintsSpec{
                        constraintsSpec{},
@@ -1239,11 +1240,11 @@ var nameConstraintsTests = []nameConstraintsTest{
                        sans: []string{"dns:example.com"},
                        ekus: []string{"serverAuth"},
                },
-               expectedError: "EKU not permitted",
+               expectedError: "incompatible key usage",
        },
 
-       // #64: A specified key usage in an intermediate forbids other usages
-       // in the leaf, even if we don't recognise them.
+       // #64: an unknown EKU in the leaf doesn't break anything, even if it's not
+       // correctly nested.
        nameConstraintsTest{
                roots: []constraintsSpec{
                        constraintsSpec{},
@@ -1259,7 +1260,7 @@ var nameConstraintsTests = []nameConstraintsTest{
                        sans: []string{"dns:example.com"},
                        ekus: []string{"other"},
                },
-               expectedError: "EKU not permitted",
+               requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
        },
 
        // #65: trying to add extra permitted key usages in an intermediate
@@ -1284,24 +1285,25 @@ var nameConstraintsTests = []nameConstraintsTest{
                },
        },
 
-       // #66: EKUs in roots are ignored.
+       // #66: EKUs in roots are not ignored.
        nameConstraintsTest{
                roots: []constraintsSpec{
                        constraintsSpec{
-                               ekus: []string{"serverAuth"},
+                               ekus: []string{"email"},
                        },
                },
                intermediates: [][]constraintsSpec{
                        []constraintsSpec{
                                constraintsSpec{
-                                       ekus: []string{"serverAuth", "email"},
+                                       ekus: []string{"serverAuth"},
                                },
                        },
                },
                leaf: leafSpec{
                        sans: []string{"dns:example.com"},
-                       ekus: []string{"serverAuth", "email"},
+                       ekus: []string{"serverAuth"},
                },
+               expectedError: "incompatible key usage",
        },
 
        // #67: in order to support COMODO chains, SGC key usages permit
@@ -1447,8 +1449,7 @@ var nameConstraintsTests = []nameConstraintsTest{
                expectedError: "\"https://example.com/test\" is excluded",
        },
 
-       // #75: While serverAuth in a CA certificate permits clientAuth in a leaf,
-       // serverAuth in a leaf shouldn't permit clientAuth when requested in
+       // #75: serverAuth in a leaf shouldn't permit clientAuth when requested in
        // VerifyOptions.
        nameConstraintsTest{
                roots: []constraintsSpec{
@@ -1558,6 +1559,27 @@ var nameConstraintsTests = []nameConstraintsTest{
                },
                requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
        },
+
+       // #81: EKUs that are not asserted in VerifyOpts are not required to be
+       // nested.
+       nameConstraintsTest{
+               roots: []constraintsSpec{
+                       constraintsSpec{},
+               },
+               intermediates: [][]constraintsSpec{
+                       []constraintsSpec{
+                               constraintsSpec{
+                                       ekus: []string{"serverAuth"},
+                               },
+                       },
+               },
+               leaf: leafSpec{
+                       sans: []string{"dns:example.com"},
+                       // There's no email EKU in the intermediate. This would be rejected if
+                       // full nesting was required.
+                       ekus: []string{"email", "serverAuth"},
+               },
+       },
 }
 
 func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
index 92cc71692d8195bbc634806310e2f3add67671f8..3621a93abac2e3d63da585202341c1c54ac1695a 100644 (file)
@@ -95,6 +95,12 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e
        return nil
 }
 
+type _CertChainPolicyPara struct {
+       Size            uint32
+       Flags           uint32
+       ExtraPolicyPara unsafe.Pointer
+}
+
 // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
 // use as a certificate chain for a SSL/TLS server.
 func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
@@ -108,13 +114,13 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex
        }
        sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
 
-       para := &syscall.CertChainPolicyPara{
-               ExtraPolicyPara: uintptr(unsafe.Pointer(sslPara)),
+       para := &_CertChainPolicyPara{
+               ExtraPolicyPara: unsafe.Pointer(sslPara),
        }
        para.Size = uint32(unsafe.Sizeof(*para))
 
        status := syscall.CertChainPolicyStatus{}
-       err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
+       err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, (*syscall.CertChainPolicyPara)(unsafe.Pointer(para)), &status)
        if err != nil {
                return err
        }
index 0ea214bd2e02a9e4996e702dd1fc71d67c2ac0c8..60e415b7ec257cd0f03009dbb3dd790f7971ba40 100644 (file)
@@ -56,8 +56,7 @@ const (
        // CPU time to verify.
        TooManyConstraints
        // CANotAuthorizedForExtKeyUsage results when an intermediate or root
-       // certificate does not permit an extended key usage that is claimed by
-       // the leaf certificate.
+       // certificate does not permit a requested extended key usage.
        CANotAuthorizedForExtKeyUsage
 )
 
@@ -82,7 +81,7 @@ func (e CertificateInvalidError) Error() string {
        case TooManyIntermediates:
                return "x509: too many intermediates for path length constraint"
        case IncompatibleUsage:
-               return "x509: certificate specifies an incompatible key usage: " + e.Detail
+               return "x509: certificate specifies an incompatible key usage"
        case NameMismatch:
                return "x509: issuer name does not match subject from issuing certificate"
        case NameConstraintsWithoutSANs:
@@ -185,9 +184,8 @@ type VerifyOptions struct {
        // list means ExtKeyUsageServerAuth. To accept any key usage, include
        // ExtKeyUsageAny.
        //
-       // Certificate chains are required to nest extended key usage values,
-       // irrespective of this value. This matches the Windows CryptoAPI behavior,
-       // but not the spec.
+       // Certificate chains are required to nest these extended key usage values.
+       // (This matches the Windows CryptoAPI behavior, but not the spec.)
        KeyUsages []ExtKeyUsage
        // MaxConstraintComparisions is the maximum number of comparisons to
        // perform when checking a given certificate's name constraints. If
@@ -549,51 +547,6 @@ func (c *Certificate) checkNameConstraints(count *int,
        return nil
 }
 
-const (
-       checkingAgainstIssuerCert = iota
-       checkingAgainstLeafCert
-)
-
-// ekuPermittedBy returns true iff the given extended key usage is permitted by
-// the given EKU from a certificate. Normally, this would be a simple
-// comparison plus a special case for the “any” EKU. But, in order to support
-// existing certificates, some exceptions are made.
-func ekuPermittedBy(eku, certEKU ExtKeyUsage, context int) bool {
-       if certEKU == ExtKeyUsageAny || eku == certEKU {
-               return true
-       }
-
-       // Some exceptions are made to support existing certificates. Firstly,
-       // the ServerAuth and SGC EKUs are treated as a group.
-       mapServerAuthEKUs := func(eku ExtKeyUsage) ExtKeyUsage {
-               if eku == ExtKeyUsageNetscapeServerGatedCrypto || eku == ExtKeyUsageMicrosoftServerGatedCrypto {
-                       return ExtKeyUsageServerAuth
-               }
-               return eku
-       }
-
-       eku = mapServerAuthEKUs(eku)
-       certEKU = mapServerAuthEKUs(certEKU)
-
-       if eku == certEKU {
-               return true
-       }
-
-       // If checking a requested EKU against the list in a leaf certificate there
-       // are fewer exceptions.
-       if context == checkingAgainstLeafCert {
-               return false
-       }
-
-       // ServerAuth in a CA permits ClientAuth in the leaf.
-       return (eku == ExtKeyUsageClientAuth && certEKU == ExtKeyUsageServerAuth) ||
-               // Any CA may issue an OCSP responder certificate.
-               eku == ExtKeyUsageOCSPSigning ||
-               // Code-signing CAs can use Microsoft's commercial and
-               // kernel-mode EKUs.
-               (eku == ExtKeyUsageMicrosoftCommercialCodeSigning || eku == ExtKeyUsageMicrosoftKernelCodeSigning) && certEKU == ExtKeyUsageCodeSigning
-}
-
 // isValid performs validity checks on c given that it is a candidate to append
 // to the chain in currentChain.
 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
@@ -708,59 +661,6 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
                }
        }
 
-       checkEKUs := certType == intermediateCertificate
-
-       // If no extended key usages are specified, then all are acceptable.
-       if checkEKUs && (len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0) {
-               checkEKUs = false
-       }
-
-       // If the “any” key usage is permitted, then no more checks are needed.
-       if checkEKUs {
-               for _, caEKU := range c.ExtKeyUsage {
-                       comparisonCount++
-                       if caEKU == ExtKeyUsageAny {
-                               checkEKUs = false
-                               break
-                       }
-               }
-       }
-
-       if checkEKUs {
-       NextEKU:
-               for _, eku := range leaf.ExtKeyUsage {
-                       if comparisonCount > maxConstraintComparisons {
-                               return CertificateInvalidError{c, TooManyConstraints, ""}
-                       }
-
-                       for _, caEKU := range c.ExtKeyUsage {
-                               comparisonCount++
-                               if ekuPermittedBy(eku, caEKU, checkingAgainstIssuerCert) {
-                                       continue NextEKU
-                               }
-                       }
-
-                       oid, _ := oidFromExtKeyUsage(eku)
-                       return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", oid)}
-               }
-
-       NextUnknownEKU:
-               for _, eku := range leaf.UnknownExtKeyUsage {
-                       if comparisonCount > maxConstraintComparisons {
-                               return CertificateInvalidError{c, TooManyConstraints, ""}
-                       }
-
-                       for _, caEKU := range c.UnknownExtKeyUsage {
-                               comparisonCount++
-                               if caEKU.Equal(eku) {
-                                       continue NextUnknownEKU
-                               }
-                       }
-
-                       return CertificateInvalidError{c, CANotAuthorizedForExtKeyUsage, fmt.Sprintf("EKU not permitted: %#v", eku)}
-               }
-       }
-
        // KeyUsage status flags are ignored. From Engineering Security, Peter
        // Gutmann: A European government CA marked its signing certificates as
        // being valid for encryption only, but no-one noticed. Another
@@ -861,63 +761,38 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
                }
        }
 
-       requestedKeyUsages := make([]ExtKeyUsage, len(opts.KeyUsages))
-       copy(requestedKeyUsages, opts.KeyUsages)
-       if len(requestedKeyUsages) == 0 {
-               requestedKeyUsages = append(requestedKeyUsages, ExtKeyUsageServerAuth)
+       var candidateChains [][]*Certificate
+       if opts.Roots.contains(c) {
+               candidateChains = append(candidateChains, []*Certificate{c})
+       } else {
+               if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
+                       return nil, err
+               }
        }
 
-       // If no key usages are specified, then any are acceptable.
-       checkEKU := len(c.ExtKeyUsage) > 0
-
-       for _, eku := range requestedKeyUsages {
-               if eku == ExtKeyUsageAny {
-                       checkEKU = false
-                       break
-               }
+       keyUsages := opts.KeyUsages
+       if len(keyUsages) == 0 {
+               keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
        }
 
-       if checkEKU {
-               foundMatch := false
-       NextUsage:
-               for _, eku := range requestedKeyUsages {
-                       for _, leafEKU := range c.ExtKeyUsage {
-                               if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) {
-                                       foundMatch = true
-                                       break NextUsage
-                               }
-                       }
+       // If any key usage is acceptable then we're done.
+       for _, usage := range keyUsages {
+               if usage == ExtKeyUsageAny {
+                       return candidateChains, nil
                }
+       }
 
-               if !foundMatch {
-                       msg := "leaf contains the following, recognized EKUs: "
-
-                       for i, leafEKU := range c.ExtKeyUsage {
-                               oid, ok := oidFromExtKeyUsage(leafEKU)
-                               if !ok {
-                                       continue
-                               }
-
-                               if i > 0 {
-                                       msg += ", "
-                               }
-                               msg += formatOID(oid)
-                       }
-
-                       return nil, CertificateInvalidError{c, IncompatibleUsage, msg}
+       for _, candidate := range candidateChains {
+               if checkChainForKeyUsage(candidate, keyUsages) {
+                       chains = append(chains, candidate)
                }
        }
 
-       var candidateChains [][]*Certificate
-       if opts.Roots.contains(c) {
-               candidateChains = append(candidateChains, []*Certificate{c})
-       } else {
-               if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
-                       return nil, err
-               }
+       if len(chains) == 0 {
+               return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
        }
 
-       return candidateChains, nil
+       return chains, nil
 }
 
 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
@@ -1078,3 +953,65 @@ func (c *Certificate) VerifyHostname(h string) error {
 
        return HostnameError{c, h}
 }
+
+func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
+       usages := make([]ExtKeyUsage, len(keyUsages))
+       copy(usages, keyUsages)
+
+       if len(chain) == 0 {
+               return false
+       }
+
+       usagesRemaining := len(usages)
+
+       // We walk down the list and cross out any usages that aren't supported
+       // by each certificate. If we cross out all the usages, then the chain
+       // is unacceptable.
+
+NextCert:
+       for i := len(chain) - 1; i >= 0; i-- {
+               cert := chain[i]
+               if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
+                       // The certificate doesn't have any extended key usage specified.
+                       continue
+               }
+
+               for _, usage := range cert.ExtKeyUsage {
+                       if usage == ExtKeyUsageAny {
+                               // The certificate is explicitly good for any usage.
+                               continue NextCert
+                       }
+               }
+
+               const invalidUsage ExtKeyUsage = -1
+
+       NextRequestedUsage:
+               for i, requestedUsage := range usages {
+                       if requestedUsage == invalidUsage {
+                               continue
+                       }
+
+                       for _, usage := range cert.ExtKeyUsage {
+                               if requestedUsage == usage {
+                                       continue NextRequestedUsage
+                               } else if requestedUsage == ExtKeyUsageServerAuth &&
+                                       (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
+                                               usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
+                                       // In order to support COMODO
+                                       // certificate chains, we have to
+                                       // accept Netscape or Microsoft SGC
+                                       // usages as equal to ServerAuth.
+                                       continue NextRequestedUsage
+                               }
+                       }
+
+                       usages[i] = invalidUsage
+                       usagesRemaining--
+                       if usagesRemaining == 0 {
+                               return false
+                       }
+               }
+       }
+
+       return true
+}
index 02c032046b7bc67247b11ef70d691cdbe51634f2..05e8243b2ea50f7548b6b866fdf776d80c7e69af 100644 (file)
@@ -474,7 +474,7 @@ func Map(mapping func(rune) rune, s string) string {
                b = make([]byte, len(s)+utf8.UTFMax)
                nbytes = copy(b, s[:i])
                if r >= 0 {
-                       if r <= utf8.RuneSelf {
+                       if r < utf8.RuneSelf {
                                b[nbytes] = byte(r)
                                nbytes++
                        } else {
@@ -504,7 +504,7 @@ func Map(mapping func(rune) rune, s string) string {
                r := mapping(c)
 
                // common case
-               if (0 <= r && r <= utf8.RuneSelf) && nbytes < len(b) {
+               if (0 <= r && r < utf8.RuneSelf) && nbytes < len(b) {
                        b[nbytes] = byte(r)
                        nbytes++
                        continue
index f2399f41b02fa1ae6e91a0d3e2475cbf2f1e62ff..92122dbf9b22eb1cbb55a155ee814ea3dd412b2d 100644 (file)
@@ -532,6 +532,7 @@ var upperTests = []StringTest{
        {"longStrinGwitHmixofsmaLLandcAps", "LONGSTRINGWITHMIXOFSMALLANDCAPS"},
        {"long\u0250string\u0250with\u0250nonascii\u2C6Fchars", "LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS"},
        {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+       {"a\u0080\U0010FFFF", "A\u0080\U0010FFFF"},                           // test utf8.RuneSelf and utf8.MaxRune
 }
 
 var lowerTests = []StringTest{
@@ -542,6 +543,7 @@ var lowerTests = []StringTest{
        {"longStrinGwitHmixofsmaLLandcAps", "longstringwithmixofsmallandcaps"},
        {"LONG\u2C6FSTRING\u2C6FWITH\u2C6FNONASCII\u2C6FCHARS", "long\u0250string\u0250with\u0250nonascii\u0250chars"},
        {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+       {"A\u0080\U0010FFFF", "a\u0080\U0010FFFF"},                           // test utf8.RuneSelf and utf8.MaxRune
 }
 
 const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
@@ -654,6 +656,27 @@ func TestMap(t *testing.T) {
        if m != expect {
                t.Errorf("replace invalid sequence: expected %q got %q", expect, m)
        }
+
+       // 8. Check utf8.RuneSelf and utf8.MaxRune encoding
+       encode := func(r rune) rune {
+               switch r {
+               case utf8.RuneSelf:
+                       return unicode.MaxRune
+               case unicode.MaxRune:
+                       return utf8.RuneSelf
+               }
+               return r
+       }
+       s := string(utf8.RuneSelf) + string(utf8.MaxRune)
+       r := string(utf8.MaxRune) + string(utf8.RuneSelf) // reverse of s
+       m = Map(encode, s)
+       if m != r {
+               t.Errorf("encoding not handled correctly: expected %q got %q", r, m)
+       }
+       m = Map(encode, r)
+       if m != s {
+               t.Errorf("encoding not handled correctly: expected %q got %q", s, m)
+       }
 }
 
 func TestToUpper(t *testing.T) { runStringTests(t, ToUpper, "ToUpper", upperTests) }
index 6e8bf141cafa81ea340b12112395d3d163518421..1a3f1d7545fc2f93ecdaeb20643a7f4e689ac5aa 100644 (file)
@@ -9,7 +9,7 @@
 #include <time.h>
 #include <unistd.h>
 
-#define fd (100)
+#define fd (30)
 
 // Tests libgo2.so, which does not export any functions.
 // Read a string from the file descriptor and print it.
index 1b69d8f09fa33c8f161037bc9260e10f4cf97463..e57c93b77d739b5e7ddf180e33234854088b55ff 100644 (file)
@@ -21,7 +21,7 @@ import (
 // that the C code can also use.
 
 const (
-       fd = 100
+       fd = 30
 )
 
 func init() {