libgo: update to Go 1.10.3 release

Reviewed-on: https://go-review.googlesource.com/118495

From-SVN: r261549
This commit is contained in:
Ian Lance Taylor 2018-06-13 13:51:23 +00:00
parent 4dea3bff79
commit c949264918
31 changed files with 554 additions and 329 deletions

View 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.

View 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.

View file

@ -1 +1 @@
go1.10.2
go1.10.3

View 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],

View 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)
}

View 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">

View 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)
}

View file

@ -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 "", ""
}

View 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
// 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)
}
if parent == nil || parent.Root == "" {
return 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
}

View 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
}
}

View 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

View 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{

View 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) {

View file

@ -0,0 +1 @@
module "new/v2"

View file

@ -0,0 +1,3 @@
package new
import _ "new/v2/p2"

View file

@ -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

View file

@ -0,0 +1 @@
package p2

View file

@ -0,0 +1 @@
module new/sub/v2

View file

@ -0,0 +1 @@
module new/sub/inner

View file

@ -0,0 +1 @@
package x

View file

@ -0,0 +1 @@
package y

View file

@ -0,0 +1,5 @@
package p1
import _ "old/p2"
import _ "new/p1"
import _ "new"

View file

@ -0,0 +1 @@
package p2

View 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])
}
}
}
}

View 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) {

View 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
}

View 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,53 +761,6 @@ 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)
}
// 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
}
}
if checkEKU {
foundMatch := false
NextUsage:
for _, eku := range requestedKeyUsages {
for _, leafEKU := range c.ExtKeyUsage {
if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) {
foundMatch = true
break NextUsage
}
}
}
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}
}
}
var candidateChains [][]*Certificate
if opts.Roots.contains(c) {
candidateChains = append(candidateChains, []*Certificate{c})
@ -917,7 +770,29 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
}
}
return candidateChains, nil
keyUsages := opts.KeyUsages
if len(keyUsages) == 0 {
keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
}
// If any key usage is acceptable then we're done.
for _, usage := range keyUsages {
if usage == ExtKeyUsageAny {
return candidateChains, nil
}
}
for _, candidate := range candidateChains {
if checkChainForKeyUsage(candidate, keyUsages) {
chains = append(chains, candidate)
}
}
if len(chains) == 0 {
return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
}
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
}

View 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

View 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) }

View 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.

View file

@ -21,7 +21,7 @@ import (
// that the C code can also use.
const (
fd = 100
fd = 30
)
func init() {