mirror of
https://github.com/golang/go
synced 2024-11-26 08:17:59 -07:00
[dev.regabi] all: merge master (bf0f7c9
) into dev.regabi
This merge involved two merge conflicts: 1. walk's ascompatee code has been substantially refactored on dev.regabi, so CL 285633 is ported to the new style. 2. The os.TestDirFS workaround added in CL 286213 can be removed now that #42637 has been fixed by CL 285720. Conflicts: - src/cmd/compile/internal/gc/walk.go - src/os/os_test.go Merge List: + 2021-01-25bf0f7c9d78
doc/go1.16: mention os.DirFS in os section + 2021-01-25deaf29a8a8
cmd/compile: fix order-of-assignment issue w/ defers + 2021-01-25ad2ca26a52
doc/go1.16: mention os.DirEntry and types moved from os to io/fs + 2021-01-25a51921fa5b
doc/go1.16: mention new testing/iotest functions + 2021-01-25e6b6d107f7
doc/go1.16: mention deprecation of io/ioutil + 2021-01-2596a276363b
doc/go1.16: mention go/build changes + 2021-01-253d85c69a0b
html/template: revert "avoid race when escaping updates template" + 2021-01-2554514c6b28
cmd/go: fix TestScript/cgo_path, cgo_path_space when CC set + 2021-01-256de8443f3b
doc/asm: add a section on go_asm.h, clean up go_tls.h section + 2021-01-2554b251f542
lib/time, time/tzdata: update tzdata to 2021a + 2021-01-25ff82cc971a
os: force consistent mtime before running fstest on directory on Windows + 2021-01-25044f937a73
doc/go1.16: fix WalkDir and Walk links + 2021-01-23b634f5d97a
doc/go1.16: add crypto/x509 memory optimization + 2021-01-239897655c61
doc/go1.16: reword ambiguously parsable sentence + 2021-01-23cd99385ff4
cmd/internal/obj/arm64: fix VMOVQ instruction encoding error + 2021-01-2366ee8b158f
runtime: restore cgo_import_dynamic for libc.so on openbsd + 2021-01-2225c39e4fb5
io/ioutil: fix example test for WriteFile to allow it to run in the playground + 2021-01-22eb21b31e48
runtime: define dummy msanmove + 2021-01-223a778ff50f
runtime: check for g0 stack last in signal handler + 2021-01-22a2cef9b544
cmd/go: don't lookup the path for CC when invoking cgo Change-Id: I651949f9eb18b57e3c996c4f3b2b3bf458bc5d97
This commit is contained in:
commit
5e4a0cdde3
72
doc/asm.html
72
doc/asm.html
@ -464,6 +464,57 @@ Function is the top of the call stack. Traceback should stop at this function.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3 id="data-offsets">Interacting with Go types and constants</h3>
|
||||
|
||||
<p>
|
||||
If a package has any .s files, then <code>go build</code> will direct
|
||||
the compiler to emit a special header called <code>go_asm.h</code>,
|
||||
which the .s files can then <code>#include</code>.
|
||||
The file contains symbolic <code>#define</code> constants for the
|
||||
offsets of Go struct fields, the sizes of Go struct types, and most
|
||||
Go <code>const</code> declarations defined in the current package.
|
||||
Go assembly should avoid making assumptions about the layout of Go
|
||||
types and instead use these constants.
|
||||
This improves the readability of assembly code, and keeps it robust to
|
||||
changes in data layout either in the Go type definitions or in the
|
||||
layout rules used by the Go compiler.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Constants are of the form <code>const_<i>name</i></code>.
|
||||
For example, given the Go declaration <code>const bufSize =
|
||||
1024</code>, assembly code can refer to the value of this constant
|
||||
as <code>const_bufSize</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Field offsets are of the form <code><i>type</i>_<i>field</i></code>.
|
||||
Struct sizes are of the form <code><i>type</i>__size</code>.
|
||||
For example, consider the following Go definition:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type reader struct {
|
||||
buf [bufSize]byte
|
||||
r int
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Assembly can refer to the size of this struct
|
||||
as <code>reader__size</code> and the offsets of the two fields
|
||||
as <code>reader_buf</code> and <code>reader_r</code>.
|
||||
Hence, if register <code>R1</code> contains a pointer to
|
||||
a <code>reader</code>, assembly can reference the <code>r</code> field
|
||||
as <code>reader_r(R1)</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If any of these <code>#define</code> names are ambiguous (for example,
|
||||
a struct with a <code>_size</code> field), <code>#include
|
||||
"go_asm.h"</code> will fail with a "redefinition of macro" error.
|
||||
</p>
|
||||
|
||||
<h3 id="runtime">Runtime Coordination</h3>
|
||||
|
||||
<p>
|
||||
@ -615,21 +666,15 @@ Here follow some descriptions of key Go-specific details for the supported archi
|
||||
<p>
|
||||
The runtime pointer to the <code>g</code> structure is maintained
|
||||
through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
|
||||
An OS-dependent macro <code>get_tls</code> is defined for the assembler if the source is
|
||||
in the <code>runtime</code> package and includes a special header, <code>go_tls.h</code>:
|
||||
In the runtime package, assembly code can include <code>go_tls.h</code>, which defines
|
||||
an OS- and architecture-dependent macro <code>get_tls</code> for accessing this register.
|
||||
The <code>get_tls</code> macro takes one argument, which is the register to load the
|
||||
<code>g</code> pointer into.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
#include "go_tls.h"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Within the runtime, the <code>get_tls</code> macro loads its argument register
|
||||
with a pointer to the <code>g</code> pointer, and the <code>g</code> struct
|
||||
contains the <code>m</code> pointer.
|
||||
There's another special header containing the offsets for each
|
||||
element of <code>g</code>, called <code>go_asm.h</code>.
|
||||
The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> looks like this:
|
||||
For example, the sequence to load <code>g</code> and <code>m</code>
|
||||
using <code>CX</code> looks like this:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
@ -642,8 +687,7 @@ MOVL g_m(AX), BX // Move g.m into BX.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Note: The code above works only in the <code>runtime</code> package, while <code>go_tls.h</code> also
|
||||
applies to <a href="#arm">arm</a>, <a href="#amd64">amd64</a> and amd64p32, and <code>go_asm.h</code> applies to all architectures.
|
||||
The <code>get_tls</code> macro is also defined on <a href="#amd64">amd64</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
163
doc/go1.16.html
163
doc/go1.16.html
@ -461,10 +461,10 @@ func TestFoo(t *testing.T) {
|
||||
|
||||
<p>
|
||||
The new <a href="/pkg/io/fs/"><code>io/fs</code></a> package
|
||||
defines an abstraction for read-only trees of files,
|
||||
the <a href="/pkg/io/fs/#FS"><code>fs.FS</code></a> interface,
|
||||
and the standard library packages have
|
||||
been adapted to make use of the interface as appropriate.
|
||||
defines the <a href="/pkg/io/fs/#FS"><code>fs.FS</code></a> interface,
|
||||
an abstraction for read-only trees of files.
|
||||
The standard library packages have been adapted to make use
|
||||
of the interface as appropriate.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
@ -499,6 +499,44 @@ func TestFoo(t *testing.T) {
|
||||
implementations.
|
||||
</p>
|
||||
|
||||
<h3 id="ioutil">Deprecation of io/ioutil</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/io/ioutil/"><code>io/ioutil</code></a> package has
|
||||
turned out to be a poorly defined and hard to understand collection
|
||||
of things. All functionality provided by the package has been moved
|
||||
to other packages. The <code>io/ioutil</code> package remains and
|
||||
will continue to work as before, but we encourage new code to use
|
||||
the new definitions in the <a href="/pkg/io/"><code>io</code></a> and
|
||||
<a href="/pkg/os/"><code>os</code></a> packages.
|
||||
|
||||
Here is a list of the new locations of the names exported
|
||||
by <code>io/ioutil</code>:
|
||||
<ul>
|
||||
<li><a href="/pkg/io/ioutil/#Discard"><code>Discard</code></a>
|
||||
=> <a href="/pkg/io/#Discard"><code>io.Discard</code></a></li>
|
||||
<li><a href="/pkg/io/ioutil/#NopCloser"><code>NopCloser</code></a>
|
||||
=> <a href="/pkg/io/#NopCloser"><code>io.NopCloser</code></a></li>
|
||||
<li><a href="/pkg/io/ioutil/#ReadAll"><code>ReadAll</code></a>
|
||||
=> <a href="/pkg/io/#ReadAll"><code>io.ReadAll</code></a></li>
|
||||
<li><a href="/pkg/io/ioutil/#ReadDir"><code>ReadDir</code></a>
|
||||
=> <a href="/pkg/os/#ReadDir"><code>os.ReadDir</code></a>
|
||||
(note: returns a slice of
|
||||
<a href="/pkg/os/#DirEntry"><code>os.DirEntry</code></a>
|
||||
rather than a slice of
|
||||
<a href="/pkg/fs/#FileInfo"><code>fs.FileInfo</code></a>)
|
||||
</li>
|
||||
<li><a href="/pkg/io/ioutil/#ReadFile"><code>ReadFile</code></a>
|
||||
=> <a href="/pkg/os/#ReadFile"><code>os.ReadFile</code></a></li>
|
||||
<li><a href="/pkg/io/ioutil/#TempDir"><code>TempDir</code></a>
|
||||
=> <a href="/pkg/os/#MkdirTemp"><code>os.MkdirTemp</code></a></li>
|
||||
<li><a href="/pkg/io/ioutil/#TempFile"><code>TempFile</code></a>
|
||||
=> <a href="/pkg/os/#CreateTemp"><code>os.CreateTemp</code></a></li>
|
||||
<li><a href="/pkg/io/ioutil/#WriteFile"><code>WriteFile</code></a>
|
||||
=> <a href="/pkg/os/#WriteFile"><code>os.WriteFile</code></a></li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<!-- okay-after-beta1
|
||||
TODO: decide if any additional changes are worth factoring out from
|
||||
"Minor changes to the library" and highlighting in "Core library"
|
||||
@ -623,6 +661,14 @@ func TestFoo(t *testing.T) {
|
||||
method allows accessing the <a href="/pkg/crypto/x509/#SystemRootsError.Err"><code>Err</code></a>
|
||||
field through the <a href="/pkg/errors"><code>errors</code></a> package functions.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 230025 -->
|
||||
On Unix systems, the <code>crypto/x509</code> package is now more
|
||||
efficient in how it stores its copy of the system cert pool.
|
||||
Programs that use only a small number of roots will use around a
|
||||
half megabyte less memory.
|
||||
</p>
|
||||
|
||||
</dd>
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
@ -685,6 +731,37 @@ func TestFoo(t *testing.T) {
|
||||
</dd>
|
||||
</dl><!-- flag -->
|
||||
|
||||
<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 243941, CL 283636 -->
|
||||
The <a href="/pkg/go/build/#Package"><code>Package</code></a>
|
||||
struct has new fields that report information
|
||||
about <code>//go:embed</code> directives in the package:
|
||||
<a href="/pkg/go/build/#Package.EmbedPatterns"><code>EmbedPatterns</code></a>,
|
||||
<a href="/pkg/go/build/#Package.EmbedPatternPos"><code>EmbedPatternPos</code></a>,
|
||||
<a href="/pkg/go/build/#Package.TestEmbedPatterns"><code>TestEmbedPatterns</code></a>,
|
||||
<a href="/pkg/go/build/#Package.TestEmbedPatternPos"><code>TestEmbedPatternPos</code></a>,
|
||||
<a href="/pkg/go/build/#Package.XTestEmbedPatterns"><code>XTestEmbedPatterns</code></a>,
|
||||
<a href="/pkg/go/build/#Package.XTestEmbedPatternPos"><code>XTestEmbedPatternPos</code></a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 240551 -->
|
||||
The <a href="/pkg/go/build/#Package"><code>Package</code></a> field
|
||||
<a href="/pkg/go/build/#Package.IgnoredGoFiles"><code>IgnoredGoFiles</code></a>
|
||||
will no longer include files that start with "_" or ".",
|
||||
as those files are always ignored.
|
||||
<code>IgnoredGoFiles</code> is for files ignored because of
|
||||
build constraints.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 240551 -->
|
||||
The new <a href="/pkg/go/build/#Package"><code>Package</code></a>
|
||||
field <a href="/pkg/go/build/#Package.IgnoredOtherFiles"><code>IgnoredOtherFiles</code></a>
|
||||
has a list of non-Go files ignored because of build constraints.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- go/build -->
|
||||
|
||||
<dl id="html/template"><dt><a href="/pkg/html/template/">html/template</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 243938 -->
|
||||
@ -703,6 +780,15 @@ func TestFoo(t *testing.T) {
|
||||
The package now defines a
|
||||
<a href="/pkg/io/#ReadSeekCloser"><code>ReadSeekCloser</code></a> interface.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 263141 -->
|
||||
The package now defines
|
||||
<a href="/pkg/io/#Discard"><code>Discard</code></a>,
|
||||
<a href="/pkg/io/#NopCloser"><code>NopCloser</code></a>, and
|
||||
<a href="/pkg/io/#ReadAll"><code>ReadAll</code></a>,
|
||||
to be used instead of the same names in the
|
||||
<a href="/pkg/io/ioutil/"><code>io/ioutil</code></a> package.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- io -->
|
||||
|
||||
@ -857,6 +943,52 @@ func TestFoo(t *testing.T) {
|
||||
instead of the unexported <code>errFinished</code> when the process has
|
||||
already finished.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 261540 -->
|
||||
The package defines a new type
|
||||
<a href="/pkg/os/#DirEntry"><code>DirEntry</code></a>
|
||||
as an alias for <a href="/pkg/io/fs/#DirEntry"><code>fs.DirEntry</code></a>.
|
||||
The new <a href="/pkg/os/#ReadDir"><code>ReadDir</code></a>
|
||||
function and the new
|
||||
<a href="/pkg/os/#File.ReadDir"><code>File.ReadDir</code></a>
|
||||
method can be used to read the contents of a directory into a
|
||||
slice of <a href="/pkg/os/#DirEntry"><code>DirEntry</code></a>.
|
||||
The <a href="/pkg/os/#File.Readdir"><code>File.Readdir</code></a>
|
||||
method (note the lower case <code>d</code> in <code>dir</code>)
|
||||
still exists, returning a slice of
|
||||
<a href="/pkg/os/#FileInfo"><code>FileInfo</code></a>, but for
|
||||
most programs it will be more efficient to switch to
|
||||
<a href="/pkg/os/#File.ReadDir"><code>File.ReadDir</code></a>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 263141 -->
|
||||
The package now defines
|
||||
<a href="/pkg/os/#CreateTemp"><code>CreateTemp</code></a>,
|
||||
<a href="/pkg/os/#MkdirTemp"><code>MkdirTemp</code></a>,
|
||||
<a href="/pkg/os/#ReadFile"><code>ReadFile</code></a>, and
|
||||
<a href="/pkg/os/#WriteFile"><code>WriteFile</code></a>,
|
||||
to be used instead of functions defined in the
|
||||
<a href="/pkg/io/ioutil/"><code>io/ioutil</code></a> package.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 243906 -->
|
||||
The types <a href="/pkg/os/#FileInfo"><code>FileInfo</code></a>,
|
||||
<a href="/pkg/os/#FileMode"><code>FileMode</code></a>, and
|
||||
<a href="/pkg/os/#PathError"><code>PathError</code></a>
|
||||
are now aliases for types of the same name in the
|
||||
<a href="/pkg/io/fs/"><code>io/fs</code></a> package.
|
||||
Function signatures in the <a href="/pkg/os/"><code>os</code></a>
|
||||
package have been updated to refer to the names in the
|
||||
<a href="/pkg/io/fs/"><code>io/fs</code></a> package.
|
||||
This should not affect any existing code.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 243911 -->
|
||||
The new <a href="/pkg/os/#DirFS"><code>DirFS</code></a> function
|
||||
provides an implementation of
|
||||
<a href="/pkg/io/fs/#FS"><code>fs.FS</code></a> backed by a tree
|
||||
of operating system files.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- os -->
|
||||
|
||||
@ -887,9 +1019,9 @@ func TestFoo(t *testing.T) {
|
||||
<dd>
|
||||
<p><!-- CL 267887 -->
|
||||
The new function
|
||||
<a href="/pkg/path/filepath/WalkDir"><code>WalkDir</code></a>
|
||||
<a href="/pkg/path/filepath/#WalkDir"><code>WalkDir</code></a>
|
||||
is similar to
|
||||
<a href="/pkg/path/filepath/Walk"><code>Walk</code></a>,
|
||||
<a href="/pkg/path/filepath/#Walk"><code>Walk</code></a>,
|
||||
but is typically more efficient.
|
||||
The function passed to <code>WalkDir</code> receives a
|
||||
<a href="/pkg/io/fs/#DirEntry"><code>fs.DirEntry</code></a>
|
||||
@ -975,6 +1107,25 @@ func TestFoo(t *testing.T) {
|
||||
</dd>
|
||||
</dl><!-- syscall -->
|
||||
|
||||
<dl id="testing/iotest"><dt><a href="/pkg/testing/iotest/">testing/iotest</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 199501 -->
|
||||
The new
|
||||
<a href="/pkg/testing/iotest/#ErrReader"><code>ErrReader</code></a>
|
||||
function returns an
|
||||
<a href="/pkg/io/#Reader"><code>io.Reader</code></a> that always
|
||||
returns an error.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 243909 -->
|
||||
The new
|
||||
<a href="/pkg/testing/iotest/#TestReader"><code>TestReader</code></a>
|
||||
function tests that an <a href="/pkg/io/#Reader"><code>io.Reader</code></a>
|
||||
behaves correctly.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- testing/iotest -->
|
||||
|
||||
<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 254257, golang.org/issue/29770 -->
|
||||
|
@ -8,8 +8,8 @@
|
||||
# Consult https://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2020f
|
||||
DATA=2020f
|
||||
CODE=2021a
|
||||
DATA=2021a
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
Binary file not shown.
@ -289,11 +289,14 @@ func ascompatee(op ir.Op, nl, nr []ir.Node) []ir.Node {
|
||||
}
|
||||
|
||||
var assigned ir.NameSet
|
||||
var memWrite bool
|
||||
var memWrite, deferResultWrite bool
|
||||
|
||||
// affected reports whether expression n could be affected by
|
||||
// the assignments applied so far.
|
||||
affected := func(n ir.Node) bool {
|
||||
if deferResultWrite {
|
||||
return true
|
||||
}
|
||||
return ir.Any(n, func(n ir.Node) bool {
|
||||
if n.Op() == ir.ONAME && assigned.Has(n.(*ir.Name)) {
|
||||
return true
|
||||
@ -369,21 +372,40 @@ func ascompatee(op ir.Op, nl, nr []ir.Node) []ir.Node {
|
||||
|
||||
appendWalkStmt(&late, convas(ir.NewAssignStmt(base.Pos, lorig, r), &late))
|
||||
|
||||
if name != nil && ir.IsBlank(name) {
|
||||
// We can ignore assignments to blank.
|
||||
continue
|
||||
}
|
||||
if op == ir.ORETURN && types.OrigSym(name.Sym()) == nil {
|
||||
// We can also ignore assignments to anonymous result
|
||||
// parameters. These can't appear in expressions anyway.
|
||||
// Check for reasons why we may need to compute later expressions
|
||||
// before this assignment happens.
|
||||
|
||||
if name == nil {
|
||||
// Not a direct assignment to a declared variable.
|
||||
// Conservatively assume any memory access might alias.
|
||||
memWrite = true
|
||||
continue
|
||||
}
|
||||
|
||||
if name != nil && name.OnStack() && !name.Addrtaken() {
|
||||
assigned.Add(name)
|
||||
} else {
|
||||
memWrite = true
|
||||
if name.Class == ir.PPARAMOUT && ir.CurFunc.HasDefer() {
|
||||
// Assignments to a result parameter in a function with defers
|
||||
// becomes visible early if evaluation of any later expression
|
||||
// panics (#43835).
|
||||
deferResultWrite = true
|
||||
continue
|
||||
}
|
||||
|
||||
if sym := types.OrigSym(name.Sym()); sym == nil || sym.IsBlank() {
|
||||
// We can ignore assignments to blank or anonymous result parameters.
|
||||
// These can't appear in expressions anyway.
|
||||
continue
|
||||
}
|
||||
|
||||
if name.Addrtaken() || !name.OnStack() {
|
||||
// Global variable, heap escaped, or just addrtaken.
|
||||
// Conservatively assume any memory access might alias.
|
||||
memWrite = true
|
||||
continue
|
||||
}
|
||||
|
||||
// Local, non-addrtaken variable.
|
||||
// Assignments can only alias with direct uses of this variable.
|
||||
assigned.Add(name)
|
||||
}
|
||||
|
||||
early.Append(late.Take()...)
|
||||
|
@ -57,9 +57,6 @@ type Builder struct {
|
||||
id sync.Mutex
|
||||
toolIDCache map[string]string // tool name -> tool ID
|
||||
buildIDCache map[string]string // file name -> build ID
|
||||
|
||||
cgoEnvOnce sync.Once
|
||||
cgoEnvCache []string
|
||||
}
|
||||
|
||||
// NOTE: Much of Action would not need to be exported if not for test.
|
||||
|
@ -1165,7 +1165,10 @@ func (b *Builder) vet(ctx context.Context, a *Action) error {
|
||||
}
|
||||
|
||||
// TODO(rsc): Why do we pass $GCCGO to go vet?
|
||||
env := b.cgoEnv()
|
||||
env := b.cCompilerEnv()
|
||||
if cfg.BuildToolchainName == "gccgo" {
|
||||
env = append(env, "GCCGO="+BuildToolchain.compiler())
|
||||
}
|
||||
|
||||
p := a.Package
|
||||
tool := VetTool
|
||||
@ -2111,24 +2114,6 @@ func (b *Builder) cCompilerEnv() []string {
|
||||
return []string{"TERM=dumb"}
|
||||
}
|
||||
|
||||
// cgoEnv returns environment variables to set when running cgo.
|
||||
// Some of these pass through to cgo running the C compiler,
|
||||
// so it includes cCompilerEnv.
|
||||
func (b *Builder) cgoEnv() []string {
|
||||
b.cgoEnvOnce.Do(func() {
|
||||
cc, err := exec.LookPath(b.ccExe()[0])
|
||||
if err != nil || filepath.Base(cc) == cc { // reject relative path
|
||||
cc = "/missing-cc"
|
||||
}
|
||||
gccgo := GccgoBin
|
||||
if filepath.Base(gccgo) == gccgo { // reject relative path
|
||||
gccgo = "/missing-gccgo"
|
||||
}
|
||||
b.cgoEnvCache = append(b.cCompilerEnv(), "CC="+cc, "GCCGO="+gccgo)
|
||||
})
|
||||
return b.cgoEnvCache
|
||||
}
|
||||
|
||||
// mkdir makes the named directory.
|
||||
func (b *Builder) Mkdir(dir string) error {
|
||||
// Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "".
|
||||
@ -2729,7 +2714,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
||||
// along to the host linker. At this point in the code, cgoLDFLAGS
|
||||
// consists of the original $CGO_LDFLAGS (unchecked) and all the
|
||||
// flags put together from source code (checked).
|
||||
cgoenv := b.cgoEnv()
|
||||
cgoenv := b.cCompilerEnv()
|
||||
if len(cgoLDFLAGS) > 0 {
|
||||
flags := make([]string, len(cgoLDFLAGS))
|
||||
for i, f := range cgoLDFLAGS {
|
||||
@ -2966,7 +2951,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe
|
||||
if p.Standard && p.ImportPath == "runtime/cgo" {
|
||||
cgoflags = []string{"-dynlinker"} // record path to dynamic linker
|
||||
}
|
||||
return b.run(a, base.Cwd, p.ImportPath, b.cgoEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
|
||||
return b.run(a, base.Cwd, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
|
||||
}
|
||||
|
||||
// Run SWIG on all SWIG input files.
|
||||
|
12
src/cmd/go/testdata/script/cgo_path.txt
vendored
12
src/cmd/go/testdata/script/cgo_path.txt
vendored
@ -1,12 +1,20 @@
|
||||
[!cgo] skip
|
||||
|
||||
# Set CC explicitly to something that requires a PATH lookup.
|
||||
# Normally, the default is gcc or clang, but if CC was set during make.bash,
|
||||
# that becomes the default.
|
||||
[exec:clang] env CC=clang
|
||||
[exec:gcc] env CC=gcc
|
||||
[!exec:clang] [!exec:gcc] skip 'Unknown C compiler'
|
||||
|
||||
env GOCACHE=$WORK/gocache # Looking for compile flags, so need a clean cache.
|
||||
[!windows] env PATH=.:$PATH
|
||||
[!windows] chmod 0777 p/gcc p/clang
|
||||
[!windows] chmod 0755 p/gcc p/clang
|
||||
[!windows] exists -exec p/gcc p/clang
|
||||
[windows] exists -exec p/gcc.bat p/clang.bat
|
||||
! exists p/bug.txt
|
||||
go build -x
|
||||
! go build -x
|
||||
stderr '^cgo: exec (clang|gcc): (clang|gcc) resolves to executable relative to current directory \(.[/\\](clang|gcc)(.bat)?\)$'
|
||||
! exists p/bug.txt
|
||||
|
||||
-- go.mod --
|
||||
|
56
src/cmd/go/testdata/script/cgo_path_space.txt
vendored
Normal file
56
src/cmd/go/testdata/script/cgo_path_space.txt
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
# Check that if the PATH directory containing the C compiler has a space,
|
||||
# we can still use that compiler with cgo.
|
||||
# Verifies #43808.
|
||||
[!cgo] skip
|
||||
|
||||
# Set CC explicitly to something that requires a PATH lookup.
|
||||
# Normally, the default is gcc or clang, but if CC was set during make.bash,
|
||||
# that becomes the default.
|
||||
[exec:clang] env CC=clang
|
||||
[exec:gcc] env CC=gcc
|
||||
[!exec:clang] [!exec:gcc] skip 'Unknown C compiler'
|
||||
|
||||
[!windows] chmod 0755 $WORK/'program files'/clang
|
||||
[!windows] chmod 0755 $WORK/'program files'/gcc
|
||||
[!windows] exists -exec $WORK/'program files'/clang
|
||||
[!windows] exists -exec $WORK/'program files'/gcc
|
||||
[!windows] env PATH=$WORK/'program files':$PATH
|
||||
[windows] exists -exec $WORK/'program files'/gcc.bat
|
||||
[windows] exists -exec $WORK/'program files'/clang.bat
|
||||
[windows] env PATH=$WORK\'program files';%PATH%
|
||||
|
||||
! exists $WORK/log.txt
|
||||
? go build -x
|
||||
exists $WORK/log.txt
|
||||
rm $WORK/log.txt
|
||||
|
||||
# TODO(#41400, #43078): when CC is set explicitly, it should be allowed to
|
||||
# contain spaces separating arguments, and it should be possible to quote
|
||||
# arguments with spaces (including the path), as in CGO_CFLAGS and other
|
||||
# variables. For now, this doesn't work.
|
||||
[!windows] env CC=$WORK/'program files'/gcc
|
||||
[windows] env CC=$WORK\'program files'\gcc.bat
|
||||
! go build -x
|
||||
! exists $WORK/log.txt
|
||||
|
||||
-- go.mod --
|
||||
module m
|
||||
|
||||
-- m.go --
|
||||
package m
|
||||
|
||||
// #define X 1
|
||||
import "C"
|
||||
|
||||
-- $WORK/program files/gcc --
|
||||
#!/bin/sh
|
||||
|
||||
echo ok >$WORK/log.txt
|
||||
-- $WORK/program files/clang --
|
||||
#!/bin/sh
|
||||
|
||||
echo ok >$WORK/log.txt
|
||||
-- $WORK/program files/gcc.bat --
|
||||
echo ok >%WORK%\log.txt
|
||||
-- $WORK/program files/clang.bat --
|
||||
echo ok >%WORK%\log.txt
|
@ -280,7 +280,7 @@ func MOVCONST(d int64, s int, rt int) uint32 {
|
||||
const (
|
||||
// Optab.flag
|
||||
LFROM = 1 << 0 // p.From uses constant pool
|
||||
LFROM3 = 1 << 1 // p.From3 uses constant pool
|
||||
LFROM128 = 1 << 1 // p.From3<<64+p.From forms a 128-bit constant in literal pool
|
||||
LTO = 1 << 2 // p.To uses constant pool
|
||||
NOTUSETMP = 1 << 3 // p expands to multiple instructions, but does NOT use REGTMP
|
||||
)
|
||||
@ -419,7 +419,7 @@ var optab = []Optab{
|
||||
{AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0},
|
||||
|
||||
// Move a large constant to a vector register.
|
||||
{AVMOVQ, C_VCON, C_NONE, C_VCON, C_VREG, 101, 4, 0, LFROM | LFROM3, 0},
|
||||
{AVMOVQ, C_VCON, C_NONE, C_VCON, C_VREG, 101, 4, 0, LFROM128, 0},
|
||||
{AVMOVD, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
|
||||
{AVMOVS, C_LCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
|
||||
|
||||
@ -995,8 +995,8 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
|
||||
if o.flag&LFROM != 0 {
|
||||
c.addpool(p, &p.From)
|
||||
}
|
||||
if o.flag&LFROM3 != 0 {
|
||||
c.addpool(p, p.GetFrom3())
|
||||
if o.flag&LFROM128 != 0 {
|
||||
c.addpool128(p, &p.From, p.GetFrom3())
|
||||
}
|
||||
if o.flag<O != 0 {
|
||||
c.addpool(p, &p.To)
|
||||
@ -1201,6 +1201,36 @@ func (c *ctxt7) flushpool(p *obj.Prog, skip int) {
|
||||
}
|
||||
}
|
||||
|
||||
// addpool128 adds a 128-bit constant to literal pool by two consecutive DWORD
|
||||
// instructions, the 128-bit constant is formed by ah.Offset<<64+al.Offset.
|
||||
func (c *ctxt7) addpool128(p *obj.Prog, al, ah *obj.Addr) {
|
||||
lit := al.Offset
|
||||
q := c.newprog()
|
||||
q.As = ADWORD
|
||||
q.To.Type = obj.TYPE_CONST
|
||||
q.To.Offset = lit
|
||||
q.Pc = int64(c.pool.size)
|
||||
|
||||
lit = ah.Offset
|
||||
t := c.newprog()
|
||||
t.As = ADWORD
|
||||
t.To.Type = obj.TYPE_CONST
|
||||
t.To.Offset = lit
|
||||
t.Pc = int64(c.pool.size + 8)
|
||||
q.Link = t
|
||||
|
||||
if c.blitrl == nil {
|
||||
c.blitrl = q
|
||||
c.pool.start = uint32(p.Pc)
|
||||
} else {
|
||||
c.elitrl.Link = q
|
||||
}
|
||||
|
||||
c.elitrl = t
|
||||
c.pool.size += 16
|
||||
p.Pool = q
|
||||
}
|
||||
|
||||
/*
|
||||
* MOVD foo(SB), R is actually
|
||||
* MOVD addr, REGTMP
|
||||
|
@ -47,7 +47,7 @@ func TestLarge(t *testing.T) {
|
||||
|
||||
// assemble generated file
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", filepath.Join(dir, "test.o"), tmpfile)
|
||||
cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux")
|
||||
cmd.Env = append(os.Environ(), "GOOS=linux")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("Assemble failed: %v, output: %s", err, out)
|
||||
@ -62,7 +62,7 @@ func TestLarge(t *testing.T) {
|
||||
|
||||
// build generated file
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
|
||||
cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux")
|
||||
cmd.Env = append(os.Environ(), "GOOS=linux")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("Build failed: %v, output: %s", err, out)
|
||||
@ -96,7 +96,7 @@ func TestNoRet(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
|
||||
cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux")
|
||||
cmd.Env = append(os.Environ(), "GOOS=linux")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Errorf("%v\n%s", err, out)
|
||||
}
|
||||
@ -134,7 +134,7 @@ func TestPCALIGN(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-S", "-o", tmpout, tmpfile)
|
||||
cmd.Env = append(os.Environ(), "GOARCH=arm64", "GOOS=linux")
|
||||
cmd.Env = append(os.Environ(), "GOOS=linux")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("The %s build failed: %v, output: %s", test.name, err, out)
|
||||
@ -150,3 +150,13 @@ func TestPCALIGN(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testvmovq() (r1, r2 uint64)
|
||||
|
||||
// TestVMOVQ checks if the arm64 VMOVQ instruction is working properly.
|
||||
func TestVMOVQ(t *testing.T) {
|
||||
a, b := testvmovq()
|
||||
if a != 0x7040201008040201 || b != 0x3040201008040201 {
|
||||
t.Errorf("TestVMOVQ got: a=0x%x, b=0x%x, want: a=0x7040201008040201, b=0x3040201008040201", a, b)
|
||||
}
|
||||
}
|
14
src/cmd/internal/obj/arm64/asm_arm64_test.s
Normal file
14
src/cmd/internal/obj/arm64/asm_arm64_test.s
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// testvmovq() (r1, r2 uint64)
|
||||
TEXT ·testvmovq(SB), NOSPLIT, $0-16
|
||||
VMOVQ $0x7040201008040201, $0x3040201008040201, V1
|
||||
VMOV V1.D[0], R0
|
||||
VMOV V1.D[1], R1
|
||||
MOVD R0, r1+0(FP)
|
||||
MOVD R1, r2+8(FP)
|
||||
RET
|
@ -1720,6 +1720,8 @@ var v = "v";
|
||||
`
|
||||
|
||||
func TestEscapeRace(t *testing.T) {
|
||||
t.Skip("this test currently fails with -race; see issue #39807")
|
||||
|
||||
tmpl := New("")
|
||||
_, err := tmpl.New("templ.html").Parse(raceText)
|
||||
if err != nil {
|
||||
@ -1777,6 +1779,39 @@ func TestRecursiveExecute(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// recursiveInvoker is for TestRecursiveExecuteViaMethod.
|
||||
type recursiveInvoker struct {
|
||||
t *testing.T
|
||||
tmpl *Template
|
||||
}
|
||||
|
||||
func (r *recursiveInvoker) Recur() (string, error) {
|
||||
var sb strings.Builder
|
||||
if err := r.tmpl.ExecuteTemplate(&sb, "subroutine", nil); err != nil {
|
||||
r.t.Fatal(err)
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
func TestRecursiveExecuteViaMethod(t *testing.T) {
|
||||
tmpl := New("")
|
||||
top, err := tmpl.New("x.html").Parse(`{{.Recur}}`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = tmpl.New("subroutine").Parse(`<a href="/x?p={{"'a<b'"}}">`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r := &recursiveInvoker{
|
||||
t: t,
|
||||
tmpl: tmpl,
|
||||
}
|
||||
if err := top.Execute(io.Discard, r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 43295.
|
||||
func TestTemplateFuncsAfterClone(t *testing.T) {
|
||||
s := `{{ f . }}`
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sync"
|
||||
"text/template"
|
||||
"text/template/parse"
|
||||
@ -36,20 +35,18 @@ var escapeOK = fmt.Errorf("template escaped correctly")
|
||||
|
||||
// nameSpace is the data structure shared by all templates in an association.
|
||||
type nameSpace struct {
|
||||
mu sync.RWMutex
|
||||
mu sync.Mutex
|
||||
set map[string]*Template
|
||||
escaped bool
|
||||
esc escaper
|
||||
// The original functions, before wrapping.
|
||||
funcMap FuncMap
|
||||
}
|
||||
|
||||
// Templates returns a slice of the templates associated with t, including t
|
||||
// itself.
|
||||
func (t *Template) Templates() []*Template {
|
||||
ns := t.nameSpace
|
||||
ns.mu.RLock()
|
||||
defer ns.mu.RUnlock()
|
||||
ns.mu.Lock()
|
||||
defer ns.mu.Unlock()
|
||||
// Return a slice so we don't expose the map.
|
||||
m := make([]*Template, 0, len(ns.set))
|
||||
for _, v := range ns.set {
|
||||
@ -87,8 +84,8 @@ func (t *Template) checkCanParse() error {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
t.nameSpace.mu.RLock()
|
||||
defer t.nameSpace.mu.RUnlock()
|
||||
t.nameSpace.mu.Lock()
|
||||
defer t.nameSpace.mu.Unlock()
|
||||
if t.nameSpace.escaped {
|
||||
return fmt.Errorf("html/template: cannot Parse after Execute")
|
||||
}
|
||||
@ -97,16 +94,6 @@ func (t *Template) checkCanParse() error {
|
||||
|
||||
// escape escapes all associated templates.
|
||||
func (t *Template) escape() error {
|
||||
t.nameSpace.mu.RLock()
|
||||
escapeErr := t.escapeErr
|
||||
t.nameSpace.mu.RUnlock()
|
||||
if escapeErr != nil {
|
||||
if escapeErr == escapeOK {
|
||||
return nil
|
||||
}
|
||||
return escapeErr
|
||||
}
|
||||
|
||||
t.nameSpace.mu.Lock()
|
||||
defer t.nameSpace.mu.Unlock()
|
||||
t.nameSpace.escaped = true
|
||||
@ -134,8 +121,6 @@ func (t *Template) Execute(wr io.Writer, data interface{}) error {
|
||||
if err := t.escape(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.nameSpace.mu.RLock()
|
||||
defer t.nameSpace.mu.RUnlock()
|
||||
return t.text.Execute(wr, data)
|
||||
}
|
||||
|
||||
@ -151,8 +136,6 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.nameSpace.mu.RLock()
|
||||
defer t.nameSpace.mu.RUnlock()
|
||||
return tmpl.text.Execute(wr, data)
|
||||
}
|
||||
|
||||
@ -160,27 +143,13 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
|
||||
// is escaped, or returns an error if it cannot be. It returns the named
|
||||
// template.
|
||||
func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
|
||||
t.nameSpace.mu.RLock()
|
||||
tmpl = t.set[name]
|
||||
var escapeErr error
|
||||
if tmpl != nil {
|
||||
escapeErr = tmpl.escapeErr
|
||||
}
|
||||
t.nameSpace.mu.RUnlock()
|
||||
|
||||
if tmpl == nil {
|
||||
return nil, fmt.Errorf("html/template: %q is undefined", name)
|
||||
}
|
||||
if escapeErr != nil {
|
||||
if escapeErr != escapeOK {
|
||||
return nil, escapeErr
|
||||
}
|
||||
return tmpl, nil
|
||||
}
|
||||
|
||||
t.nameSpace.mu.Lock()
|
||||
defer t.nameSpace.mu.Unlock()
|
||||
t.nameSpace.escaped = true
|
||||
tmpl = t.set[name]
|
||||
if tmpl == nil {
|
||||
return nil, fmt.Errorf("html/template: %q is undefined", name)
|
||||
}
|
||||
if tmpl.escapeErr != nil && tmpl.escapeErr != escapeOK {
|
||||
return nil, tmpl.escapeErr
|
||||
}
|
||||
@ -286,13 +255,6 @@ func (t *Template) Clone() (*Template, error) {
|
||||
}
|
||||
ns := &nameSpace{set: make(map[string]*Template)}
|
||||
ns.esc = makeEscaper(ns)
|
||||
if t.nameSpace.funcMap != nil {
|
||||
ns.funcMap = make(FuncMap, len(t.nameSpace.funcMap))
|
||||
for name, fn := range t.nameSpace.funcMap {
|
||||
ns.funcMap[name] = fn
|
||||
}
|
||||
}
|
||||
wrapFuncs(ns, textClone, ns.funcMap)
|
||||
ret := &Template{
|
||||
nil,
|
||||
textClone,
|
||||
@ -307,13 +269,12 @@ func (t *Template) Clone() (*Template, error) {
|
||||
return nil, fmt.Errorf("html/template: cannot Clone %q after it has executed", t.Name())
|
||||
}
|
||||
x.Tree = x.Tree.Copy()
|
||||
tc := &Template{
|
||||
ret.set[name] = &Template{
|
||||
nil,
|
||||
x,
|
||||
x.Tree,
|
||||
ret.nameSpace,
|
||||
}
|
||||
ret.set[name] = tc
|
||||
}
|
||||
// Return the template associated with the name of this template.
|
||||
return ret.set[ret.Name()], nil
|
||||
@ -382,43 +343,10 @@ type FuncMap map[string]interface{}
|
||||
// type. However, it is legal to overwrite elements of the map. The return
|
||||
// value is the template, so calls can be chained.
|
||||
func (t *Template) Funcs(funcMap FuncMap) *Template {
|
||||
t.nameSpace.mu.Lock()
|
||||
if t.nameSpace.funcMap == nil {
|
||||
t.nameSpace.funcMap = make(FuncMap, len(funcMap))
|
||||
}
|
||||
for name, fn := range funcMap {
|
||||
t.nameSpace.funcMap[name] = fn
|
||||
}
|
||||
t.nameSpace.mu.Unlock()
|
||||
|
||||
wrapFuncs(t.nameSpace, t.text, funcMap)
|
||||
t.text.Funcs(template.FuncMap(funcMap))
|
||||
return t
|
||||
}
|
||||
|
||||
// wrapFuncs records the functions with text/template. We wrap them to
|
||||
// unlock the nameSpace. See TestRecursiveExecute for a test case.
|
||||
func wrapFuncs(ns *nameSpace, textTemplate *template.Template, funcMap FuncMap) {
|
||||
if len(funcMap) == 0 {
|
||||
return
|
||||
}
|
||||
tfuncs := make(template.FuncMap, len(funcMap))
|
||||
for name, fn := range funcMap {
|
||||
fnv := reflect.ValueOf(fn)
|
||||
wrapper := func(args []reflect.Value) []reflect.Value {
|
||||
ns.mu.RUnlock()
|
||||
defer ns.mu.RLock()
|
||||
if fnv.Type().IsVariadic() {
|
||||
return fnv.CallSlice(args)
|
||||
} else {
|
||||
return fnv.Call(args)
|
||||
}
|
||||
}
|
||||
wrapped := reflect.MakeFunc(fnv.Type(), wrapper)
|
||||
tfuncs[name] = wrapped.Interface()
|
||||
}
|
||||
textTemplate.Funcs(tfuncs)
|
||||
}
|
||||
|
||||
// Delims sets the action delimiters to the specified strings, to be used in
|
||||
// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
|
||||
// definitions will inherit the settings. An empty delimiter stands for the
|
||||
@ -432,8 +360,8 @@ func (t *Template) Delims(left, right string) *Template {
|
||||
// Lookup returns the template with the given name that is associated with t,
|
||||
// or nil if there is no such template.
|
||||
func (t *Template) Lookup(name string) *Template {
|
||||
t.nameSpace.mu.RLock()
|
||||
defer t.nameSpace.mu.RUnlock()
|
||||
t.nameSpace.mu.Lock()
|
||||
defer t.nameSpace.mu.Unlock()
|
||||
return t.set[name]
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ func ExampleReadFile() {
|
||||
|
||||
func ExampleWriteFile() {
|
||||
message := []byte("Hello, Gophers!")
|
||||
err := ioutil.WriteFile("testdata/hello", message, 0644)
|
||||
err := ioutil.WriteFile("hello", message, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
. "os"
|
||||
osexec "os/exec"
|
||||
@ -2689,8 +2690,31 @@ func TestOpenFileKeepsPermissions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDirFS(t *testing.T) {
|
||||
// On Windows, we force the MFT to update by reading the actual metadata from GetFileInformationByHandle and then
|
||||
// explicitly setting that. Otherwise it might get out of sync with FindFirstFile. See golang.org/issues/42637.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("workaround for dev.regabi/dev.typeparams until #42637 is fixed")
|
||||
if err := filepath.WalkDir("./testdata/dirfs", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stat, err := Stat(path) // This uses GetFileInformationByHandle internally.
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stat.ModTime() == info.ModTime() {
|
||||
return nil
|
||||
}
|
||||
if err := Chtimes(path, stat.ModTime(), stat.ModTime()); err != nil {
|
||||
t.Log(err) // We only log, not die, in case the test directory is not writable.
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := fstest.TestFS(DirFS("./testdata/dirfs"), "a", "b", "dir/x"); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -20,3 +20,4 @@ func msanread(addr unsafe.Pointer, sz uintptr) { throw("msan") }
|
||||
func msanwrite(addr unsafe.Pointer, sz uintptr) { throw("msan") }
|
||||
func msanmalloc(addr unsafe.Pointer, sz uintptr) { throw("msan") }
|
||||
func msanfree(addr unsafe.Pointer, sz uintptr) { throw("msan") }
|
||||
func msanmove(dst, src unsafe.Pointer, sz uintptr) { throw("msan") }
|
||||
|
@ -1251,6 +1251,11 @@ func mstart() {
|
||||
// Initialize stack bounds from system stack.
|
||||
// Cgo may have left stack size in stack.hi.
|
||||
// minit may update the stack bounds.
|
||||
//
|
||||
// Note: these bounds may not be very accurate.
|
||||
// We set hi to &size, but there are things above
|
||||
// it. The 1024 is supposed to compensate this,
|
||||
// but is somewhat arbitrary.
|
||||
size := _g_.stack.hi
|
||||
if size == 0 {
|
||||
size = 8192 * sys.StackGuardMultiplier
|
||||
|
@ -475,6 +475,14 @@ func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var st stackt
|
||||
sigaltstack(nil, &st)
|
||||
stsp := uintptr(unsafe.Pointer(st.ss_sp))
|
||||
if st.ss_flags&_SS_DISABLE == 0 && sp >= stsp && sp < stsp+st.ss_size {
|
||||
setGsignalStack(&st, gsigStack)
|
||||
return true
|
||||
}
|
||||
|
||||
if sp >= mp.g0.stack.lo && sp < mp.g0.stack.hi {
|
||||
// The signal was delivered on the g0 stack.
|
||||
// This can happen when linked with C code
|
||||
@ -483,29 +491,25 @@ func adjustSignalStack(sig uint32, mp *m, gsigStack *gsignalStack) bool {
|
||||
// the signal handler directly when C code,
|
||||
// including C code called via cgo, calls a
|
||||
// TSAN-intercepted function such as malloc.
|
||||
//
|
||||
// We check this condition last as g0.stack.lo
|
||||
// may be not very accurate (see mstart).
|
||||
st := stackt{ss_size: mp.g0.stack.hi - mp.g0.stack.lo}
|
||||
setSignalstackSP(&st, mp.g0.stack.lo)
|
||||
setGsignalStack(&st, gsigStack)
|
||||
return true
|
||||
}
|
||||
|
||||
var st stackt
|
||||
sigaltstack(nil, &st)
|
||||
// sp is not within gsignal stack, g0 stack, or sigaltstack. Bad.
|
||||
setg(nil)
|
||||
needm()
|
||||
if st.ss_flags&_SS_DISABLE != 0 {
|
||||
setg(nil)
|
||||
needm()
|
||||
noSignalStack(sig)
|
||||
dropm()
|
||||
}
|
||||
stsp := uintptr(unsafe.Pointer(st.ss_sp))
|
||||
if sp < stsp || sp >= stsp+st.ss_size {
|
||||
setg(nil)
|
||||
needm()
|
||||
} else {
|
||||
sigNotOnStack(sig)
|
||||
dropm()
|
||||
}
|
||||
setGsignalStack(&st, gsigStack)
|
||||
return true
|
||||
dropm()
|
||||
return false
|
||||
}
|
||||
|
||||
// crashing is the number of m's we have waited for when implementing
|
||||
|
@ -57,3 +57,4 @@ func pthread_create_trampoline()
|
||||
//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "libpthread.so"
|
||||
|
||||
//go:cgo_import_dynamic _ _ "libpthread.so"
|
||||
//go:cgo_import_dynamic _ _ "libc.so"
|
||||
|
File diff suppressed because it is too large
Load Diff
45
test/fixedbugs/issue43835.go
Normal file
45
test/fixedbugs/issue43835.go
Normal file
@ -0,0 +1,45 @@
|
||||
// run
|
||||
|
||||
// Copyright 2021 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
|
||||
|
||||
func main() {
|
||||
if f() {
|
||||
panic("FAIL")
|
||||
}
|
||||
if bad, _ := g(); bad {
|
||||
panic("FAIL")
|
||||
}
|
||||
if bad, _ := h(); bad {
|
||||
panic("FAIL")
|
||||
}
|
||||
}
|
||||
|
||||
func f() (bad bool) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
var p *int
|
||||
bad, _ = true, *p
|
||||
return
|
||||
}
|
||||
|
||||
func g() (bool, int) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
var p *int
|
||||
return true, *p
|
||||
}
|
||||
|
||||
|
||||
func h() (_ bool, _ int) {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
var p *int
|
||||
return true, *p
|
||||
}
|
Loading…
Reference in New Issue
Block a user