mirror of
https://github.com/golang/go.git
synced 2026-01-29 15:12:08 +03:00
Compare commits
31 Commits
dev.typeal
...
release-br
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
357c914136 | ||
|
|
9574ce9cf6 | ||
|
|
44821583bc | ||
|
|
96c72e9468 | ||
|
|
89e6a4d6d0 | ||
|
|
a5a3be1636 | ||
|
|
45a42c9be5 | ||
|
|
6c733cd93b | ||
|
|
d4ccbd8833 | ||
|
|
79be6cb389 | ||
|
|
b838f943ab | ||
|
|
3be9637d56 | ||
|
|
2eac89d5c8 | ||
|
|
142d449081 | ||
|
|
533ee44cd4 | ||
|
|
8093678ae1 | ||
|
|
0bf8909ff8 | ||
|
|
b3b1e12b13 | ||
|
|
1ab2a4e85f | ||
|
|
25be91ae4f | ||
|
|
82cfda2910 | ||
|
|
9ccc2921dd | ||
|
|
ead964dc80 | ||
|
|
7e9658fea9 | ||
|
|
7e2cd1d81e | ||
|
|
f5bcb9b8fe | ||
|
|
4be3fc33ef | ||
|
|
a4544a0f8a | ||
|
|
9d1d78c34c | ||
|
|
d45b26b1b7 | ||
|
|
f3e6216450 |
@@ -63,6 +63,36 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.3">Go
|
||||
1.8.3 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.4 (released 2017/10/04) includes two security fixes.
|
||||
It contains the same fixes as Go 1.9.1 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.4">Go
|
||||
1.8.4 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.5 (released 2017/10/25) includes fixes to the compiler, linker, runtime,
|
||||
documentation, <code>go</code> command,
|
||||
and the <code>crypto/x509</code> and <code>net/smtp</code> packages.
|
||||
It includes a fix to a bug introduced in Go 1.8.4 that broke <code>go</code> <code>get</code>
|
||||
of non-Git repositories under certain conditions.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.5">Go
|
||||
1.8.5 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.6 (released 2018/01/22) includes the the same fix in <code>math/big</code>
|
||||
as Go 1.9.3 and was released at the same time.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.6">Go
|
||||
1.8.6 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
go1.8.7 (released 2018/02/07) includes a security fix to “go get”.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.8.7">Go
|
||||
1.8.7</a> milestone on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
This file lists things yet to be moved into go1.8.html or deemed too
|
||||
minor to mention. Either way, delete from here when done.
|
||||
|
||||
Tools:
|
||||
|
||||
go: -buildmode=c-archive now builds PIC on ELF (CL 24180)
|
||||
go: mobile pkg dir change, recommend using go list in scripts (CL 24930, CL 27929)
|
||||
go, dist: can set default pkg-config tool using PKG_CONFIG env var (CL 29991)
|
||||
go: can set secure/insecure GIT schemes using GIT_ALLOW_PROTOCOL env var (CL 30135)
|
||||
|
||||
API additions and behavior changes:
|
||||
|
||||
cmd/compile, runtime, etc: get rid of constant FP registers (CL 28095)
|
||||
cmd/compile, runtime: add go:yeswritebarrierrec pragma (CL 30938)
|
||||
cmd/compile/internal/gc: enable new parser by default (CL 27203)
|
||||
cmd/compile/internal/syntax: fast Go syntax trees, initial commit (CL 27195)
|
||||
cmd/compile: add compiler phase timing (CL 24462)
|
||||
cmd/compile: add inline explainer (CL 22782)
|
||||
cmd/compile: enable flag-specified dump of specific phase+function (CL 23044)
|
||||
|
||||
cmd/internal/obj, cmd/link: darwin dynlink support (CL 29393)
|
||||
cmd/internal/objfile: add ppc64/ppc64le disassembler support (CL 9682)
|
||||
cmd/link, cmd/go: delay linking of mingwex and mingw32 until very end (CL 26670)
|
||||
cmd/link: R_ADDR dynamic relocs for internal PIE (CL 29118)
|
||||
cmd/link: add trampolines for too far calls in ppc64x (CL 30850)
|
||||
cmd/link: allow internal PIE linking (CL 28543)
|
||||
cmd/link: fix -X importpath.name=value when import path needs escaping (CL 31970)
|
||||
cmd/link: fix -buildmode=pie / -linkshared combination (CL 28996)
|
||||
cmd/link: for -buildmode=exe pass -no-pie to external linker (CL 33106)
|
||||
cmd/link: insert trampolines for too-far jumps on ARM (CL 29397)
|
||||
cmd/link: non-executable stack support for Solaris (CL 24142)
|
||||
cmd/link: put text at address 0x1000000 on darwin/amd64 (CL 32185)
|
||||
cmd/link: remove the -shared flag (CL 28852)
|
||||
cmd/link: split large elf text sections on ppc64x (CL 27790)
|
||||
cmd/link: trampoline support for external linking on ARM (CL 31143)
|
||||
cmd/objdump: implement objdump of .o files (CL 24818)
|
||||
|
||||
go/build: allow % in ${SRCDIR} expansion for Jenkins (CL 31611)
|
||||
go/build: do not record go:binary-only-package if build tags not satisfied (CL 31577)
|
||||
go/build: implement default GOPATH (CL 32019)
|
||||
|
||||
runtime/race: update race runtime (CL 32160)
|
||||
runtime: assume 64kB physical pages on ARM (CL 25021)
|
||||
runtime: disable stack rescanning by default (CL 31766)
|
||||
runtime: don't call cgocallback from signal handler (CL 30218)
|
||||
runtime: fix check for vacuous page boundary rounding (CL 27230)
|
||||
runtime: fix map iterator concurrent map check (CL 24749)
|
||||
runtime: fix newextram PC passed to race detector (CL 29712)
|
||||
runtime: implement unconditional hybrid barrier (CL 31765)
|
||||
runtime: include pre-panic/throw logs in core dumps (CL 32013)
|
||||
runtime: limit the number of map overflow buckets (CL 25049)
|
||||
runtime: pass windows float syscall args via XMM (CL 32173)
|
||||
runtime: print sigcode on signal crash (CL 32183)
|
||||
runtime: record current PC for SIGPROF on non-Go thread (CL 30252)
|
||||
runtime: sleep on CLOCK_MONOTONIC in futexsleep1 on freebsd (CL 30154)
|
||||
@@ -143,7 +143,7 @@ packaged Go distribution.
|
||||
<p>
|
||||
To build a bootstrap tool chain from source, use
|
||||
either the git branch <code>release-branch.go1.4</code> or
|
||||
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20161024.tar.gz">go1.4-bootstrap-20161024.tar.gz</a>,
|
||||
<a href="https://storage.googleapis.com/golang/go1.4-bootstrap-20170531.tar.gz">go1.4-bootstrap-20170531.tar.gz</a>,
|
||||
which contains the Go 1.4 source code plus accumulated fixes
|
||||
to keep the tools running on newer operating systems.
|
||||
(Go 1.4 was the last distribution in which the tool chain was written in C.)
|
||||
|
||||
144
doc/root.html
144
doc/root.html
@@ -6,7 +6,9 @@
|
||||
<div class="left">
|
||||
|
||||
<div id="learn">
|
||||
{{if not $.GoogleCN}}
|
||||
<a class="popout share">Pop-out</a>
|
||||
{{end}}
|
||||
<div class="rootHeading">Try Go</div>
|
||||
<div class="input">
|
||||
<textarea spellcheck="false" class="code">// You can edit this code!
|
||||
@@ -26,10 +28,10 @@ Hello, 世界
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<a class="run" href="#" title="Run this code [shift-enter]">Run</a>
|
||||
{{if $.Share}}
|
||||
{{if not $.GoogleCN}}
|
||||
<a class="share" href="#" title="Share this code">Share</a>
|
||||
{{end}}
|
||||
<a class="tour" href="//tour.golang.org/" title="Learn Go from your browser">Tour</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="toys">
|
||||
<select>
|
||||
@@ -68,85 +70,91 @@ Linux, Mac OS X, Windows, and more.
|
||||
|
||||
<div style="clear: both"></div>
|
||||
|
||||
{{if not $.GoogleCN}}
|
||||
<div class="left">
|
||||
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<div id="video">
|
||||
<div class="rootHeading">Featured video</div>
|
||||
<iframe width="415" height="241" src="//www.youtube.com/embed/ytEkHepK08c" frameborder="0" allowfullscreen></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
|
||||
<div id="blog">
|
||||
<div class="rootHeading">Featured articles</div>
|
||||
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
|
||||
</div>
|
||||
|
||||
<div id="blog">
|
||||
<div class="rootHeading">Featured articles</div>
|
||||
<div class="read"><a href="//blog.golang.org/">Read more</a></div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div style="clear: both;"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
<script>
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function readableTime(t) {
|
||||
var m = ["January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"];
|
||||
var p = t.substring(0, t.indexOf("T")).split("-");
|
||||
var d = new Date(p[0], p[1]-1, p[2]);
|
||||
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
|
||||
}
|
||||
window.initFuncs.push(function() {
|
||||
// Set up playground if enabled.
|
||||
if (window.playground) {
|
||||
window.playground({
|
||||
"codeEl": "#learn .code",
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "//play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
} else {
|
||||
$('#learn').hide()
|
||||
}
|
||||
});
|
||||
|
||||
function feedLoaded(result) {
|
||||
var blog = document.getElementById("blog");
|
||||
var read = blog.getElementsByClassName("read")[0];
|
||||
for (var i = 0; i < result.length && i < 2; i++) {
|
||||
var entry = result[i];
|
||||
var title = document.createElement("a");
|
||||
title.className = "title";
|
||||
title.href = entry.Link;
|
||||
title.innerHTML = entry.Title;
|
||||
blog.insertBefore(title, read);
|
||||
var extract = document.createElement("div");
|
||||
extract.className = "extract";
|
||||
extract.innerHTML = entry.Summary;
|
||||
blog.insertBefore(extract, read);
|
||||
var when = document.createElement("div");
|
||||
when.className = "when";
|
||||
when.innerHTML = "Published " + readableTime(entry.Time);
|
||||
blog.insertBefore(when, read);
|
||||
}
|
||||
}
|
||||
{{if not $.GoogleCN}}
|
||||
|
||||
window.initFuncs.push(function() {
|
||||
// Set up playground if enabled.
|
||||
if (window.playground) {
|
||||
window.playground({
|
||||
"codeEl": "#learn .code",
|
||||
"outputEl": "#learn .output",
|
||||
"runEl": "#learn .run",
|
||||
"shareEl": "#learn .share",
|
||||
"shareRedirect": "//play.golang.org/p/",
|
||||
"toysEl": "#learn .toys select"
|
||||
});
|
||||
} else {
|
||||
$('#learn').hide()
|
||||
function readableTime(t) {
|
||||
var m = ["January", "February", "March", "April", "May", "June", "July",
|
||||
"August", "September", "October", "November", "December"];
|
||||
var p = t.substring(0, t.indexOf("T")).split("-");
|
||||
var d = new Date(p[0], p[1]-1, p[2]);
|
||||
return d.getDate() + " " + m[d.getMonth()] + " " + d.getFullYear();
|
||||
}
|
||||
|
||||
// Load blog feed.
|
||||
$('<script/>').attr('text', 'text/javascript')
|
||||
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
|
||||
.appendTo('body');
|
||||
window.feedLoaded = function(result) {
|
||||
var blog = document.getElementById("blog");
|
||||
var read = blog.getElementsByClassName("read")[0];
|
||||
for (var i = 0; i < result.length && i < 2; i++) {
|
||||
var entry = result[i];
|
||||
var title = document.createElement("a");
|
||||
title.className = "title";
|
||||
title.href = entry.Link;
|
||||
title.innerHTML = entry.Title;
|
||||
blog.insertBefore(title, read);
|
||||
var extract = document.createElement("div");
|
||||
extract.className = "extract";
|
||||
extract.innerHTML = entry.Summary;
|
||||
blog.insertBefore(extract, read);
|
||||
var when = document.createElement("div");
|
||||
when.className = "when";
|
||||
when.innerHTML = "Published " + readableTime(entry.Time);
|
||||
blog.insertBefore(when, read);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the video at random.
|
||||
var videos = [
|
||||
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
|
||||
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
|
||||
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
});
|
||||
window.initFuncs.push(function() {
|
||||
// Load blog feed.
|
||||
$('<script/>').attr('text', 'text/javascript')
|
||||
.attr('src', '//blog.golang.org/.json?jsonp=feedLoaded')
|
||||
.appendTo('body');
|
||||
|
||||
// Set the video at random.
|
||||
var videos = [
|
||||
{h: 241, s: "//www.youtube.com/embed/ytEkHepK08c"}, // Tour of Go
|
||||
{h: 241, s: "//www.youtube.com/embed/f6kdp27TYZs"}, // Concurrency Patterns
|
||||
{h: 233, s: "//player.vimeo.com/video/69237265"} // Simple environment
|
||||
];
|
||||
var v = videos[Math.floor(Math.random()*videos.length)];
|
||||
$('#video iframe').attr('height', v.h).attr('src', v.s);
|
||||
});
|
||||
|
||||
{{end}}
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
package main
|
||||
|
||||
/*
|
||||
#cgo LDFLAGS: -c
|
||||
#cgo LDFLAGS: -L/nonexist
|
||||
|
||||
void test() {
|
||||
xxx; // ERROR HERE
|
||||
|
||||
@@ -55,11 +55,21 @@ For example:
|
||||
|
||||
The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
|
||||
|
||||
For security reasons, only a limited set of flags are allowed, notably -D, -I, and -l.
|
||||
To allow additional flags, set CGO_CFLAGS_ALLOW to a regular expression
|
||||
matching the new flags. To disallow flags that would otherwise be allowed,
|
||||
set CGO_CFLAGS_DISALLOW to a regular expression matching arguments
|
||||
that must be disallowed. In both cases the regular expression must match
|
||||
a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
|
||||
not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
|
||||
the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
|
||||
|
||||
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
|
||||
CGO_LDFLAGS environment variables are added to the flags derived from
|
||||
these directives. Package-specific flags should be set using the
|
||||
directives, not the environment variables, so that builds work in
|
||||
unmodified environments.
|
||||
unmodified environments. Flags obtained from environment variables
|
||||
are not subject to the security limitations described above.
|
||||
|
||||
All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and
|
||||
used to compile C files in that package. All the CPPFLAGS and CXXFLAGS
|
||||
|
||||
@@ -248,6 +248,7 @@ var nblank *Node
|
||||
var typecheckok bool
|
||||
|
||||
var compiling_runtime bool
|
||||
var compiling_std bool
|
||||
|
||||
var compiling_wrappers int
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ func Main() {
|
||||
}
|
||||
|
||||
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
|
||||
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
|
||||
obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
|
||||
obj.Flagcount("B", "disable bounds checking", &Debug['B'])
|
||||
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
|
||||
|
||||
@@ -7,6 +7,7 @@ package gc
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
@@ -1057,6 +1058,11 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_"):
|
||||
lineno = p.baseline + int32(line) - 1 // pragcgo may call yyerror
|
||||
// For security, we disallow //go:cgo_* directives outside cgo-generated files.
|
||||
// Exception: they are allowed in the standard library, for runtime and syscall.
|
||||
if !isCgoGeneratedFile() && !compiling_std {
|
||||
p.error(syntax.Error{Pos: pos, Line: line, Msg: fmt.Sprintf("//%s only allowed in cgo-generated code", text)})
|
||||
}
|
||||
pragcgobuf += pragcgo(text)
|
||||
fallthrough // because of //go:cgo_unsafe_args
|
||||
default:
|
||||
@@ -1071,6 +1077,20 @@ func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
|
||||
return 0
|
||||
}
|
||||
|
||||
// isCgoGeneratedFile reports whether lineno is in a file
|
||||
// generated by cgo, which is to say a file with name
|
||||
// beginning with "_cgo_". Such files are allowed to
|
||||
// contain cgo directives, and for security reasons
|
||||
// (primarily misuse of linker flags), other files are not.
|
||||
// See golang.org/issue/23672.
|
||||
func isCgoGeneratedFile() bool {
|
||||
stk := Ctxt.LineHist.At(int(lineno))
|
||||
if stk == nil {
|
||||
return false
|
||||
}
|
||||
return strings.HasPrefix(filepath.Base(filepath.Clean(stk.File)), "_cgo_")
|
||||
}
|
||||
|
||||
func mkname(sym *Sym) *Node {
|
||||
n := oldname(sym)
|
||||
if n.Name != nil && n.Name.Pack != nil {
|
||||
|
||||
108
src/cmd/compile/internal/gc/testdata/loadstore.go
vendored
108
src/cmd/compile/internal/gc/testdata/loadstore.go
vendored
@@ -102,12 +102,120 @@ func testDeadStorePanic() {
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStore8(x int8, p *int8) int32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return int32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStoreU8(x uint8, p *uint8) uint32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return uint32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStore16(x int16, p *int16) int32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return int32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStoreU16(x uint16, p *uint16) uint32 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return uint32(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStore32(x int32, p *int32) int64 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return int64(*p) // load and cast
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func loadHitStoreU32(x uint32, p *uint32) uint64 {
|
||||
x *= x // try to trash high bits (arch-dependent)
|
||||
*p = x // store
|
||||
return uint64(*p) // load and cast
|
||||
}
|
||||
|
||||
func testLoadHitStore() {
|
||||
// Test that sign/zero extensions are kept when a load-hit-store
|
||||
// is replaced by a register-register move.
|
||||
{
|
||||
var in int8 = (1 << 6) + 1
|
||||
var p int8
|
||||
got := loadHitStore8(in, &p)
|
||||
want := int32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (int8) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in uint8 = (1 << 6) + 1
|
||||
var p uint8
|
||||
got := loadHitStoreU8(in, &p)
|
||||
want := uint32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (uint8) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in int16 = (1 << 10) + 1
|
||||
var p int16
|
||||
got := loadHitStore16(in, &p)
|
||||
want := int32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (int16) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in uint16 = (1 << 10) + 1
|
||||
var p uint16
|
||||
got := loadHitStoreU16(in, &p)
|
||||
want := uint32(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (uint16) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in int32 = (1 << 30) + 1
|
||||
var p int32
|
||||
got := loadHitStore32(in, &p)
|
||||
want := int64(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (int32) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
{
|
||||
var in uint32 = (1 << 30) + 1
|
||||
var p uint32
|
||||
got := loadHitStoreU32(in, &p)
|
||||
want := uint64(in * in)
|
||||
if got != want {
|
||||
fmt.Println("testLoadHitStore (uint32) failed. want =", want, ", got =", got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
testLoadStoreOrder()
|
||||
testStoreSize()
|
||||
testExtStore()
|
||||
testDeadStorePanic()
|
||||
testLoadHitStore()
|
||||
|
||||
if failed {
|
||||
panic("failed")
|
||||
|
||||
@@ -620,10 +620,12 @@
|
||||
(MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
||||
(MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
|
||||
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLSX x)
|
||||
(MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLSX x)
|
||||
|
||||
// Fold extensions and ANDs together.
|
||||
(MOVBLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
|
||||
|
||||
@@ -762,11 +762,14 @@
|
||||
(MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
|
||||
(MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
|
||||
(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQZX x)
|
||||
(MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQSX x)
|
||||
(MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQSX x)
|
||||
(MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQSX x)
|
||||
|
||||
// Fold extensions and ANDs together.
|
||||
(MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
|
||||
|
||||
@@ -467,12 +467,13 @@
|
||||
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
|
||||
@@ -679,14 +679,14 @@
|
||||
(MOVWstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
|
||||
(MOVDstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVDstorezero [off] {sym} ptr mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
// these seem to have bad interaction with other rules, resulting in slower code
|
||||
//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
|
||||
//(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
|
||||
//(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
|
||||
//(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
|
||||
//(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWreg x)
|
||||
//(MOVWUload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWUreg x)
|
||||
//(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(FMOVSload [off] {sym} ptr (FMOVSstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
//(FMOVDload [off] {sym} ptr (FMOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
@@ -522,11 +522,11 @@
|
||||
(MOVWstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
|
||||
// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
|
||||
(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
|
||||
(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
|
||||
(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
|
||||
(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
|
||||
(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
|
||||
|
||||
@@ -656,9 +656,9 @@
|
||||
(MOVWZreg x:(MOVWZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZloadidx <v.Type> [off] {sym} ptr idx mem)
|
||||
|
||||
// replace load from same location as preceding store with copy
|
||||
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
|
||||
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
|
||||
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
|
||||
(MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBZreg x)
|
||||
(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHZreg x)
|
||||
(MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWZreg x)
|
||||
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDreg x)
|
||||
|
||||
// Don't extend before storing
|
||||
|
||||
@@ -2503,6 +2503,28 @@ func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
|
||||
func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBLSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != Op386MOVBstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(Op386MOVBLSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
|
||||
// result: (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -2606,7 +2628,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVBLZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -2622,8 +2644,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(Op386MOVBLZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5248,6 +5269,28 @@ func rewriteValue386_Op386MOVWLSX(v *Value, config *Config) bool {
|
||||
func rewriteValue386_Op386MOVWLSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVWLSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != Op386MOVWstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(Op386MOVWLSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
|
||||
// result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -5378,7 +5421,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVWLZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5394,8 +5437,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(Op386MOVWLZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3361,6 +3361,28 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBQSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAMD64MOVBstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVBQSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
|
||||
// result: (MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -3539,7 +3561,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVBQZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -3555,8 +3577,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpAMD64MOVBQZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -4834,6 +4855,28 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVLQSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAMD64MOVLstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVLQSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVLQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
|
||||
// result: (MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -5041,7 +5084,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVLQZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5057,8 +5100,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpAMD64MOVLQZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -8703,6 +8745,28 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
|
||||
func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVWQSX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
ptr := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpAMD64MOVWstore {
|
||||
break
|
||||
}
|
||||
off2 := v_1.AuxInt
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpAMD64MOVWQSX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
|
||||
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
|
||||
// result: (MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
|
||||
@@ -8883,7 +8947,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: x
|
||||
// result: (MOVWQZX x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -8899,8 +8963,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpAMD64MOVWQZX)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -5188,8 +5188,8 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBUreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5202,11 +5202,10 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVBUreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5317,8 +5316,8 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5331,11 +5330,10 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVBreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5836,8 +5834,8 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVHUreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -5850,11 +5848,10 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVHUreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -5989,8 +5986,8 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVHreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -6003,11 +6000,10 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpARMMOVHreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3332,8 +3332,8 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBUreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -3346,11 +3346,10 @@ func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpMIPSMOVBUreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -3490,8 +3489,8 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVBreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -3504,11 +3503,10 @@ func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpMIPSMOVBreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -4148,8 +4146,8 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVHUreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -4162,11 +4160,10 @@ func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpMIPSMOVHUreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -4330,8 +4327,8 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
|
||||
return true
|
||||
}
|
||||
// match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
|
||||
// result: x
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVHreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -4344,11 +4341,10 @@ func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
|
||||
sym2 := v_1.Aux
|
||||
ptr2 := v_1.Args[0]
|
||||
x := v_1.Args[1]
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpCopy)
|
||||
v.Type = x.Type
|
||||
v.reset(OpMIPSMOVHreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -7851,7 +7851,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVBZload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVDreg x)
|
||||
// result: (MOVBZreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -7867,7 +7867,7 @@ func rewriteValueS390X_OpS390XMOVBZload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.reset(OpS390XMOVBZreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -11021,7 +11021,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVDreg x)
|
||||
// result: (MOVHZreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -11037,7 +11037,7 @@ func rewriteValueS390X_OpS390XMOVHZload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.reset(OpS390XMOVHZreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
@@ -12406,7 +12406,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
|
||||
_ = b
|
||||
// match: (MOVWZload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
|
||||
// cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
|
||||
// result: (MOVDreg x)
|
||||
// result: (MOVWZreg x)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
sym := v.Aux
|
||||
@@ -12422,7 +12422,7 @@ func rewriteValueS390X_OpS390XMOVWZload(v *Value, config *Config) bool {
|
||||
if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpS390XMOVDreg)
|
||||
v.reset(OpS390XMOVWZreg)
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
|
||||
2
src/cmd/dist/build.go
vendored
2
src/cmd/dist/build.go
vendored
@@ -701,7 +701,7 @@ func install(dir string) {
|
||||
} else {
|
||||
archive = b
|
||||
}
|
||||
compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
|
||||
compile := []string{pathf("%s/compile", tooldir), "-std", "-pack", "-o", b, "-p", pkg}
|
||||
if gogcflags != "" {
|
||||
compile = append(compile, strings.Fields(gogcflags)...)
|
||||
}
|
||||
|
||||
@@ -1103,17 +1103,26 @@
|
||||
// CGO_CFLAGS
|
||||
// Flags that cgo will pass to the compiler when compiling
|
||||
// C code.
|
||||
// CGO_CPPFLAGS
|
||||
// Flags that cgo will pass to the compiler when compiling
|
||||
// C or C++ code.
|
||||
// CGO_CXXFLAGS
|
||||
// Flags that cgo will pass to the compiler when compiling
|
||||
// C++ code.
|
||||
// CGO_FFLAGS
|
||||
// Flags that cgo will pass to the compiler when compiling
|
||||
// Fortran code.
|
||||
// CGO_LDFLAGS
|
||||
// Flags that cgo will pass to the compiler when linking.
|
||||
// CGO_CFLAGS_ALLOW
|
||||
// A regular expression specifying additional flags to allow
|
||||
// to appear in #cgo CFLAGS source code directives.
|
||||
// Does not apply to the CGO_CFLAGS environment variable.
|
||||
// CGO_CFLAGS_DISALLOW
|
||||
// A regular expression specifying flags that must be disallowed
|
||||
// from appearing in #cgo CFLAGS source code directives.
|
||||
// Does not apply to the CGO_CFLAGS environment variable.
|
||||
// CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
|
||||
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
// but for the C preprocessor.
|
||||
// CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
|
||||
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
// but for the C++ compiler.
|
||||
// CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
|
||||
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
// but for the Fortran compiler.
|
||||
// CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
|
||||
// Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
// but for the linker.
|
||||
// CXX
|
||||
// The command to use to compile C++ code.
|
||||
// PKG_CONFIG
|
||||
|
||||
@@ -1670,26 +1670,35 @@ func splitPkgConfigOutput(out []byte) []string {
|
||||
// Calls pkg-config if needed and returns the cflags/ldflags needed to build the package.
|
||||
func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err error) {
|
||||
if pkgs := p.CgoPkgConfig; len(pkgs) > 0 {
|
||||
for _, pkg := range pkgs {
|
||||
if !SafeArg(pkg) {
|
||||
return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg)
|
||||
}
|
||||
}
|
||||
var out []byte
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(p.Dir, b.pkgconfigCmd()+" --cflags "+strings.Join(pkgs, " "), string(out))
|
||||
b.print(err.Error() + "\n")
|
||||
err = errPrintedOutput
|
||||
return
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
if len(out) > 0 {
|
||||
cflags = splitPkgConfigOutput(out)
|
||||
if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", cflags); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
|
||||
out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", "--", pkgs)
|
||||
if err != nil {
|
||||
b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
|
||||
b.print(err.Error() + "\n")
|
||||
err = errPrintedOutput
|
||||
return
|
||||
return nil, nil, errPrintedOutput
|
||||
}
|
||||
if len(out) > 0 {
|
||||
ldflags = strings.Fields(string(out))
|
||||
if err := checkLinkerFlags("CFLAGS", "pkg-config --cflags", ldflags); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -2117,6 +2126,17 @@ func (b *builder) processOutput(out []byte) string {
|
||||
// It returns the command output and any errors that occurred.
|
||||
func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...interface{}) ([]byte, error) {
|
||||
cmdline := stringList(cmdargs...)
|
||||
|
||||
for _, arg := range cmdline {
|
||||
// GNU binutils commands, including gcc and gccgo, interpret an argument
|
||||
// @foo anywhere in the command line (even following --) as meaning
|
||||
// "read and insert arguments from the file named foo."
|
||||
// Don't say anything that might be misinterpreted that way.
|
||||
if strings.HasPrefix(arg, "@") {
|
||||
return nil, fmt.Errorf("invalid command-line argument %s in command: %s", arg, joinUnambiguously(cmdline))
|
||||
}
|
||||
}
|
||||
|
||||
if buildN || buildX {
|
||||
var envcmdline string
|
||||
for i := range env {
|
||||
@@ -2357,6 +2377,9 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
|
||||
// additional reflect type data.
|
||||
gcargs = append(gcargs, "-+")
|
||||
}
|
||||
if p.Standard {
|
||||
gcargs = append(gcargs, "-std")
|
||||
}
|
||||
|
||||
// If we're giving the compiler the entire package (no C etc files), tell it that,
|
||||
// so that it can give good error messages about forward declarations.
|
||||
@@ -3255,23 +3278,45 @@ func envList(key, def string) []string {
|
||||
return strings.Fields(v)
|
||||
}
|
||||
|
||||
// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
|
||||
func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
|
||||
// CFlags returns the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
|
||||
func (b *builder) cflags(p *Package) (cppflags, cflags, cxxflags, fflags, ldflags []string, err error) {
|
||||
defaults := "-g -O2"
|
||||
|
||||
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
|
||||
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
|
||||
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
|
||||
fflags = stringList(envList("CGO_FFLAGS", defaults), p.CgoFFLAGS)
|
||||
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
|
||||
if cppflags, err = buildFlags("CPPFLAGS", "", p.CgoCPPFLAGS, checkCompilerFlags); err != nil {
|
||||
return
|
||||
}
|
||||
if cflags, err = buildFlags("CFLAGS", defaults, p.CgoCFLAGS, checkCompilerFlags); err != nil {
|
||||
return
|
||||
}
|
||||
if cxxflags, err = buildFlags("CXXFLAGS", defaults, p.CgoCXXFLAGS, checkCompilerFlags); err != nil {
|
||||
return
|
||||
}
|
||||
if fflags, err = buildFlags("FFLAGS", defaults, p.CgoFFLAGS, checkCompilerFlags); err != nil {
|
||||
return
|
||||
}
|
||||
if ldflags, err = buildFlags("LDFLAGS", defaults, p.CgoLDFLAGS, checkLinkerFlags); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func buildFlags(name, defaults string, fromPackage []string, check func(string, string, []string) error) ([]string, error) {
|
||||
if err := check(name, "#cgo "+name, fromPackage); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return stringList(envList("CGO_"+name, defaults), fromPackage), nil
|
||||
}
|
||||
|
||||
var cgoRe = regexp.MustCompile(`[/\\:]`)
|
||||
|
||||
func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, objdirCgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
|
||||
p := a.p
|
||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p)
|
||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS, err := b.cflags(p)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
|
||||
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
|
||||
// If we are compiling Objective-C code, then we need to link against libobjc
|
||||
@@ -3335,6 +3380,12 @@ func (b *builder) cgo(a *action, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofil
|
||||
}
|
||||
|
||||
// Update $CGO_LDFLAGS with p.CgoLDFLAGS.
|
||||
// These flags are recorded in the generated _cgo_gotypes.go file
|
||||
// using //go:cgo_ldflag directives, the compiler records them in the
|
||||
// object file for the package, and then the Go linker passes them
|
||||
// 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).
|
||||
var cgoenv []string
|
||||
if len(cgoLDFLAGS) > 0 {
|
||||
flags := make([]string, len(cgoLDFLAGS))
|
||||
@@ -3684,7 +3735,11 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
|
||||
|
||||
// Run SWIG on one SWIG input file.
|
||||
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
|
||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
|
||||
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _, err := b.cflags(p)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var cflags []string
|
||||
if cxx {
|
||||
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
|
||||
|
||||
@@ -90,7 +90,12 @@ func findEnv(env []envVar, name string) string {
|
||||
func extraEnvVars() []envVar {
|
||||
var b builder
|
||||
b.init()
|
||||
cppflags, cflags, cxxflags, fflags, ldflags := b.cflags(&Package{})
|
||||
cppflags, cflags, cxxflags, fflags, ldflags, err := b.cflags(&Package{})
|
||||
if err != nil {
|
||||
// Should not happen - b.CFlags was given an empty package.
|
||||
fmt.Fprintf(os.Stderr, "go: invalid cflags: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
return []envVar{
|
||||
{"PKG_CONFIG", b.pkgconfigCmd()},
|
||||
{"CGO_CFLAGS", strings.Join(cflags, " ")},
|
||||
|
||||
@@ -439,6 +439,11 @@ func downloadPackage(p *Package) error {
|
||||
p.build.PkgRoot = filepath.Join(list[0], "pkg")
|
||||
}
|
||||
root := filepath.Join(p.build.SrcRoot, filepath.FromSlash(rootPath))
|
||||
|
||||
if err := checkNestedVCS(vcs, root, p.build.SrcRoot); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we've considered this repository already, don't do it again.
|
||||
if downloadRootCache[root] {
|
||||
return nil
|
||||
|
||||
@@ -1120,7 +1120,7 @@ func testMove(t *testing.T, vcs, url, base, config string) {
|
||||
tg.runFail("get", "-d", "-u", url)
|
||||
tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason")
|
||||
tg.runFail("get", "-d", "-f", "-u", url)
|
||||
tg.grepStderr("validating server certificate|not found", "go get -d -f -u "+url+" failed for wrong reason")
|
||||
tg.grepStderr("validating server certificate|[nN]ot [fF]ound", "go get -d -f -u "+url+" failed for wrong reason")
|
||||
}
|
||||
|
||||
func TestInternalPackageErrorsAreHandled(t *testing.T) {
|
||||
@@ -1141,10 +1141,9 @@ func TestMoveGit(t *testing.T) {
|
||||
testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config")
|
||||
}
|
||||
|
||||
// TODO(rsc): Set up a test case on bitbucket for hg.
|
||||
// func TestMoveHG(t *testing.T) {
|
||||
// testMove(t, "hg", "rsc.io/x86/x86asm", "x86", "rsc.io/x86/.hg/hgrc")
|
||||
// }
|
||||
func TestMoveHG(t *testing.T) {
|
||||
testMove(t, "hg", "vcs-test.golang.org/go/custom-hg-hello", "custom-hg-hello", "vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc")
|
||||
}
|
||||
|
||||
// TODO(rsc): Set up a test case on SourceForge (?) for svn.
|
||||
// func testMoveSVN(t *testing.T) {
|
||||
@@ -1273,6 +1272,25 @@ func TestGetGitDefaultBranch(t *testing.T) {
|
||||
tg.grepStdout(`\* another-branch`, "not on correct default branch")
|
||||
}
|
||||
|
||||
func TestAccidentalGitCheckout(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
if _, err := exec.LookPath("git"); err != nil {
|
||||
t.Skip("skipping because git binary not found")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempDir("src")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
|
||||
tg.runFail("get", "-u", "vcs-test.golang.org/go/test1-svn-git")
|
||||
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
|
||||
|
||||
tg.runFail("get", "-u", "vcs-test.golang.org/go/test2-svn-git/test2main")
|
||||
tg.grepStderr("src[\\\\/]vcs-test.* uses git, but parent .*src[\\\\/]vcs-test.* uses svn", "get did not fail for right reason")
|
||||
}
|
||||
|
||||
func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
@@ -2336,7 +2354,7 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempFile("src/origin/origin.go", `package origin
|
||||
// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
|
||||
// #cgo !darwin LDFLAGS: -Wl,-rpath,$ORIGIN
|
||||
// void f(void) {}
|
||||
import "C"
|
||||
func f() { C.f() }`)
|
||||
@@ -2719,7 +2737,7 @@ func TestImportMain(t *testing.T) {
|
||||
func TestFoo(t *testing.T) {}
|
||||
`)
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.creatingTemp("x")
|
||||
tg.creatingTemp("x" + exeSuffix)
|
||||
tg.run("build", "x")
|
||||
tg.run("test", "x")
|
||||
|
||||
@@ -3773,3 +3791,150 @@ func TestA(t *testing.T) {}`)
|
||||
tg.grepStdout("pkgs$", "expected package not listed")
|
||||
tg.grepStdout("pkgs/a", "expected package not listed")
|
||||
}
|
||||
|
||||
func TestBadCommandLines(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
tg.tempFile("src/x/x.go", "package x\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
|
||||
tg.run("build", "x")
|
||||
|
||||
tg.tempFile("src/x/@y.go", "package x\n")
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid input file name \"@y.go\"", "did not reject @y.go")
|
||||
tg.must(os.Remove(tg.path("src/x/@y.go")))
|
||||
|
||||
tg.tempFile("src/x/-y.go", "package x\n")
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid input file name \"-y.go\"", "did not reject -y.go")
|
||||
tg.must(os.Remove(tg.path("src/x/-y.go")))
|
||||
|
||||
tg.runFail("build", "-gcflags=@x", "x")
|
||||
tg.grepStderr("invalid command-line argument @x in command", "did not reject @x during exec")
|
||||
|
||||
tg.tempFile("src/@x/x.go", "package x\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.runFail("build", "@x")
|
||||
tg.grepStderr("invalid input directory name \"@x\"", "did not reject @x directory")
|
||||
|
||||
tg.tempFile("src/@x/y/y.go", "package y\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.runFail("build", "@x/y")
|
||||
tg.grepStderr("invalid import path \"@x/y\"", "did not reject @x/y import path")
|
||||
|
||||
tg.tempFile("src/-x/x.go", "package x\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.runFail("build", "--", "-x")
|
||||
tg.grepStderr("invalid input directory name \"-x\"", "did not reject -x directory")
|
||||
|
||||
tg.tempFile("src/-x/y/y.go", "package y\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.runFail("build", "--", "-x/y")
|
||||
tg.grepStderr("invalid import path \"-x/y\"", "did not reject -x/y import path")
|
||||
}
|
||||
|
||||
func TestBadCgoDirectives(t *testing.T) {
|
||||
if !canCgo {
|
||||
t.Skip("no cgo")
|
||||
}
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
tg.tempFile("src/x/x.go", "package x\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
|
||||
tg.tempFile("src/x/x.go", `package x
|
||||
|
||||
//go:cgo_ldflag "-fplugin=foo.so"
|
||||
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("//go:cgo_ldflag .* only allowed in cgo-generated code", "did not reject //go:cgo_ldflag directive")
|
||||
|
||||
tg.must(os.Remove(tg.path("src/x/x.go")))
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("no buildable Go source files", "did not report missing source code")
|
||||
tg.tempFile("src/x/_cgo_yy.go", `package x
|
||||
|
||||
//go:cgo_ldflag "-fplugin=foo.so"
|
||||
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("no buildable Go source files", "did not report missing source code") // _* files are ignored...
|
||||
|
||||
tg.runFail("build", tg.path("src/x/_cgo_yy.go")) // ... but if forced, the comment is rejected
|
||||
// Actually, today there is a separate issue that _ files named
|
||||
// on the command-line are ignored. Once that is fixed,
|
||||
// we want to see the cgo_ldflag error.
|
||||
tg.grepStderr("//go:cgo_ldflag only allowed in cgo-generated code|no buildable Go source files", "did not reject //go:cgo_ldflag directive")
|
||||
tg.must(os.Remove(tg.path("src/x/_cgo_yy.go")))
|
||||
|
||||
tg.tempFile("src/x/x.go", "package x\n")
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo CFLAGS: -fplugin=foo.so
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid flag in #cgo CFLAGS: -fplugin=foo.so", "did not reject -fplugin")
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo CFLAGS: -Ibar -fplugin=foo.so
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid flag in #cgo CFLAGS: -fplugin=foo.so", "did not reject -fplugin")
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo pkg-config: -foo
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid pkg-config package name: -foo", "did not reject pkg-config: -foo")
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo pkg-config: @foo
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid pkg-config package name: @foo", "did not reject pkg-config: -foo")
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo CFLAGS: @foo
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid flag in #cgo CFLAGS: @foo", "did not reject @foo flag")
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo CFLAGS: -D
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid flag in #cgo CFLAGS: -D without argument", "did not reject trailing -I flag")
|
||||
|
||||
// Note that -I @foo is allowed because we rewrite it into -I /path/to/src/@foo
|
||||
// before the check is applied. There's no such rewrite for -D.
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo CFLAGS: -D @foo
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid flag in #cgo CFLAGS: -D @foo", "did not reject -D @foo flag")
|
||||
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
// #cgo CFLAGS: -D@foo
|
||||
import "C"
|
||||
`)
|
||||
tg.runFail("build", "x")
|
||||
tg.grepStderr("invalid flag in #cgo CFLAGS: -D@foo", "did not reject -D@foo flag")
|
||||
|
||||
tg.setenv("CGO_CFLAGS", "-D@foo")
|
||||
tg.tempFile("src/x/y.go", `package x
|
||||
import "C"
|
||||
`)
|
||||
tg.run("build", "-n", "x")
|
||||
tg.grepStderr("-D@foo", "did not find -D@foo in commands")
|
||||
}
|
||||
|
||||
@@ -468,17 +468,26 @@ Environment variables for use with cgo:
|
||||
CGO_CFLAGS
|
||||
Flags that cgo will pass to the compiler when compiling
|
||||
C code.
|
||||
CGO_CPPFLAGS
|
||||
Flags that cgo will pass to the compiler when compiling
|
||||
C or C++ code.
|
||||
CGO_CXXFLAGS
|
||||
Flags that cgo will pass to the compiler when compiling
|
||||
C++ code.
|
||||
CGO_FFLAGS
|
||||
Flags that cgo will pass to the compiler when compiling
|
||||
Fortran code.
|
||||
CGO_LDFLAGS
|
||||
Flags that cgo will pass to the compiler when linking.
|
||||
CGO_CFLAGS_ALLOW
|
||||
A regular expression specifying additional flags to allow
|
||||
to appear in #cgo CFLAGS source code directives.
|
||||
Does not apply to the CGO_CFLAGS environment variable.
|
||||
CGO_CFLAGS_DISALLOW
|
||||
A regular expression specifying flags that must be disallowed
|
||||
from appearing in #cgo CFLAGS source code directives.
|
||||
Does not apply to the CGO_CFLAGS environment variable.
|
||||
CGO_CPPFLAGS, CGO_CPPFLAGS_ALLOW, CGO_CPPFLAGS_DISALLOW
|
||||
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
but for the C preprocessor.
|
||||
CGO_CXXFLAGS, CGO_CXXFLAGS_ALLOW, CGO_CXXFLAGS_DISALLOW
|
||||
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
but for the C++ compiler.
|
||||
CGO_FFLAGS, CGO_FFLAGS_ALLOW, CGO_FFLAGS_DISALLOW
|
||||
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
but for the Fortran compiler.
|
||||
CGO_LDFLAGS, CGO_LDFLAGS_ALLOW, CGO_LDFLAGS_DISALLOW
|
||||
Like CGO_CFLAGS, CGO_CFLAGS_ALLOW, and CGO_CFLAGS_DISALLOW,
|
||||
but for the linker.
|
||||
CXX
|
||||
The command to use to compile C++ code.
|
||||
PKG_CONFIG
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var ignoreImports bool // control whether we ignore imports in packages
|
||||
@@ -47,6 +48,8 @@ type Package struct {
|
||||
BinaryOnly bool `json:",omitempty"` // package cannot be recompiled
|
||||
|
||||
// Source files
|
||||
// If you add to this list you MUST add to p.AllFiles (below) too.
|
||||
// Otherwise file name security lists will not apply to any new additions.
|
||||
GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
|
||||
CgoFiles []string `json:",omitempty"` // .go sources files that import "C"
|
||||
IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints
|
||||
@@ -78,6 +81,8 @@ type Package struct {
|
||||
DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies
|
||||
|
||||
// Test information
|
||||
// If you add to this list you MUST add to p.AllFiles (below) too.
|
||||
// Otherwise file name security lists will not apply to any new additions.
|
||||
TestGoFiles []string `json:",omitempty"` // _test.go files in package
|
||||
TestImports []string `json:",omitempty"` // imports from TestGoFiles
|
||||
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
|
||||
@@ -106,6 +111,30 @@ type Package struct {
|
||||
gobinSubdir bool // install target would be subdir of GOBIN
|
||||
}
|
||||
|
||||
// allFiles returns the names of all the files considered for the package.
|
||||
// This is used for sanity and security checks, so we include all files,
|
||||
// even IgnoredGoFiles, because some subcommands consider them.
|
||||
// The go/build package filtered others out (like foo_wrongGOARCH.s)
|
||||
// and that's OK.
|
||||
func (p *Package) allFiles() []string {
|
||||
return stringList(
|
||||
p.GoFiles,
|
||||
p.CgoFiles,
|
||||
p.IgnoredGoFiles,
|
||||
p.CFiles,
|
||||
p.CXXFiles,
|
||||
p.MFiles,
|
||||
p.HFiles,
|
||||
p.FFiles,
|
||||
p.SFiles,
|
||||
p.SwigFiles,
|
||||
p.SwigCXXFiles,
|
||||
p.SysoFiles,
|
||||
p.TestGoFiles,
|
||||
p.XTestGoFiles,
|
||||
)
|
||||
}
|
||||
|
||||
// vendored returns the vendor-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
|
||||
@@ -990,22 +1019,8 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||
// To avoid problems on case-insensitive files, we reject any package
|
||||
// where two different input files have equal names under a case-insensitive
|
||||
// comparison.
|
||||
f1, f2 := foldDup(stringList(
|
||||
p.GoFiles,
|
||||
p.CgoFiles,
|
||||
p.IgnoredGoFiles,
|
||||
p.CFiles,
|
||||
p.CXXFiles,
|
||||
p.MFiles,
|
||||
p.HFiles,
|
||||
p.FFiles,
|
||||
p.SFiles,
|
||||
p.SysoFiles,
|
||||
p.SwigFiles,
|
||||
p.SwigCXXFiles,
|
||||
p.TestGoFiles,
|
||||
p.XTestGoFiles,
|
||||
))
|
||||
inputs := p.allFiles()
|
||||
f1, f2 := foldDup(inputs)
|
||||
if f1 != "" {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
@@ -1014,6 +1029,37 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||
return p
|
||||
}
|
||||
|
||||
// If first letter of input file is ASCII, it must be alphanumeric.
|
||||
// This avoids files turning into flags when invoking commands,
|
||||
// and other problems we haven't thought of yet.
|
||||
// Also, _cgo_ files must be generated by us, not supplied.
|
||||
// They are allowed to have //go:cgo_ldflag directives.
|
||||
// The directory scan ignores files beginning with _,
|
||||
// so we shouldn't see any _cgo_ files anyway, but just be safe.
|
||||
for _, file := range inputs {
|
||||
if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("invalid input file name %q", file),
|
||||
}
|
||||
return p
|
||||
}
|
||||
}
|
||||
if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("invalid input directory name %q", name),
|
||||
}
|
||||
return p
|
||||
}
|
||||
if !SafeArg(p.ImportPath) {
|
||||
p.Error = &PackageError{
|
||||
ImportStack: stk.copy(),
|
||||
Err: fmt.Sprintf("invalid import path %q", p.ImportPath),
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// Build list of imported packages and full dependency list.
|
||||
imports := make([]*Package, 0, len(p.Imports))
|
||||
deps := make(map[string]*Package)
|
||||
@@ -1130,6 +1176,22 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
||||
return p
|
||||
}
|
||||
|
||||
// SafeArg reports whether arg is a "safe" command-line argument,
|
||||
// meaning that when it appears in a command-line, it probably
|
||||
// doesn't have some special meaning other than its own name.
|
||||
// Obviously args beginning with - are not safe (they look like flags).
|
||||
// Less obviously, args beginning with @ are not safe (they look like
|
||||
// GNU binutils flagfile specifiers, sometimes called "response files").
|
||||
// To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
|
||||
// We accept leading . _ and / as likely in file system paths.
|
||||
func SafeArg(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
c := name[0]
|
||||
return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
|
||||
}
|
||||
|
||||
// usesSwig reports whether the package needs to run SWIG.
|
||||
func (p *Package) usesSwig() bool {
|
||||
return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
|
||||
|
||||
159
src/cmd/go/security.go
Normal file
159
src/cmd/go/security.go
Normal file
@@ -0,0 +1,159 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Checking of compiler and linker flags.
|
||||
// We must avoid flags like -fplugin=, which can allow
|
||||
// arbitrary code execution during the build.
|
||||
// Do not make changes here without carefully
|
||||
// considering the implications.
|
||||
// (That's why the code is isolated in a file named security.go.)
|
||||
//
|
||||
// Note that -Wl,foo means split foo on commas and pass to
|
||||
// the linker, so that -Wl,-foo,bar means pass -foo bar to
|
||||
// the linker. Similarly -Wa,foo for the assembler and so on.
|
||||
// If any of these are permitted, the wildcard portion must
|
||||
// disallow commas.
|
||||
//
|
||||
// Note also that GNU binutils accept any argument @foo
|
||||
// as meaning "read more flags from the file foo", so we must
|
||||
// guard against any command-line argument beginning with @,
|
||||
// even things like "-I @foo".
|
||||
// We use load.SafeArg (which is even more conservative)
|
||||
// to reject these.
|
||||
//
|
||||
// Even worse, gcc -I@foo (one arg) turns into cc1 -I @foo (two args),
|
||||
// so although gcc doesn't expand the @foo, cc1 will.
|
||||
// So out of paranoia, we reject @ at the beginning of every
|
||||
// flag argument that might be split into its own argument.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var re = regexp.MustCompile
|
||||
|
||||
var validCompilerFlags = []*regexp.Regexp{
|
||||
re(`-D([A-Za-z_].*)`),
|
||||
re(`-I([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`-W`),
|
||||
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
|
||||
re(`-f(no-)?objc-arc`),
|
||||
re(`-f(no-)?omit-frame-pointer`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?split-stack`),
|
||||
re(`-f(no-)?stack-(.+)`),
|
||||
re(`-f(no-)?strict-aliasing`),
|
||||
re(`-fsanitize=(.+)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-m(no-)?stack-(.+)`),
|
||||
re(`-mmacosx-(.+)`),
|
||||
re(`-mnop-fun-dllimport`),
|
||||
re(`-pthread`),
|
||||
re(`-std=([^@\-].*)`),
|
||||
re(`-x([^@\-].*)`),
|
||||
}
|
||||
|
||||
var validCompilerFlagsWithNextArg = []string{
|
||||
"-D",
|
||||
"-I",
|
||||
"-framework",
|
||||
"-x",
|
||||
}
|
||||
|
||||
var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-l([^@\-].*)`),
|
||||
re(`-L([^@\-].*)`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-fsanitize=([^@\-].*)`),
|
||||
re(`-g([^@\-].*)?`),
|
||||
re(`-m(arch|cpu|fpu|tune)=([^@\-].*)`),
|
||||
re(`-(pic|PIC|pie|PIE)`),
|
||||
re(`-pthread`),
|
||||
|
||||
// Note that any wildcards in -Wl need to exclude comma,
|
||||
// since -Wl splits its argument at commas and passes
|
||||
// them all to the linker uninterpreted. Allowing comma
|
||||
// in a wildcard would allow tunnelling arbitrary additional
|
||||
// linker arguments through one of these.
|
||||
re(`-Wl,-rpath,([^,@\-][^,]+)`),
|
||||
re(`-Wl,--(no-)?warn-([^,]+)`),
|
||||
|
||||
re(`[a-zA-Z0-9_].*\.(o|obj|dll|dylib|so)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
|
||||
}
|
||||
|
||||
var validLinkerFlagsWithNextArg = []string{
|
||||
"-F",
|
||||
"-l",
|
||||
"-L",
|
||||
"-framework",
|
||||
}
|
||||
|
||||
func checkCompilerFlags(name, source string, list []string) error {
|
||||
return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg)
|
||||
}
|
||||
|
||||
func checkLinkerFlags(name, source string, list []string) error {
|
||||
return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg)
|
||||
}
|
||||
|
||||
func checkFlags(name, source string, list []string, valid []*regexp.Regexp, validNext []string) error {
|
||||
// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc.
|
||||
var (
|
||||
allow *regexp.Regexp
|
||||
disallow *regexp.Regexp
|
||||
)
|
||||
if env := os.Getenv("CGO_" + name + "_ALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_ALLOW: %v", name, err)
|
||||
}
|
||||
allow = r
|
||||
}
|
||||
if env := os.Getenv("CGO_" + name + "_DISALLOW"); env != "" {
|
||||
r, err := regexp.Compile(env)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing $CGO_%s_DISALLOW: %v", name, err)
|
||||
}
|
||||
disallow = r
|
||||
}
|
||||
|
||||
Args:
|
||||
for i := 0; i < len(list); i++ {
|
||||
arg := list[i]
|
||||
if disallow != nil && disallow.FindString(arg) == arg {
|
||||
goto Bad
|
||||
}
|
||||
if allow != nil && allow.FindString(arg) == arg {
|
||||
continue Args
|
||||
}
|
||||
for _, re := range valid {
|
||||
if re.FindString(arg) == arg { // must be complete match
|
||||
continue Args
|
||||
}
|
||||
}
|
||||
for _, x := range validNext {
|
||||
if arg == x {
|
||||
if i+1 < len(list) && SafeArg(list[i+1]) {
|
||||
i++
|
||||
continue Args
|
||||
}
|
||||
if i+1 < len(list) {
|
||||
return fmt.Errorf("invalid flag in %s: %s %s", source, arg, list[i+1])
|
||||
}
|
||||
return fmt.Errorf("invalid flag in %s: %s without argument", source, arg)
|
||||
}
|
||||
}
|
||||
Bad:
|
||||
return fmt.Errorf("invalid flag in %s: %s", source, arg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
240
src/cmd/go/security_test.go
Normal file
240
src/cmd/go/security_test.go
Normal file
@@ -0,0 +1,240 @@
|
||||
// Copyright 2018 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 main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var goodCompilerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-I/"},
|
||||
{"-I/etc/passwd"},
|
||||
{"-I."},
|
||||
{"-O"},
|
||||
{"-O2"},
|
||||
{"-Osmall"},
|
||||
{"-W"},
|
||||
{"-Wall"},
|
||||
{"-fobjc-arc"},
|
||||
{"-fno-objc-arc"},
|
||||
{"-fomit-frame-pointer"},
|
||||
{"-fno-omit-frame-pointer"},
|
||||
{"-fpic"},
|
||||
{"-fno-pic"},
|
||||
{"-fPIC"},
|
||||
{"-fno-PIC"},
|
||||
{"-fpie"},
|
||||
{"-fno-pie"},
|
||||
{"-fPIE"},
|
||||
{"-fno-PIE"},
|
||||
{"-fsplit-stack"},
|
||||
{"-fno-split-stack"},
|
||||
{"-fstack-xxx"},
|
||||
{"-fno-stack-xxx"},
|
||||
{"-fsanitize=hands"},
|
||||
{"-g"},
|
||||
{"-ggdb"},
|
||||
{"-march=souza"},
|
||||
{"-mcpu=123"},
|
||||
{"-mfpu=123"},
|
||||
{"-mtune=happybirthday"},
|
||||
{"-mstack-overflow"},
|
||||
{"-mno-stack-overflow"},
|
||||
{"-mmacosx-version"},
|
||||
{"-mnop-fun-dllimport"},
|
||||
{"-pthread"},
|
||||
{"-std=c99"},
|
||||
{"-xc"},
|
||||
{"-D", "FOO"},
|
||||
{"-D", "foo=bar"},
|
||||
{"-I", "."},
|
||||
{"-I", "/etc/passwd"},
|
||||
{"-I", "世界"},
|
||||
{"-framework", "Chocolate"},
|
||||
{"-x", "c"},
|
||||
}
|
||||
|
||||
var badCompilerFlags = [][]string{
|
||||
{"-D@X"},
|
||||
{"-D-X"},
|
||||
{"-I@dir"},
|
||||
{"-I-dir"},
|
||||
{"-O@1"},
|
||||
{"-Wa,-foo"},
|
||||
{"-W@foo"},
|
||||
{"-g@gdb"},
|
||||
{"-g-gdb"},
|
||||
{"-march=@dawn"},
|
||||
{"-march=-dawn"},
|
||||
{"-std=@c99"},
|
||||
{"-std=-c99"},
|
||||
{"-x@c"},
|
||||
{"-x-c"},
|
||||
{"-D", "@foo"},
|
||||
{"-D", "-foo"},
|
||||
{"-I", "@foo"},
|
||||
{"-I", "-foo"},
|
||||
{"-framework", "-Caffeine"},
|
||||
{"-framework", "@Home"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
}
|
||||
|
||||
func TestCheckCompilerFlags(t *testing.T) {
|
||||
for _, f := range goodCompilerFlags {
|
||||
if err := checkCompilerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
for _, f := range badCompilerFlags {
|
||||
if err := checkCompilerFlags("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var goodLinkerFlags = [][]string{
|
||||
{"-Fbar"},
|
||||
{"-lbar"},
|
||||
{"-Lbar"},
|
||||
{"-fpic"},
|
||||
{"-fno-pic"},
|
||||
{"-fPIC"},
|
||||
{"-fno-PIC"},
|
||||
{"-fpie"},
|
||||
{"-fno-pie"},
|
||||
{"-fPIE"},
|
||||
{"-fno-PIE"},
|
||||
{"-fsanitize=hands"},
|
||||
{"-g"},
|
||||
{"-ggdb"},
|
||||
{"-march=souza"},
|
||||
{"-mcpu=123"},
|
||||
{"-mfpu=123"},
|
||||
{"-mtune=happybirthday"},
|
||||
{"-pic"},
|
||||
{"-pthread"},
|
||||
{"-Wl,-rpath,foo"},
|
||||
{"-Wl,-rpath,$ORIGIN/foo"},
|
||||
{"-Wl,--warn-error"},
|
||||
{"-Wl,--no-warn-error"},
|
||||
{"foo.so"},
|
||||
{"_世界.dll"},
|
||||
{"libcgosotest.dylib"},
|
||||
{"-F", "framework"},
|
||||
{"-l", "."},
|
||||
{"-l", "/etc/passwd"},
|
||||
{"-l", "世界"},
|
||||
{"-L", "framework"},
|
||||
{"-framework", "Chocolate"},
|
||||
}
|
||||
|
||||
var badLinkerFlags = [][]string{
|
||||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-O"},
|
||||
{"-O2"},
|
||||
{"-Osmall"},
|
||||
{"-W"},
|
||||
{"-Wall"},
|
||||
{"-fobjc-arc"},
|
||||
{"-fno-objc-arc"},
|
||||
{"-fomit-frame-pointer"},
|
||||
{"-fno-omit-frame-pointer"},
|
||||
{"-fsplit-stack"},
|
||||
{"-fno-split-stack"},
|
||||
{"-fstack-xxx"},
|
||||
{"-fno-stack-xxx"},
|
||||
{"-mstack-overflow"},
|
||||
{"-mno-stack-overflow"},
|
||||
{"-mmacosx-version"},
|
||||
{"-mnop-fun-dllimport"},
|
||||
{"-std=c99"},
|
||||
{"-xc"},
|
||||
{"-D", "FOO"},
|
||||
{"-D", "foo=bar"},
|
||||
{"-I", "FOO"},
|
||||
{"-L", "@foo"},
|
||||
{"-L", "-foo"},
|
||||
{"-x", "c"},
|
||||
{"-D@X"},
|
||||
{"-D-X"},
|
||||
{"-I@dir"},
|
||||
{"-I-dir"},
|
||||
{"-O@1"},
|
||||
{"-Wa,-foo"},
|
||||
{"-W@foo"},
|
||||
{"-g@gdb"},
|
||||
{"-g-gdb"},
|
||||
{"-march=@dawn"},
|
||||
{"-march=-dawn"},
|
||||
{"-std=@c99"},
|
||||
{"-std=-c99"},
|
||||
{"-x@c"},
|
||||
{"-x-c"},
|
||||
{"-D", "@foo"},
|
||||
{"-D", "-foo"},
|
||||
{"-I", "@foo"},
|
||||
{"-I", "-foo"},
|
||||
{"-l", "@foo"},
|
||||
{"-l", "-foo"},
|
||||
{"-framework", "-Caffeine"},
|
||||
{"-framework", "@Home"},
|
||||
{"-x", "--c"},
|
||||
{"-x", "@obj"},
|
||||
{"-Wl,-rpath,@foo"},
|
||||
}
|
||||
|
||||
func TestCheckLinkerFlags(t *testing.T) {
|
||||
for _, f := range goodLinkerFlags {
|
||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||
t.Errorf("unexpected error for %q: %v", f, err)
|
||||
}
|
||||
}
|
||||
for _, f := range badLinkerFlags {
|
||||
if err := checkLinkerFlags("test", "test", f); err == nil {
|
||||
t.Errorf("missing error for %q", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil {
|
||||
t.Fatalf("missing error for -disallow")
|
||||
}
|
||||
os.Setenv("CGO_TEST_ALLOW", "-disallo")
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil {
|
||||
t.Fatalf("missing error for -disallow with CGO_TEST_ALLOW=-disallo")
|
||||
}
|
||||
os.Setenv("CGO_TEST_ALLOW", "-disallow")
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err != nil {
|
||||
t.Fatalf("unexpected error for -disallow with CGO_TEST_ALLOW=-disallow: %v", err)
|
||||
}
|
||||
os.Unsetenv("CGO_TEST_ALLOW")
|
||||
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err != nil {
|
||||
t.Fatalf("unexpected error for -Wall: %v", err)
|
||||
}
|
||||
os.Setenv("CGO_TEST_DISALLOW", "-Wall")
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil {
|
||||
t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall")
|
||||
}
|
||||
os.Setenv("CGO_TEST_ALLOW", "-Wall") // disallow wins
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-Wall"}); err == nil {
|
||||
t.Fatalf("missing error for -Wall with CGO_TEST_DISALLOW=-Wall and CGO_TEST_ALLOW=-Wall")
|
||||
}
|
||||
|
||||
os.Setenv("CGO_TEST_ALLOW", "-fplugin.*")
|
||||
os.Setenv("CGO_TEST_DISALLOW", "-fplugin=lint.so")
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=faster.so"}); err != nil {
|
||||
t.Fatalf("unexpected error for -fplugin=faster.so: %v", err)
|
||||
}
|
||||
if err := checkCompilerFlags("TEST", "test", []string{"-fplugin=lint.so"}); err == nil {
|
||||
t.Fatalf("missing error for -fplugin=lint.so: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -497,11 +497,28 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
|
||||
return nil, "", fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||
}
|
||||
|
||||
var vcsRet *vcsCmd
|
||||
var rootRet string
|
||||
|
||||
origDir := dir
|
||||
for len(dir) > len(srcRoot) {
|
||||
for _, vcs := range vcsList {
|
||||
if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
|
||||
return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
|
||||
root := filepath.ToSlash(dir[len(srcRoot)+1:])
|
||||
// Record first VCS we find, but keep looking,
|
||||
// to detect mistakes like one kind of VCS inside another.
|
||||
if vcsRet == nil {
|
||||
vcsRet = vcs
|
||||
rootRet = root
|
||||
continue
|
||||
}
|
||||
// Allow .git inside .git, which can arise due to submodules.
|
||||
if vcsRet == vcs && vcs.cmd == "git" {
|
||||
continue
|
||||
}
|
||||
// Otherwise, we have one VCS inside a different VCS.
|
||||
return nil, "", fmt.Errorf("directory %q uses %s, but parent %q uses %s",
|
||||
filepath.Join(srcRoot, rootRet), vcsRet.cmd, filepath.Join(srcRoot, root), vcs.cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -514,9 +531,48 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
|
||||
dir = ndir
|
||||
}
|
||||
|
||||
if vcsRet != nil {
|
||||
return vcsRet, rootRet, nil
|
||||
}
|
||||
|
||||
return nil, "", fmt.Errorf("directory %q is not using a known version control system", origDir)
|
||||
}
|
||||
|
||||
// checkNestedVCS checks for an incorrectly-nested VCS-inside-VCS
|
||||
// situation for dir, checking parents up until srcRoot.
|
||||
func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error {
|
||||
if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator {
|
||||
return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot)
|
||||
}
|
||||
|
||||
otherDir := dir
|
||||
for len(otherDir) > len(srcRoot) {
|
||||
for _, otherVCS := range vcsList {
|
||||
if _, err := os.Stat(filepath.Join(otherDir, "."+otherVCS.cmd)); err == nil {
|
||||
// Allow expected vcs in original dir.
|
||||
if otherDir == dir && otherVCS == vcs {
|
||||
continue
|
||||
}
|
||||
// Allow .git inside .git, which can arise due to submodules.
|
||||
if otherVCS == vcs && vcs.cmd == "git" {
|
||||
continue
|
||||
}
|
||||
// Otherwise, we have one VCS inside a different VCS.
|
||||
return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.cmd, otherDir, otherVCS.cmd)
|
||||
}
|
||||
}
|
||||
// Move to parent.
|
||||
newDir := filepath.Dir(otherDir)
|
||||
if len(newDir) >= len(otherDir) {
|
||||
// Shouldn't happen, but just in case, stop.
|
||||
break
|
||||
}
|
||||
otherDir = newDir
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// repoRoot represents a version control system, a repo, and a root of
|
||||
// where to put it on disk.
|
||||
type repoRoot struct {
|
||||
|
||||
@@ -322,15 +322,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
|
||||
|
||||
// Rewrite p, if necessary, to access global data via the global offset table.
|
||||
func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||
var add, lea, mov obj.As
|
||||
var lea, mov obj.As
|
||||
var reg int16
|
||||
if p.Mode == 64 {
|
||||
add = AADDQ
|
||||
lea = ALEAQ
|
||||
mov = AMOVQ
|
||||
reg = REG_R15
|
||||
} else {
|
||||
add = AADDL
|
||||
lea = ALEAL
|
||||
mov = AMOVL
|
||||
reg = REG_CX
|
||||
@@ -347,8 +345,10 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||
// ADUFFxxx $offset
|
||||
// becomes
|
||||
// $MOV runtime.duffxxx@GOT, $reg
|
||||
// $ADD $offset, $reg
|
||||
// $LEA $offset($reg), $reg
|
||||
// CALL $reg
|
||||
// (we use LEAx rather than ADDx because ADDx clobbers
|
||||
// flags and duffzero on 386 does not otherwise do so)
|
||||
var sym *obj.LSym
|
||||
if p.As == obj.ADUFFZERO {
|
||||
sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
|
||||
@@ -365,9 +365,10 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||
p.To.Offset = 0
|
||||
p.To.Sym = nil
|
||||
p1 := obj.Appendp(ctxt, p)
|
||||
p1.As = add
|
||||
p1.From.Type = obj.TYPE_CONST
|
||||
p1.As = lea
|
||||
p1.From.Type = obj.TYPE_MEM
|
||||
p1.From.Offset = offset
|
||||
p1.From.Reg = reg
|
||||
p1.To.Type = obj.TYPE_REG
|
||||
p1.To.Reg = reg
|
||||
p2 := obj.Appendp(ctxt, p1)
|
||||
|
||||
@@ -324,18 +324,36 @@ func isRuntimeDepPkg(pkg string) bool {
|
||||
return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
|
||||
}
|
||||
|
||||
// Estimate the max size needed to hold any new trampolines created for this function. This
|
||||
// is used to determine when the section can be split if it becomes too large, to ensure that
|
||||
// the trampolines are in the same section as the function that uses them.
|
||||
func maxSizeTrampolinesPPC64(s *Symbol, isTramp bool) uint64 {
|
||||
// If Thearch.Trampoline is nil, then trampoline support is not available on this arch.
|
||||
// A trampoline does not need any dependent trampolines.
|
||||
if Thearch.Trampoline == nil || isTramp {
|
||||
return 0
|
||||
}
|
||||
|
||||
n := uint64(0)
|
||||
for ri := range s.R {
|
||||
r := &s.R[ri]
|
||||
if r.Type.IsDirectJump() {
|
||||
n++
|
||||
}
|
||||
}
|
||||
// Trampolines in ppc64 are 4 instructions.
|
||||
return n * 16
|
||||
}
|
||||
|
||||
// detect too-far jumps in function s, and add trampolines if necessary
|
||||
// ARM supports trampoline insertion for internal and external linking
|
||||
// PPC64 & PPC64LE support trampoline insertion for internal linking only
|
||||
// ARM, PPC64 & PPC64LE support trampoline insertion for internal and external linking
|
||||
// On PPC64 & PPC64LE the text sections might be split but will still insert trampolines
|
||||
// where necessary.
|
||||
func trampoline(ctxt *Link, s *Symbol) {
|
||||
if Thearch.Trampoline == nil {
|
||||
return // no need or no support of trampolines on this arch
|
||||
}
|
||||
|
||||
if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
|
||||
return
|
||||
}
|
||||
|
||||
for ri := range s.R {
|
||||
r := &s.R[ri]
|
||||
if !r.Type.IsDirectJump() {
|
||||
@@ -2044,14 +2062,14 @@ func (ctxt *Link) textaddress() {
|
||||
sect.Vaddr = va
|
||||
ntramps := 0
|
||||
for _, sym := range ctxt.Textp {
|
||||
sect, n, va = assignAddress(ctxt, sect, n, sym, va)
|
||||
sect, n, va = assignAddress(ctxt, sect, n, sym, va, false)
|
||||
|
||||
trampoline(ctxt, sym) // resolve jumps, may add trampolines if jump too far
|
||||
|
||||
// lay down trampolines after each function
|
||||
for ; ntramps < len(ctxt.tramps); ntramps++ {
|
||||
tramp := ctxt.tramps[ntramps]
|
||||
sect, n, va = assignAddress(ctxt, sect, n, tramp, va)
|
||||
sect, n, va = assignAddress(ctxt, sect, n, tramp, va, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2077,7 +2095,7 @@ func (ctxt *Link) textaddress() {
|
||||
// assigns address for a text symbol, returns (possibly new) section, its number, and the address
|
||||
// Note: once we have trampoline insertion support for external linking, this function
|
||||
// will not need to create new text sections, and so no need to return sect and n.
|
||||
func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*Section, int, uint64) {
|
||||
func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64, isTramp bool) (*Section, int, uint64) {
|
||||
sym.Sect = sect
|
||||
if sym.Type&obj.SSUB != 0 {
|
||||
return sect, n, va
|
||||
@@ -2106,7 +2124,7 @@ func assignAddress(ctxt *Link, sect *Section, n int, sym *Symbol, va uint64) (*S
|
||||
|
||||
// Only break at outermost syms.
|
||||
|
||||
if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize > 0x1c00000 {
|
||||
if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(sym, isTramp) > 0x1c00000 {
|
||||
|
||||
// Set the length for the previous text section
|
||||
sect.Length = va - sect.Vaddr
|
||||
|
||||
@@ -522,13 +522,22 @@ func archrelocaddr(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
|
||||
// resolve direct jump relocation r in s, and add trampoline if necessary
|
||||
func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
|
||||
|
||||
// Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
|
||||
// For internal linking, trampolines are always created for long calls.
|
||||
// For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
|
||||
// r2. For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
|
||||
if ld.Linkmode == ld.LinkExternal && (ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE) {
|
||||
// No trampolines needed since r2 contains the TOC
|
||||
return
|
||||
}
|
||||
|
||||
t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
|
||||
switch r.Type {
|
||||
case obj.R_CALLPOWER:
|
||||
|
||||
// If branch offset is too far then create a trampoline.
|
||||
|
||||
if int64(int32(t<<6)>>6) != t || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
|
||||
if (ld.Linkmode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
|
||||
var tramp *ld.Symbol
|
||||
for i := 0; ; i++ {
|
||||
|
||||
@@ -552,26 +561,20 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
|
||||
|
||||
t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
|
||||
|
||||
// If the offset of the trampoline that has been found is within range, use it.
|
||||
if int64(int32(t<<6)>>6) == t {
|
||||
// With internal linking, the trampoline can be used if it is not too far.
|
||||
// With external linking, the trampoline must be in this section for it to be reused.
|
||||
if (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ld.Linkmode == ld.LinkExternal && s.Sect == tramp.Sect) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if tramp.Type == 0 {
|
||||
ctxt.AddTramp(tramp)
|
||||
tramp.Size = 16 // 4 instructions
|
||||
tramp.P = make([]byte, tramp.Size)
|
||||
t = ld.Symaddr(r.Sym) + r.Add
|
||||
f := t & 0xffff0000
|
||||
o1 := uint32(0x3fe00000 | (f >> 16)) // lis r31,trampaddr hi (r31 is temp reg)
|
||||
f = t & 0xffff
|
||||
o2 := uint32(0x63ff0000 | f) // ori r31,trampaddr lo
|
||||
o3 := uint32(0x7fe903a6) // mtctr
|
||||
o4 := uint32(0x4e800420) // bctr
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
|
||||
if ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE {
|
||||
// Should have returned for above cases
|
||||
ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
|
||||
} else {
|
||||
ctxt.AddTramp(tramp)
|
||||
gentramp(tramp, r.Sym, int64(r.Add))
|
||||
}
|
||||
}
|
||||
r.Sym = tramp
|
||||
r.Add = 0 // This was folded into the trampoline target address
|
||||
@@ -582,6 +585,42 @@ func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
|
||||
}
|
||||
}
|
||||
|
||||
func gentramp(tramp, target *ld.Symbol, offset int64) {
|
||||
// Used for default build mode for an executable
|
||||
// Address of the call target is generated using
|
||||
// relocation and doesn't depend on r2 (TOC).
|
||||
tramp.Size = 16 // 4 instructions
|
||||
tramp.P = make([]byte, tramp.Size)
|
||||
t := ld.Symaddr(target) + offset
|
||||
o1 := uint32(0x3fe00000) // lis r31,targetaddr hi
|
||||
o2 := uint32(0x3bff0000) // addi r31,targetaddr lo
|
||||
// With external linking, the target address must be
|
||||
// relocated using LO and HA
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
tr := ld.Addrel(tramp)
|
||||
tr.Off = 0
|
||||
tr.Type = obj.R_ADDRPOWER
|
||||
tr.Siz = 8 // generates 2 relocations: HA + LO
|
||||
tr.Sym = target
|
||||
tr.Add = offset
|
||||
} else {
|
||||
// adjustment needed if lo has sign bit set
|
||||
// when using addi to compute address
|
||||
val := uint32((t & 0xffff0000) >> 16)
|
||||
if t&0x8000 != 0 {
|
||||
val += 1
|
||||
}
|
||||
o1 |= val // hi part of addr
|
||||
o2 |= uint32(t & 0xffff) // lo part of addr
|
||||
}
|
||||
o3 := uint32(0x7fe903a6) // mtctr r31
|
||||
o4 := uint32(0x4e800420) // bctr
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
|
||||
ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
|
||||
}
|
||||
|
||||
func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
|
||||
if ld.Linkmode == ld.LinkExternal {
|
||||
switch r.Type {
|
||||
|
||||
@@ -191,6 +191,10 @@ func matchNameConstraint(domain, constraint string) bool {
|
||||
|
||||
// isValid performs validity checks on the c.
|
||||
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
|
||||
if len(c.UnhandledCriticalExtensions) > 0 {
|
||||
return UnhandledCriticalExtension{}
|
||||
}
|
||||
|
||||
if len(currentChain) > 0 {
|
||||
child := currentChain[len(currentChain)-1]
|
||||
if !bytes.Equal(child.RawIssuer, c.RawSubject) {
|
||||
@@ -279,10 +283,6 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
|
||||
return c.systemVerify(&opts)
|
||||
}
|
||||
|
||||
if len(c.UnhandledCriticalExtensions) > 0 {
|
||||
return nil, UnhandledCriticalExtension{}
|
||||
}
|
||||
|
||||
if opts.Roots == nil {
|
||||
opts.Roots = systemRootsPool()
|
||||
if opts.Roots == nil {
|
||||
|
||||
@@ -263,6 +263,30 @@ var verifyTests = []verifyTest{
|
||||
|
||||
errorCallback: expectSubjectIssuerMismatcthError,
|
||||
},
|
||||
{
|
||||
// Test that unknown critical extensions in a leaf cause a
|
||||
// verify error.
|
||||
leaf: criticalExtLeafWithExt,
|
||||
dnsName: "example.com",
|
||||
intermediates: []string{criticalExtIntermediate},
|
||||
roots: []string{criticalExtRoot},
|
||||
currentTime: 1486684488,
|
||||
systemSkip: true,
|
||||
|
||||
errorCallback: expectUnhandledCriticalExtension,
|
||||
},
|
||||
{
|
||||
// Test that unknown critical extensions in an intermediate
|
||||
// cause a verify error.
|
||||
leaf: criticalExtLeaf,
|
||||
dnsName: "example.com",
|
||||
intermediates: []string{criticalExtIntermediateWithExt},
|
||||
roots: []string{criticalExtRoot},
|
||||
currentTime: 1486684488,
|
||||
systemSkip: true,
|
||||
|
||||
errorCallback: expectUnhandledCriticalExtension,
|
||||
},
|
||||
}
|
||||
|
||||
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
|
||||
@@ -330,6 +354,14 @@ func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool)
|
||||
return true
|
||||
}
|
||||
|
||||
func expectUnhandledCriticalExtension(t *testing.T, i int, err error) (ok bool) {
|
||||
if _, ok := err.(UnhandledCriticalExtension); !ok {
|
||||
t.Errorf("#%d: error was not an UnhandledCriticalExtension: %s", i, err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func certificateFromPEM(pemBytes string) (*Certificate, error) {
|
||||
block, _ := pem.Decode([]byte(pemBytes))
|
||||
if block == nil {
|
||||
@@ -1379,3 +1411,67 @@ w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
|
||||
4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
|
||||
8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const criticalExtRoot = `-----BEGIN CERTIFICATE-----
|
||||
MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
|
||||
A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
|
||||
MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
|
||||
CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
|
||||
gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
|
||||
BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
|
||||
uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
|
||||
FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
|
||||
A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
|
||||
MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
|
||||
KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
|
||||
rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
|
||||
AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
|
||||
Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
|
||||
EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
|
||||
cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
|
||||
xXbdbm27KQ==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
|
||||
MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
|
||||
A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
|
||||
MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
|
||||
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
|
||||
6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
|
||||
gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
|
||||
AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
|
||||
IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
|
||||
SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
|
||||
I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
|
||||
MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
|
||||
T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
|
||||
MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
|
||||
cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
|
||||
mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
|
||||
oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
|
||||
BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
|
||||
UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
|
||||
BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
|
||||
c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
|
||||
MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
|
||||
A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
|
||||
aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
|
||||
T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
|
||||
A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
|
||||
GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
|
||||
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
|
||||
UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
|
||||
CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
|
||||
2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
@@ -518,74 +518,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownCriticalExtension(t *testing.T) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to generate ECDSA key: %s", err)
|
||||
}
|
||||
|
||||
oids := []asn1.ObjectIdentifier{
|
||||
// This OID is in the PKIX arc, but unknown.
|
||||
{2, 5, 29, 999999},
|
||||
// This is a nonsense, unassigned OID.
|
||||
{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
for _, oid := range oids {
|
||||
template := Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{
|
||||
CommonName: "foo",
|
||||
},
|
||||
NotBefore: time.Unix(1000, 0),
|
||||
NotAfter: time.Now().AddDate(1, 0, 0),
|
||||
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
|
||||
KeyUsage: KeyUsageCertSign,
|
||||
ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
|
||||
|
||||
ExtraExtensions: []pkix.Extension{
|
||||
{
|
||||
Id: oid,
|
||||
Critical: true,
|
||||
Value: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create certificate: %s", err)
|
||||
}
|
||||
|
||||
cert, err := ParseCertificate(derBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err)
|
||||
}
|
||||
|
||||
roots := NewCertPool()
|
||||
roots.AddCert(cert)
|
||||
|
||||
// Setting Roots ensures that Verify won't delegate to the OS
|
||||
// library and thus the correct error should always be
|
||||
// returned.
|
||||
_, err = cert.Verify(VerifyOptions{Roots: roots})
|
||||
if err == nil {
|
||||
t.Fatal("Certificate with unknown critical extension was verified without error")
|
||||
}
|
||||
if _, ok := err.(UnhandledCriticalExtension); !ok {
|
||||
t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
|
||||
}
|
||||
|
||||
cert.UnhandledCriticalExtensions = nil
|
||||
if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil {
|
||||
t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Self-signed certificate using ECDSA with SHA1 & secp256r1
|
||||
var ecdsaSHA1CertPem = `
|
||||
-----BEGIN CERTIFICATE-----
|
||||
|
||||
@@ -1487,6 +1487,26 @@ func TestSqrt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// We can't test this together with the other Exp tests above because
|
||||
// it requires a different receiver setup.
|
||||
func TestIssue22830(t *testing.T) {
|
||||
one := new(Int).SetInt64(1)
|
||||
base, _ := new(Int).SetString("84555555300000000000", 10)
|
||||
mod, _ := new(Int).SetString("66666670001111111111", 10)
|
||||
want, _ := new(Int).SetString("17888885298888888889", 10)
|
||||
|
||||
var tests = []int64{
|
||||
0, 1, -1,
|
||||
}
|
||||
|
||||
for _, n := range tests {
|
||||
m := NewInt(n)
|
||||
if got := m.Exp(base, one, mod); got.Cmp(want) != 0 {
|
||||
t.Errorf("(%v).Exp(%s, 1, %s) = %s, want %s", n, base, mod, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSqrt(b *testing.B) {
|
||||
n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10)
|
||||
b.ResetTimer()
|
||||
|
||||
@@ -575,8 +575,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
|
||||
// determine if z can be reused
|
||||
// TODO(gri) should find a better solution - this if statement
|
||||
// is very costly (see e.g. time pidigits -s -n 10000)
|
||||
if alias(z, uIn) || alias(z, v) {
|
||||
z = nil // z is an alias for uIn or v - cannot reuse
|
||||
if alias(z, u) || alias(z, uIn) || alias(z, v) {
|
||||
z = nil // z is an alias for u or uIn or v - cannot reuse
|
||||
}
|
||||
q = z.make(m + 1)
|
||||
|
||||
|
||||
@@ -225,6 +225,8 @@ func dialClosedPort() (actual, expected time.Duration) {
|
||||
// but other platforms should be instantaneous.
|
||||
if runtime.GOOS == "windows" {
|
||||
expected = 1500 * time.Millisecond
|
||||
} else if runtime.GOOS == "darwin" {
|
||||
expected = 150 * time.Millisecond
|
||||
} else {
|
||||
expected = 95 * time.Millisecond
|
||||
}
|
||||
|
||||
@@ -1091,7 +1091,12 @@ func TestLinuxSendfile(t *testing.T) {
|
||||
// and will error out if we specify that with `-e trace='.
|
||||
syscalls = "sendfile"
|
||||
case "mips64":
|
||||
t.Skip("TODO: update this test to be robust against various versions of strace on mips64. See golang.org/issue/33430")
|
||||
t.Skip("TODO: update this test to be robust against various versions of strace on mips64. See golang.org/issue/18008")
|
||||
}
|
||||
|
||||
// Attempt to run strace, and skip on failure - this test requires SYS_PTRACE.
|
||||
if err := exec.Command("strace", "-f", "-q", "-e", "trace="+syscalls, os.Args[0], "-test.run=^$").Run(); err != nil {
|
||||
t.Skipf("skipping; failed to run strace: %v", err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
@@ -503,21 +503,26 @@ func TestInterfaceAddrsWithNetsh(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getmacSpeaksEnglish(t *testing.T) bool {
|
||||
// check that getmac exists as a powershell command, and that it
|
||||
// speaks English.
|
||||
func checkGetmac(t *testing.T) {
|
||||
out, err := runCmd("getmac", "/?")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "term 'getmac' is not recognized as the name of a cmdlet") {
|
||||
t.Skipf("getmac not available")
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
return bytes.Contains(out, []byte("network adapters on a system"))
|
||||
if !bytes.Contains(out, []byte("network adapters on a system")) {
|
||||
t.Skipf("skipping test on non-English system")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterfaceHardwareAddrWithGetmac(t *testing.T) {
|
||||
if isWindowsXP(t) {
|
||||
t.Skip("Windows XP does not have powershell command")
|
||||
}
|
||||
if !getmacSpeaksEnglish(t) {
|
||||
t.Skip("English version of getmac required for this test")
|
||||
}
|
||||
checkGetmac(t)
|
||||
|
||||
ift, err := Interfaces()
|
||||
if err != nil {
|
||||
|
||||
@@ -44,26 +44,29 @@ type plainAuth struct {
|
||||
}
|
||||
|
||||
// PlainAuth returns an Auth that implements the PLAIN authentication
|
||||
// mechanism as defined in RFC 4616.
|
||||
// The returned Auth uses the given username and password to authenticate
|
||||
// on TLS connections to host and act as identity. Usually identity will be
|
||||
// left blank to act as username.
|
||||
// mechanism as defined in RFC 4616. The returned Auth uses the given
|
||||
// username and password to authenticate to host and act as identity.
|
||||
// Usually identity should be the empty string, to act as username.
|
||||
//
|
||||
// PlainAuth will only send the credentials if the connection is using TLS
|
||||
// or is connected to localhost. Otherwise authentication will fail with an
|
||||
// error, without sending the credentials.
|
||||
func PlainAuth(identity, username, password, host string) Auth {
|
||||
return &plainAuth{identity, username, password, host}
|
||||
}
|
||||
|
||||
func isLocalhost(name string) bool {
|
||||
return name == "localhost" || name == "127.0.0.1" || name == "::1"
|
||||
}
|
||||
|
||||
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
|
||||
if !server.TLS {
|
||||
advertised := false
|
||||
for _, mechanism := range server.Auth {
|
||||
if mechanism == "PLAIN" {
|
||||
advertised = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !advertised {
|
||||
return "", nil, errors.New("unencrypted connection")
|
||||
}
|
||||
// Must have TLS, or else localhost server.
|
||||
// Note: If TLS is not true, then we can't trust ANYTHING in ServerInfo.
|
||||
// In particular, it doesn't matter if the server advertises PLAIN auth.
|
||||
// That might just be the attacker saying
|
||||
// "it's ok, you can trust me with your password."
|
||||
if !server.TLS && !isLocalhost(server.Name) {
|
||||
return "", nil, errors.New("unencrypted connection")
|
||||
}
|
||||
if server.Name != a.host {
|
||||
return "", nil, errors.New("wrong host name")
|
||||
|
||||
@@ -67,6 +67,7 @@ func NewClient(conn net.Conn, host string) (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
c := &Client{Text: text, conn: conn, serverName: host, localName: "localhost"}
|
||||
_, c.tls = conn.(*tls.Conn)
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -60,29 +60,41 @@ testLoop:
|
||||
}
|
||||
|
||||
func TestAuthPlain(t *testing.T) {
|
||||
auth := PlainAuth("foo", "bar", "baz", "servername")
|
||||
|
||||
tests := []struct {
|
||||
server *ServerInfo
|
||||
err string
|
||||
authName string
|
||||
server *ServerInfo
|
||||
err string
|
||||
}{
|
||||
{
|
||||
server: &ServerInfo{Name: "servername", TLS: true},
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "servername", TLS: true},
|
||||
},
|
||||
{
|
||||
// Okay; explicitly advertised by server.
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
|
||||
// OK to use PlainAuth on localhost without TLS
|
||||
authName: "localhost",
|
||||
server: &ServerInfo{Name: "localhost", TLS: false},
|
||||
},
|
||||
{
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
|
||||
err: "unencrypted connection",
|
||||
// NOT OK on non-localhost, even if server says PLAIN is OK.
|
||||
// (We don't know that the server is the real server.)
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
|
||||
err: "unencrypted connection",
|
||||
},
|
||||
{
|
||||
server: &ServerInfo{Name: "attacker", TLS: true},
|
||||
err: "wrong host name",
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
|
||||
err: "unencrypted connection",
|
||||
},
|
||||
{
|
||||
authName: "servername",
|
||||
server: &ServerInfo{Name: "attacker", TLS: true},
|
||||
err: "wrong host name",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
auth := PlainAuth("foo", "bar", "baz", tt.authName)
|
||||
_, _, err := auth.Start(tt.server)
|
||||
got := ""
|
||||
if err != nil {
|
||||
@@ -350,6 +362,53 @@ HELO localhost
|
||||
QUIT
|
||||
`
|
||||
|
||||
func TestNewClientWithTLS(t *testing.T) {
|
||||
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
||||
if err != nil {
|
||||
t.Fatalf("loadcert: %v", err)
|
||||
}
|
||||
|
||||
config := tls.Config{Certificates: []tls.Certificate{cert}}
|
||||
|
||||
ln, err := tls.Listen("tcp", "127.0.0.1:0", &config)
|
||||
if err != nil {
|
||||
ln, err = tls.Listen("tcp", "[::1]:0", &config)
|
||||
if err != nil {
|
||||
t.Fatalf("server: listen: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
conn, err := ln.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("server: accept: %s", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
_, err = conn.Write([]byte("220 SIGNS\r\n"))
|
||||
if err != nil {
|
||||
t.Fatalf("server: write: %s", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
config.InsecureSkipVerify = true
|
||||
conn, err := tls.Dial("tcp", ln.Addr().String(), &config)
|
||||
if err != nil {
|
||||
t.Fatalf("client: dial: %s", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client, err := NewClient(conn, ln.Addr().String())
|
||||
if err != nil {
|
||||
t.Fatalf("smtp: newclient: %s", err)
|
||||
}
|
||||
if !client.tls {
|
||||
t.Errorf("client.tls Got: %t Expected: %t", client.tls, true)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHello(t *testing.T) {
|
||||
|
||||
if len(helloServer) != len(helloClient) {
|
||||
|
||||
@@ -404,6 +404,8 @@ func TestDirectorySymbolicLink(t *testing.T) {
|
||||
func TestNetworkSymbolicLink(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
const _NERR_ServerNotStarted = syscall.Errno(2114)
|
||||
|
||||
dir, err := ioutil.TempDir("", "TestNetworkSymbolicLink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -454,6 +456,9 @@ func TestNetworkSymbolicLink(t *testing.T) {
|
||||
if err == syscall.ERROR_ACCESS_DENIED {
|
||||
t.Skip("you don't have enough privileges to add network share")
|
||||
}
|
||||
if err == _NERR_ServerNotStarted {
|
||||
t.Skip(_NERR_ServerNotStarted.Error())
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
|
||||
@@ -169,7 +169,7 @@ func TestPeriodicGC(t *testing.T) {
|
||||
// slack if things are slow.
|
||||
var numGCs uint32
|
||||
const want = 2
|
||||
for i := 0; i < 20 && numGCs < want; i++ {
|
||||
for i := 0; i < 200 && numGCs < want; i++ {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
|
||||
// Test that periodic GC actually happened.
|
||||
|
||||
@@ -100,7 +100,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
|
||||
MOVL AX, 0(SP)
|
||||
MOVL $1000, AX // usec to nsec
|
||||
MULL DX
|
||||
MOVL DX, 4(SP)
|
||||
MOVL AX, 4(SP)
|
||||
|
||||
// pselect6(0, 0, 0, 0, &ts, 0)
|
||||
MOVL $308, AX
|
||||
|
||||
34
test/fixedbugs/issue20530.go
Normal file
34
test/fixedbugs/issue20530.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
var a uint8
|
||||
|
||||
//go:noinline
|
||||
func f() {
|
||||
b := int8(func() int32 { return -1 }())
|
||||
a = uint8(b)
|
||||
if int32(a) != 255 {
|
||||
// Failing case prints 'got 255 expected 255'
|
||||
println("got", a, "expected 255")
|
||||
}
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func g() {
|
||||
b := int8(func() uint32 { return 0xffffffff }())
|
||||
a = uint8(b)
|
||||
if int32(a) != 255 {
|
||||
// Failing case prints 'got 255 expected 255'
|
||||
println("got", a, "expected 255")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f()
|
||||
g()
|
||||
}
|
||||
Reference in New Issue
Block a user