mirror of https://github.com/golang/go.git
[release-branch.go1.14] all: merge release-branch.go1.14-security into release-branch.go1.14
Change-Id: I32a354618306a72315048c3b5943ed46e1036e25
This commit is contained in:
commit
f1f01bfa33
|
|
@ -16,11 +16,11 @@ import (
|
|||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ import (
|
|||
"go/ast"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"internal/xcoff"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// run runs the command argv, feeding in stdin on standard input.
|
||||
|
|
@ -63,7 +63,7 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
|
|||
p.Env = append(os.Environ(), "TERM=dumb")
|
||||
err := p.Run()
|
||||
if _, ok := err.(*exec.ExitError); err != nil && !ok {
|
||||
fatalf("%s", err)
|
||||
fatalf("exec %s: %s", argv[0], err)
|
||||
}
|
||||
ok = p.ProcessState.Success()
|
||||
stdout, stderr = bout.Bytes(), berr.Bytes()
|
||||
|
|
@ -88,7 +88,7 @@ func fatalf(msg string, args ...interface{}) {
|
|||
// If we've already printed other errors, they might have
|
||||
// caused the fatal condition. Assume they're enough.
|
||||
if nerrors == 0 {
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
fmt.Fprintf(os.Stderr, "cgo: "+msg+"\n", args...)
|
||||
}
|
||||
os.Exit(2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import (
|
|||
"cmd/internal/src"
|
||||
"fmt"
|
||||
"html"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ import (
|
|||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ package main
|
|||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
exec "internal/execabs"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -298,8 +298,10 @@ func bootstrapFixImports(srcFile string) string {
|
|||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
|
||||
inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
|
||||
inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"") || strings.HasPrefix(line, "\texec \"")) {
|
||||
line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
|
||||
// During bootstrap, must use plain os/exec.
|
||||
line = strings.Replace(line, `exec "internal/execabs"`, `"os/exec"`, -1)
|
||||
for _, dir := range bootstrapDirs {
|
||||
if strings.HasPrefix(dir, "cmd/") {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import (
|
|||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@ import (
|
|||
"flag"
|
||||
"fmt"
|
||||
"go/scanner"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ package bug
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
urlpkg "net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ import (
|
|||
"bytes"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import (
|
|||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ package tool
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ type Builder struct {
|
|||
id sync.Mutex
|
||||
toolIDCache map[string]string // tool name -> tool ID
|
||||
buildIDCache map[string]string // file name -> build ID
|
||||
|
||||
cgoEnvOnce sync.Once
|
||||
cgoEnvCache []string
|
||||
}
|
||||
|
||||
// NOTE: Much of Action would not need to be exported if not for test.
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"go/build"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ package work
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"cmd/go/internal/base"
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"internal/lazyregexp"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
|
|
@ -1075,10 +1075,8 @@ func (b *Builder) vet(a *Action) error {
|
|||
return err
|
||||
}
|
||||
|
||||
env := b.cCompilerEnv()
|
||||
if cfg.BuildToolchainName == "gccgo" {
|
||||
env = append(env, "GCCGO="+BuildToolchain.compiler())
|
||||
}
|
||||
// TODO(rsc): Why do we pass $GCCGO to go vet?
|
||||
env := b.cgoEnv()
|
||||
|
||||
p := a.Package
|
||||
tool := VetTool
|
||||
|
|
@ -1920,6 +1918,9 @@ func (b *Builder) runOut(a *Action, dir string, env []string, cmdargs ...interfa
|
|||
|
||||
var buf bytes.Buffer
|
||||
cmd := exec.Command(cmdline[0], cmdline[1:]...)
|
||||
if cmd.Path != "" {
|
||||
cmd.Args[0] = cmd.Path
|
||||
}
|
||||
cmd.Stdout = &buf
|
||||
cmd.Stderr = &buf
|
||||
cleanup := passLongArgsInResponseFiles(cmd)
|
||||
|
|
@ -1979,6 +1980,24 @@ func (b *Builder) cCompilerEnv() []string {
|
|||
return []string{"TERM=dumb"}
|
||||
}
|
||||
|
||||
// cgoEnv returns environment variables to set when running cgo.
|
||||
// Some of these pass through to cgo running the C compiler,
|
||||
// so it includes cCompilerEnv.
|
||||
func (b *Builder) cgoEnv() []string {
|
||||
b.cgoEnvOnce.Do(func() {
|
||||
cc, err := exec.LookPath(b.ccExe()[0])
|
||||
if err != nil || filepath.Base(cc) == cc { // reject relative path
|
||||
cc = "/missing-cc"
|
||||
}
|
||||
gccgo := GccgoBin
|
||||
if filepath.Base(gccgo) == gccgo { // reject relative path
|
||||
gccgo = "/missing-gccgo"
|
||||
}
|
||||
b.cgoEnvCache = append(b.cCompilerEnv(), "CC="+cc, "GCCGO="+gccgo)
|
||||
})
|
||||
return b.cgoEnvCache
|
||||
}
|
||||
|
||||
// mkdir makes the named directory.
|
||||
func (b *Builder) Mkdir(dir string) error {
|
||||
// Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "".
|
||||
|
|
@ -2524,13 +2543,13 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
|||
// along to the host linker. At this point in the code, cgoLDFLAGS
|
||||
// consists of the original $CGO_LDFLAGS (unchecked) and all the
|
||||
// flags put together from source code (checked).
|
||||
cgoenv := b.cCompilerEnv()
|
||||
cgoenv := b.cgoEnv()
|
||||
if len(cgoLDFLAGS) > 0 {
|
||||
flags := make([]string, len(cgoLDFLAGS))
|
||||
for i, f := range cgoLDFLAGS {
|
||||
flags[i] = strconv.Quote(f)
|
||||
}
|
||||
cgoenv = []string{"CGO_LDFLAGS=" + strings.Join(flags, " ")}
|
||||
cgoenv = append(cgoenv, "CGO_LDFLAGS="+strings.Join(flags, " "))
|
||||
}
|
||||
|
||||
if cfg.BuildToolchainName == "gccgo" {
|
||||
|
|
@ -2745,7 +2764,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
|
|||
if p.Standard && p.ImportPath == "runtime/cgo" {
|
||||
cgoflags = []string{"-dynlinker"} // record path to dynamic linker
|
||||
}
|
||||
return b.run(a, p.Dir, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
|
||||
return b.run(a, p.Dir, p.ImportPath, b.cgoEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
|
||||
}
|
||||
|
||||
// Run SWIG on all SWIG input files.
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ package work
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
exec "internal/execabs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
[!cgo] skip
|
||||
|
||||
env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache.
|
||||
[!windows] env PATH=.:$PATH
|
||||
[!windows] chmod 0777 p/gcc p/clang
|
||||
[!windows] exists p/gcc p/clang
|
||||
[windows] exists p/gcc.bat p/clang.bat
|
||||
! exists p/bug.txt
|
||||
go build -x
|
||||
! exists p/bug.txt
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
-- m.go --
|
||||
package m
|
||||
|
||||
import _ "m/p"
|
||||
|
||||
-- p/p.go --
|
||||
package p
|
||||
|
||||
// #define X 1
|
||||
import "C"
|
||||
|
||||
-- p/gcc --
|
||||
#!/bin/sh
|
||||
echo ran gcc >bug.txt
|
||||
-- p/clang --
|
||||
#!/bin/sh
|
||||
echo ran clang >bug.txt
|
||||
-- p/gcc.bat --
|
||||
echo ran gcc >bug.txt
|
||||
-- p/clang.bat --
|
||||
echo ran clang >bug.txt
|
||||
|
|
@ -6,8 +6,8 @@
|
|||
package browser
|
||||
|
||||
import (
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@
|
|||
package diff
|
||||
|
||||
import (
|
||||
exec "internal/execabs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"cmd/internal/objabi"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
exec "internal/execabs"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
package ld
|
||||
|
||||
import (
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ import (
|
|||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"cmd/internal/test2json"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ package main
|
|||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
exec "internal/execabs"
|
||||
"internal/trace"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
|
|
|
|||
|
|
@ -386,10 +386,11 @@ func p224Invert(out, in *p224FieldElement) {
|
|||
// p224Contract converts a FieldElement to its unique, minimal form.
|
||||
//
|
||||
// On entry, in[i] < 2**29
|
||||
// On exit, in[i] < 2**28
|
||||
// On exit, out[i] < 2**28 and out < p
|
||||
func p224Contract(out, in *p224FieldElement) {
|
||||
copy(out[:], in[:])
|
||||
|
||||
// First, carry the bits above 28 to the higher limb.
|
||||
for i := 0; i < 7; i++ {
|
||||
out[i+1] += out[i] >> 28
|
||||
out[i] &= bottom28Bits
|
||||
|
|
@ -397,10 +398,13 @@ func p224Contract(out, in *p224FieldElement) {
|
|||
top := out[7] >> 28
|
||||
out[7] &= bottom28Bits
|
||||
|
||||
// Use the reduction identity to carry the overflow.
|
||||
//
|
||||
// a + top * 2²²⁴ = a + top * 2⁹⁶ - top
|
||||
out[0] -= top
|
||||
out[3] += top << 12
|
||||
|
||||
// We may just have made out[i] negative. So we carry down. If we made
|
||||
// We may just have made out[0] negative. So we carry down. If we made
|
||||
// out[0] negative then we know that out[3] is sufficiently positive
|
||||
// because we just added to it.
|
||||
for i := 0; i < 3; i++ {
|
||||
|
|
@ -425,13 +429,12 @@ func p224Contract(out, in *p224FieldElement) {
|
|||
// There are two cases to consider for out[3]:
|
||||
// 1) The first time that we eliminated top, we didn't push out[3] over
|
||||
// 2**28. In this case, the partial carry chain didn't change any values
|
||||
// and top is zero.
|
||||
// and top is now zero.
|
||||
// 2) We did push out[3] over 2**28 the first time that we eliminated top.
|
||||
// The first value of top was in [0..16), therefore, prior to eliminating
|
||||
// the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after
|
||||
// overflowing and being reduced by the second carry chain, out[3] <=
|
||||
// 0xf000. Thus it cannot have overflowed when we eliminated top for the
|
||||
// second time.
|
||||
// The first value of top was in [0..2], therefore, after overflowing
|
||||
// and being reduced by the second carry chain, out[3] <= 2<<12 - 1.
|
||||
// In both cases, out[3] cannot have overflowed when we eliminated top for
|
||||
// the second time.
|
||||
|
||||
// Again, we may just have made out[0] negative, so do the same carry down.
|
||||
// As before, if we made out[0] negative then we know that out[3] is
|
||||
|
|
@ -470,12 +473,11 @@ func p224Contract(out, in *p224FieldElement) {
|
|||
bottom3NonZero |= bottom3NonZero >> 1
|
||||
bottom3NonZero = uint32(int32(bottom3NonZero<<31) >> 31)
|
||||
|
||||
// Everything depends on the value of out[3].
|
||||
// If it's > 0xffff000 and top4AllOnes != 0 then the whole value is >= p
|
||||
// If it's = 0xffff000 and top4AllOnes != 0 and bottom3NonZero != 0,
|
||||
// then the whole value is >= p
|
||||
// Assuming top4AllOnes != 0, everything depends on the value of out[3].
|
||||
// If it's > 0xffff000 then the whole value is > p
|
||||
// If it's = 0xffff000 and bottom3NonZero != 0, then the whole value is >= p
|
||||
// If it's < 0xffff000, then the whole value is < p
|
||||
n := out[3] - 0xffff000
|
||||
n := 0xffff000 - out[3]
|
||||
out3Equal := n
|
||||
out3Equal |= out3Equal >> 16
|
||||
out3Equal |= out3Equal >> 8
|
||||
|
|
@ -484,8 +486,8 @@ func p224Contract(out, in *p224FieldElement) {
|
|||
out3Equal |= out3Equal >> 1
|
||||
out3Equal = ^uint32(int32(out3Equal<<31) >> 31)
|
||||
|
||||
// If out[3] > 0xffff000 then n's MSB will be zero.
|
||||
out3GT := ^uint32(int32(n) >> 31)
|
||||
// If out[3] > 0xffff000 then n's MSB will be one.
|
||||
out3GT := uint32(int32(n) >> 31)
|
||||
|
||||
mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)
|
||||
out[0] -= 1 & mask
|
||||
|
|
@ -494,6 +496,15 @@ func p224Contract(out, in *p224FieldElement) {
|
|||
out[5] -= 0xfffffff & mask
|
||||
out[6] -= 0xfffffff & mask
|
||||
out[7] -= 0xfffffff & mask
|
||||
|
||||
// Do one final carry down, in case we made out[0] negative. One of
|
||||
// out[0..3] needs to be positive and able to absorb the -1 or the value
|
||||
// would have been < p, and the subtraction wouldn't have happened.
|
||||
for i := 0; i < 3; i++ {
|
||||
mask := uint32(int32(out[i]) >> 31)
|
||||
out[i] += (1 << 28) & mask
|
||||
out[i+1] -= 1 & mask
|
||||
}
|
||||
}
|
||||
|
||||
// Group element functions.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,11 @@ package elliptic
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"math/bits"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
)
|
||||
|
||||
var toFromBigTests = []string{
|
||||
|
|
@ -21,16 +25,16 @@ func p224AlternativeToBig(in *p224FieldElement) *big.Int {
|
|||
ret := new(big.Int)
|
||||
tmp := new(big.Int)
|
||||
|
||||
for i := uint(0); i < 8; i++ {
|
||||
for i := len(in) - 1; i >= 0; i-- {
|
||||
ret.Lsh(ret, 28)
|
||||
tmp.SetInt64(int64(in[i]))
|
||||
tmp.Lsh(tmp, 28*i)
|
||||
ret.Add(ret, tmp)
|
||||
}
|
||||
ret.Mod(ret, p224.P)
|
||||
ret.Mod(ret, P224().Params().P)
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestToFromBig(t *testing.T) {
|
||||
func TestP224ToFromBig(t *testing.T) {
|
||||
for i, test := range toFromBigTests {
|
||||
n, _ := new(big.Int).SetString(test, 16)
|
||||
var x p224FieldElement
|
||||
|
|
@ -41,7 +45,270 @@ func TestToFromBig(t *testing.T) {
|
|||
}
|
||||
q := p224AlternativeToBig(&x)
|
||||
if n.Cmp(q) != 0 {
|
||||
t.Errorf("#%d: %x != %x (alternative)", i, n, m)
|
||||
t.Errorf("#%d: %x != %x (alternative)", i, n, q)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// quickCheckConfig32 will make each quickcheck test run (32 * -quickchecks)
|
||||
// times. The default value of -quickchecks is 100.
|
||||
var quickCheckConfig32 = &quick.Config{MaxCountScale: 32}
|
||||
|
||||
// weirdLimbs can be combined to generate a range of edge-case field elements.
|
||||
var weirdLimbs = [...]uint32{
|
||||
0, 1, (1 << 29) - 1,
|
||||
(1 << 12), (1 << 12) - 1,
|
||||
(1 << 28), (1 << 28) - 1,
|
||||
}
|
||||
|
||||
func generateLimb(rand *rand.Rand) uint32 {
|
||||
const bottom29Bits = 0x1fffffff
|
||||
n := rand.Intn(len(weirdLimbs) + 3)
|
||||
switch n {
|
||||
case len(weirdLimbs):
|
||||
// Random value.
|
||||
return uint32(rand.Int31n(1 << 29))
|
||||
case len(weirdLimbs) + 1:
|
||||
// Sum of two values.
|
||||
k := generateLimb(rand) + generateLimb(rand)
|
||||
return k & bottom29Bits
|
||||
case len(weirdLimbs) + 2:
|
||||
// Difference of two values.
|
||||
k := generateLimb(rand) - generateLimb(rand)
|
||||
return k & bottom29Bits
|
||||
default:
|
||||
return weirdLimbs[n]
|
||||
}
|
||||
}
|
||||
|
||||
func (p224FieldElement) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
return reflect.ValueOf(p224FieldElement{
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
weirdLimbs[rand.Intn(len(weirdLimbs))],
|
||||
})
|
||||
}
|
||||
|
||||
func isInBounds(x *p224FieldElement) bool {
|
||||
return bits.Len32(x[0]) <= 29 &&
|
||||
bits.Len32(x[1]) <= 29 &&
|
||||
bits.Len32(x[2]) <= 29 &&
|
||||
bits.Len32(x[3]) <= 29 &&
|
||||
bits.Len32(x[4]) <= 29 &&
|
||||
bits.Len32(x[5]) <= 29 &&
|
||||
bits.Len32(x[6]) <= 29 &&
|
||||
bits.Len32(x[7]) <= 29
|
||||
}
|
||||
|
||||
func TestP224Mul(t *testing.T) {
|
||||
mulMatchesBigInt := func(a, b, out p224FieldElement) bool {
|
||||
var tmp p224LargeFieldElement
|
||||
p224Mul(&out, &a, &b, &tmp)
|
||||
|
||||
exp := new(big.Int).Mul(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
|
||||
exp.Mod(exp, P224().Params().P)
|
||||
got := p224AlternativeToBig(&out)
|
||||
if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||
t.Logf("a = %x", a)
|
||||
t.Logf("b = %x", b)
|
||||
t.Logf("p224Mul(a, b) = %x = %v", out, got)
|
||||
t.Logf("a * b = %v", exp)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
a := p224FieldElement{0xfffffff, 0xfffffff, 0xf00ffff, 0x20f, 0x0, 0x0, 0x0, 0x0}
|
||||
b := p224FieldElement{1, 0, 0, 0, 0, 0, 0, 0}
|
||||
if !mulMatchesBigInt(a, b, p224FieldElement{}) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if err := quick.Check(mulMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP224Square(t *testing.T) {
|
||||
squareMatchesBigInt := func(a, out p224FieldElement) bool {
|
||||
var tmp p224LargeFieldElement
|
||||
p224Square(&out, &a, &tmp)
|
||||
|
||||
exp := p224AlternativeToBig(&a)
|
||||
exp.Mul(exp, exp)
|
||||
exp.Mod(exp, P224().Params().P)
|
||||
got := p224AlternativeToBig(&out)
|
||||
if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||
t.Logf("a = %x", a)
|
||||
t.Logf("p224Square(a, b) = %x = %v", out, got)
|
||||
t.Logf("a * a = %v", exp)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(squareMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP224Add(t *testing.T) {
|
||||
addMatchesBigInt := func(a, b, out p224FieldElement) bool {
|
||||
p224Add(&out, &a, &b)
|
||||
|
||||
exp := new(big.Int).Add(p224AlternativeToBig(&a), p224AlternativeToBig(&b))
|
||||
exp.Mod(exp, P224().Params().P)
|
||||
got := p224AlternativeToBig(&out)
|
||||
if exp.Cmp(got) != 0 {
|
||||
t.Logf("a = %x", a)
|
||||
t.Logf("b = %x", b)
|
||||
t.Logf("p224Add(a, b) = %x = %v", out, got)
|
||||
t.Logf("a + b = %v", exp)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(addMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP224Reduce(t *testing.T) {
|
||||
reduceMatchesBigInt := func(a p224FieldElement) bool {
|
||||
out := a
|
||||
// TODO: generate higher values for functions like p224Reduce that are
|
||||
// expected to work with higher input bounds.
|
||||
p224Reduce(&out)
|
||||
|
||||
exp := p224AlternativeToBig(&a)
|
||||
got := p224AlternativeToBig(&out)
|
||||
if exp.Cmp(got) != 0 || !isInBounds(&out) {
|
||||
t.Logf("a = %x = %v", a, exp)
|
||||
t.Logf("p224Reduce(a) = %x = %v", out, got)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(reduceMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP224Contract(t *testing.T) {
|
||||
contractMatchesBigInt := func(a, out p224FieldElement) bool {
|
||||
p224Contract(&out, &a)
|
||||
|
||||
exp := p224AlternativeToBig(&a)
|
||||
got := p224AlternativeToBig(&out)
|
||||
if exp.Cmp(got) != 0 {
|
||||
t.Logf("a = %x = %v", a, exp)
|
||||
t.Logf("p224Contract(a) = %x = %v", out, got)
|
||||
return false
|
||||
}
|
||||
|
||||
// Check that out < P.
|
||||
for i := range p224P {
|
||||
k := 8 - i - 1
|
||||
if out[k] > p224P[k] {
|
||||
t.Logf("p224Contract(a) = %x", out)
|
||||
return false
|
||||
}
|
||||
if out[k] < p224P[k] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
t.Logf("p224Contract(a) = %x", out)
|
||||
return false
|
||||
}
|
||||
|
||||
if !contractMatchesBigInt(p224P, p224FieldElement{}) {
|
||||
t.Error("p224Contract(p) is broken")
|
||||
}
|
||||
pMinus1 := p224FieldElement{0, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||
if !contractMatchesBigInt(pMinus1, p224FieldElement{}) {
|
||||
t.Error("p224Contract(p - 1) is broken")
|
||||
}
|
||||
// Check that we can handle input above p, but lowest limb zero.
|
||||
a := p224FieldElement{0, 1, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||
if !contractMatchesBigInt(a, p224FieldElement{}) {
|
||||
t.Error("p224Contract(p + 2²⁸) is broken")
|
||||
}
|
||||
// Check that we can handle input above p, but lowest three limbs zero.
|
||||
b := p224FieldElement{0, 0, 0, 0xffff001, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff}
|
||||
if !contractMatchesBigInt(b, p224FieldElement{}) {
|
||||
t.Error("p224Contract(p + 2⁸⁴) is broken")
|
||||
}
|
||||
|
||||
if err := quick.Check(contractMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP224IsZero(t *testing.T) {
|
||||
if got := p224IsZero(&p224FieldElement{}); got != 1 {
|
||||
t.Errorf("p224IsZero(0) = %d, expected 1", got)
|
||||
}
|
||||
if got := p224IsZero((*p224FieldElement)(&p224P)); got != 1 {
|
||||
t.Errorf("p224IsZero(p) = %d, expected 1", got)
|
||||
}
|
||||
if got := p224IsZero(&p224FieldElement{1}); got != 0 {
|
||||
t.Errorf("p224IsZero(1) = %d, expected 0", got)
|
||||
}
|
||||
|
||||
isZeroMatchesBigInt := func(a p224FieldElement) bool {
|
||||
isZero := p224IsZero(&a)
|
||||
|
||||
big := p224AlternativeToBig(&a)
|
||||
if big.Sign() == 0 && isZero != 1 {
|
||||
return false
|
||||
}
|
||||
if big.Sign() != 0 && isZero != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if err := quick.Check(isZeroMatchesBigInt, quickCheckConfig32); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP224Invert(t *testing.T) {
|
||||
var out p224FieldElement
|
||||
|
||||
p224Invert(&out, &p224FieldElement{})
|
||||
if got := p224IsZero(&out); got != 1 {
|
||||
t.Errorf("p224Invert(0) = %x, expected 0", out)
|
||||
}
|
||||
|
||||
p224Invert(&out, (*p224FieldElement)(&p224P))
|
||||
if got := p224IsZero(&out); got != 1 {
|
||||
t.Errorf("p224Invert(p) = %x, expected 0", out)
|
||||
}
|
||||
|
||||
p224Invert(&out, &p224FieldElement{1})
|
||||
p224Contract(&out, &out)
|
||||
if out != (p224FieldElement{1}) {
|
||||
t.Errorf("p224Invert(1) = %x, expected 1", out)
|
||||
}
|
||||
|
||||
var tmp p224LargeFieldElement
|
||||
a := p224FieldElement{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
p224Invert(&out, &a)
|
||||
p224Mul(&out, &out, &a, &tmp)
|
||||
p224Contract(&out, &out)
|
||||
if out != (p224FieldElement{1}) {
|
||||
t.Errorf("p224Invert(a) * a = %x, expected 1", out)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,13 +12,13 @@ import (
|
|||
"go/doc"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
exec "internal/execabs"
|
||||
"internal/goroot"
|
||||
"internal/goversion"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
pathpkg "path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
|
|
|||
|
|
@ -207,6 +207,8 @@ var pkgDeps = map[string][]string{
|
|||
"internal/lazyregexp": {"L2", "OS", "regexp"},
|
||||
"internal/lazytemplate": {"L2", "OS", "text/template"},
|
||||
|
||||
"internal/execabs": {"L2", "OS", "fmt", "context", "reflect"},
|
||||
|
||||
// L4 is defined as L3+fmt+log+time, because in general once
|
||||
// you're using L3 packages, use of fmt, log, or time is not a big deal.
|
||||
"L4": {
|
||||
|
|
@ -240,7 +242,7 @@ var pkgDeps = map[string][]string{
|
|||
"go/constant": {"L4", "go/token", "math/big"},
|
||||
"go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
|
||||
"go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
|
||||
"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "internal/xcoff", "text/scanner"},
|
||||
"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "internal/xcoff", "text/scanner", "internal/execabs"},
|
||||
"go/internal/srcimporter": {"L4", "OS", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
|
||||
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
|
||||
|
||||
|
|
@ -272,7 +274,7 @@ var pkgDeps = map[string][]string{
|
|||
"encoding/pem": {"L4"},
|
||||
"encoding/xml": {"L4", "encoding"},
|
||||
"flag": {"L4", "OS"},
|
||||
"go/build": {"L4", "OS", "GOPARSER", "internal/goroot", "internal/goversion"},
|
||||
"go/build": {"L4", "OS", "GOPARSER", "internal/goroot", "internal/goversion", "internal/execabs"},
|
||||
"html": {"L4"},
|
||||
"image/draw": {"L4", "image/internal/imageutil"},
|
||||
"image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
|
||||
|
|
@ -280,7 +282,7 @@ var pkgDeps = map[string][]string{
|
|||
"image/jpeg": {"L4", "image/internal/imageutil"},
|
||||
"image/png": {"L4", "compress/zlib"},
|
||||
"index/suffixarray": {"L4", "regexp"},
|
||||
"internal/goroot": {"L4", "OS"},
|
||||
"internal/goroot": {"L4", "OS", "internal/execabs"},
|
||||
"internal/singleflight": {"sync"},
|
||||
"internal/trace": {"L4", "OS", "container/heap"},
|
||||
"internal/xcoff": {"L4", "OS", "debug/dwarf"},
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ package gccgoimporter
|
|||
import (
|
||||
"bufio"
|
||||
"go/types"
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2020 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 execabs is a drop-in replacement for os/exec
|
||||
// that requires PATH lookups to find absolute paths.
|
||||
// That is, execabs.Command("cmd") runs the same PATH lookup
|
||||
// as exec.Command("cmd"), but if the result is a path
|
||||
// which is relative, the Run and Start methods will report
|
||||
// an error instead of running the executable.
|
||||
package execabs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var ErrNotFound = exec.ErrNotFound
|
||||
|
||||
type (
|
||||
Cmd = exec.Cmd
|
||||
Error = exec.Error
|
||||
ExitError = exec.ExitError
|
||||
)
|
||||
|
||||
func relError(file, path string) error {
|
||||
return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path)
|
||||
}
|
||||
|
||||
func LookPath(file string) (string, error) {
|
||||
path, err := exec.LookPath(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if filepath.Base(file) == file && !filepath.IsAbs(path) {
|
||||
return "", relError(file, path)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func fixCmd(name string, cmd *exec.Cmd) {
|
||||
if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) {
|
||||
// exec.Command was called with a bare binary name and
|
||||
// exec.LookPath returned a path which is not absolute.
|
||||
// Set cmd.lookPathErr and clear cmd.Path so that it
|
||||
// cannot be run.
|
||||
lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer()))
|
||||
if *lookPathErr == nil {
|
||||
*lookPathErr = relError(name, cmd.Path)
|
||||
}
|
||||
cmd.Path = ""
|
||||
}
|
||||
}
|
||||
|
||||
func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd {
|
||||
cmd := exec.CommandContext(ctx, name, arg...)
|
||||
fixCmd(name, cmd)
|
||||
return cmd
|
||||
|
||||
}
|
||||
|
||||
func Command(name string, arg ...string) *exec.Cmd {
|
||||
cmd := exec.Command(name, arg...)
|
||||
fixCmd(name, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2020 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 execabs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFixCmd(t *testing.T) {
|
||||
cmd := &exec.Cmd{Path: "hello"}
|
||||
fixCmd("hello", cmd)
|
||||
if cmd.Path != "" {
|
||||
t.Errorf("fixCmd didn't clear cmd.Path")
|
||||
}
|
||||
expectedErr := fmt.Sprintf("hello resolves to executable in current directory (.%chello)", filepath.Separator)
|
||||
if err := cmd.Run(); err == nil {
|
||||
t.Fatal("Command.Run didn't fail")
|
||||
} else if err.Error() != expectedErr {
|
||||
t.Fatalf("Command.Run returned unexpected error: want %q, got %q", expectedErr, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
for _, cmd := range []func(string) *Cmd{
|
||||
func(s string) *Cmd { return Command(s) },
|
||||
func(s string) *Cmd { return CommandContext(context.Background(), s) },
|
||||
} {
|
||||
tmpDir, err := ioutil.TempDir("", "execabs-test")
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.TempDir failed: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
executable := "execabs-test"
|
||||
if runtime.GOOS == "windows" {
|
||||
executable += ".exe"
|
||||
}
|
||||
if err = ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil {
|
||||
t.Fatalf("ioutil.WriteFile failed: %s", err)
|
||||
}
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("os.Getwd failed: %s", err)
|
||||
}
|
||||
defer os.Chdir(cwd)
|
||||
if err = os.Chdir(tmpDir); err != nil {
|
||||
t.Fatalf("os.Chdir failed: %s", err)
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
// add "." to PATH so that exec.LookPath looks in the current directory on
|
||||
// non-windows platforms as well
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
os.Setenv("PATH", fmt.Sprintf(".:%s", origPath))
|
||||
}
|
||||
expectedErr := fmt.Sprintf("execabs-test resolves to executable in current directory (.%c%s)", filepath.Separator, executable)
|
||||
if err = cmd("execabs-test").Run(); err == nil {
|
||||
t.Fatalf("Command.Run didn't fail when exec.LookPath returned a relative path")
|
||||
} else if err.Error() != expectedErr {
|
||||
t.Errorf("Command.Run returned unexpected error: want %q, got %q", expectedErr, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookPath(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "execabs-test")
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.TempDir failed: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
executable := "execabs-test"
|
||||
if runtime.GOOS == "windows" {
|
||||
executable += ".exe"
|
||||
}
|
||||
if err = ioutil.WriteFile(filepath.Join(tmpDir, executable), []byte{1, 2, 3}, 0111); err != nil {
|
||||
t.Fatalf("ioutil.WriteFile failed: %s", err)
|
||||
}
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatalf("os.Getwd failed: %s", err)
|
||||
}
|
||||
defer os.Chdir(cwd)
|
||||
if err = os.Chdir(tmpDir); err != nil {
|
||||
t.Fatalf("os.Chdir failed: %s", err)
|
||||
}
|
||||
if runtime.GOOS != "windows" {
|
||||
// add "." to PATH so that exec.LookPath looks in the current directory on
|
||||
// non-windows platforms as well
|
||||
origPath := os.Getenv("PATH")
|
||||
defer os.Setenv("PATH", origPath)
|
||||
os.Setenv("PATH", fmt.Sprintf(".:%s", origPath))
|
||||
}
|
||||
expectedErr := fmt.Sprintf("execabs-test resolves to executable in current directory (.%c%s)", filepath.Separator, executable)
|
||||
if _, err := LookPath("execabs-test"); err == nil {
|
||||
t.Fatalf("LookPath didn't fail when finding a non-relative path")
|
||||
} else if err.Error() != expectedErr {
|
||||
t.Errorf("LookPath returned unexpected error: want %q, got %q", expectedErr, err.Error())
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@
|
|||
package goroot
|
||||
|
||||
import (
|
||||
exec "internal/execabs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
|
|||
Loading…
Reference in New Issue