Afanasev Stanislav <phpprogger@gmail.com>
Agis Anastasopoulos <agis.anast@gmail.com>
Agniva De Sarker <agnivade@yahoo.co.in>
-Ahmed Wahed <oneofone@gmail.com>
+Ahmed W. Mones <oneofone@gmail.com>
Ahmet Soormally <ahmet@mangomm.co.uk>
Ahmy Yulrizka <yulrizka@gmail.com>
Aiden Scandella <ai@uber.com>
Afanasev Stanislav <phpprogger@gmail.com>
Agis Anastasopoulos <agis.anast@gmail.com>
Agniva De Sarker <agnivade@yahoo.co.in>
-Ahmed Wahed <oneofone@gmail.com>
+Ahmed W. Mones <oneofone@gmail.com>
Ahmet Alp Balkan <ahmetb@google.com>
Ahmet Soormally <ahmet@mangomm.co.uk>
Ahmy Yulrizka <yulrizka@gmail.com>
OpenBSD.
</p>
+<h3 id="arm64">ARM64</h3>
+
+<p><!-- CL 288814 -->
+ Go programs now maintain stack frame pointers on the 64-bit ARM
+ architecture on all operating systems. Previously it maintained
+ stack frame pointers only on Linux, macOS, and iOS.
+</p>
+
<p>
TODO: complete the Ports section
</p>
<h2 id="runtime">Runtime</h2>
-<p><!-- CL 304470 -->
- TODO: <a href="https://golang.org/cl/304470">https://golang.org/cl/304470</a>: cmd/compile, runtime: add metadata for argument printing in traceback
-</p>
-
<p>
TODO: complete the Runtime section
</p>
<h2 id="compiler">Compiler</h2>
-<p><!-- CL 283112, golang.org/issue/28727 -->
+<p><!-- golang.org/issue/40724 -->
+ Go 1.17 implements a new way of passing function arguments and results using
+ registers instead of the stack. This work is enabled for Linux, MacOS, and
+ Windows on the 64-bit x86 architecture (the <code>linux/amd64</code>,
+ <code>darwin/amd64</code>, <code>windows/amd64</code> ports). For a
+ representative set of Go packages and programs, benchmarking has shown
+ performance improvements of about 5%, and a typical reduction in binary size
+ of about 2%.
+</p>
+
+<p>
+ This change does not affect the functionality of any safe Go code. It can affect
+ code outside the <a href="/doc/go1compat">compatibility guidelines</a> with
+ minimal impact. To maintain compatibility with existing assembly functions,
+ adapter functions converting between the new register-based calling convention
+ and the previous stack-based calling convention (also known as ABI wrappers)
+ are sometimes used. This is mostly invisible to users, except for assembly
+ functions that have their addresses taken in Go. Using <code>reflect.ValueOf(fn).Pointer()</code>
+ (or similar approaches such as via <code>unsafe.Pointer</code>) to get the address
+ of an assembly function will now return the address of the ABI wrapper. This is
+ mostly harmless, except for special-purpose assembly code (such as accessing
+ thread-local storage or requiring a special stack alignment). Assembly functions
+ called indirectly from Go via <code>func</code> values will now be made through
+ ABI wrappers, which may cause a very small performance overhead. Also, calling
+ Go functions from assembly may now go through ABI wrappers, with a very small
+ performance overhead.
+</p>
+
+<p><!-- CL 304470 -->
+ The format of stack traces from the runtime (printed when an uncaught panic
+ occurs, or when <code>runtime.Stack</code> is called) is improved. Previously,
+ the function arguments were printed as hexadecimal words based on the memory
+ layout. Now each argument in the source code is printed separately, separated
+ by commas. Aggregate-typed (struct, array, string, slice, interface, and complex)
+ arguments are delimited by curly braces. A caveat is that the value of an
+ argument that only lives in a register and is not stored to memory may be
+ inaccurate. Results (which were usually inaccurate) are no longer printed.
+</p>
+<p><!-- CL 283112, golang.org/issue/28727 -->
Functions containing closures can now be inlined. One effect of this change is
that a function with a closure may actually produce a distinct closure function
for each place that the function is inlined. Hence, this change could reveal
bugs where Go functions are compared (incorrectly) by pointer value. Go
functions are by definition not comparable.
-
- TODO: complete the Compiler section, or delete if not needed
-</p>
-
-<h2 id="linker">Linker</h2>
-
-<p>
- TODO: complete the Linker section, or delete if not needed
</p>
<h2 id="library">Core library</h2>
<dl id="compress/lzw"><dt><a href="/pkg/compress/lzw/">compress/lzw</a></dt>
<dd>
<p><!-- CL 273667 -->
- The new
- <a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>
- and
- <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>
- methods allow reuse of a <code>Reader</code> or <code>Writer</code>.
+ The <a href="/pkg/compress/lzw/#NewReader"><code>NewReader</code></a>
+ function is guaranteed to return a value of the new
+ type <a href="/pkg/compress/lzw/#Reader"><code>Reader</code></a>,
+ and similarly <a href="/pkg/compress/lzw/#NewWriter"><code>NewWriter</code></a>
+ is guaranteed to return a value of the new
+ type <a href="/pkg/compress/lzw/#Writer"><code>Writer</code></a>.
+ These new types both implement a <code>Reset</code> method
+ (<a href="/pkg/compress/lzw/#Reader.Reset"><code>Reader.Reset</code></a>,
+ <a href="/pkg/compress/lzw/#Writer.Reset"><code>Writer.Reset</code></a>)
+ that allows reuse of the <code>Reader</code> or <code>Writer</code>.
</p>
</dd>
</dl><!-- compress/lzw -->
</dd>
</dl><!-- database/sql -->
+<dl id="debug/elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
+ <dd>
+ <p><!-- CL 239217 -->
+ The <a href="/pkg/debug/elf/#SHT_MIPS_ABIFLAGS"><code>SHT_MIPS_ABIFLAGS</code></a>
+ constant has been added.
+ </p>
+ </dd>
+</dl><!-- debug/elf -->
+
<dl id="encoding/binary"><dt><a href="/pkg/encoding/binary/">encoding/binary</a></dt>
<dd>
<p><!-- CL 299531 -->
</dd>
</dl><!-- encoding/binary -->
+<dl id="encoding/csv"><dt><a href="/pkg/encoding/csv/">encoding/csv</a></dt>
+ <dd>
+ <p><!-- CL 291290 -->
+ The new
+ <a href="/pkg/encoding/csv/#Reader.FieldPos"><code>Reader.FieldPos</code></a>
+ method returns the line and column corresponding to the start of
+ a given field in the record most recently returned by
+ <a href="/pkg/encoding/csv/#Reader.Read"><code>Read</code></a>.
+ </p>
+ </dd>
+</dl><!-- encoding/csv -->
+
<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
<dd>
<p><!-- CL 271788 -->
</dd>
</dl><!-- flag -->
+<dl id="go/build"><dt><a href="/pkg/go/build/">go/build</a></dt>
+ <dd>
+ <p><!-- CL 310732 -->
+ The new
+ <a href="/pkg/go/build/#Context.ToolTags"><code>Context.ToolTags</code></a>
+ field holds the build tags appropriate to the current Go
+ toolchain configuration.
+ </p>
+ </dd>
+</dl><!-- go/build -->
+
<dl id="io/fs"><dt><a href="/pkg/io/fs/">io/fs</a></dt>
<dd>
<p><!-- CL 293649 -->
<dl id="mime"><dt><a href="/pkg/mime/">mime</a></dt>
<dd>
<p><!-- CL 305230 -->
- TODO: <a href="https://golang.org/cl/305230">https://golang.org/cl/305230</a>: support reading shared mime-info database on unix systems
+ On Unix systems, the table of MIME types is now read from the local system's
+ <a href="https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.21.html">Shared MIME-info Database</a>
+ when available.
</p>
</dd>
</dl><!-- mime -->
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
<dd>
<p><!-- CL 272668 -->
- TODO: <a href="https://golang.org/cl/272668">https://golang.org/cl/272668</a>: add IP.IsPrivate
+ The new method <a href="/pkg/net/#IP.IsPrivate"><code>IP.IsPrivate</code></a> reports whether an address is
+ a private IPv4 address according to <a href="http://tools.ietf.org/html/rfc1918">RFC 1918</a>
+ or a local IPv6 address according <a href="http://tools.ietf.org/html/rfc4193">RFC 4193</a>.
</p>
<p><!-- CL 301709 -->
- TODO: <a href="https://golang.org/cl/301709">https://golang.org/cl/301709</a>: make go resolver aware of network parameter
+ The Go DNS resolver now only sends one DNS query when resolving an address for an IPv4-only or IPv6-only network,
+ rather than querying for both address families.
</p>
<p><!-- CL 307030 -->
- TODO: <a href="https://golang.org/cl/307030">https://golang.org/cl/307030</a>: make ErrClosed and ParseError implement net.Error
+ The <a href="/pkg/net/#ErrClosed"><code>ErrClosed</code></a> sentinel error and
+ <a href="/pkg/net/#ParseError"><code>ParseError</code></a> error type now implement
+ the <a href="/pkg/net/#Error"><code>net.Error</code></a> interface.
</p>
</dd>
</dl><!-- net -->
</p>
<p><!-- CL 235437 -->
- TODO: <a href="https://golang.org/cl/235437">https://golang.org/cl/235437</a>: add to deadlines only when positive
+ Setting the <a href="/pkg/net/http/#Server"><code>Server</code></a>
+ <code>ReadTimeout</code> or <code>WriteTimeout</code> fields to a negative value now indicates no timeout
+ rather than an immediate timeout.
</p>
<p><!-- CL 308952 -->
<dl id="net/http/httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
<dd>
<p><!-- CL 308950 -->
- TODO: <a href="https://golang.org/cl/308950">https://golang.org/cl/308950</a>: panic on non-3 digit (XXX) status code in Recorder.WriteHeader
+ <a href="/pkg/net/http/httptest/#ResponseRecorder.WriteHeader"><code>ResponseRecorder.WriteHeader></code></a>
+ now panics when the provided code is not a valid three-digit HTTP status code.
+ This matches the behavior of <a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter></code></a>
+ implementations in the <a href="/pkg/net/http/"><code>net/http</code></a> package.
</p>
</dd>
</dl><!-- net/http/httptest -->
<dl id="net/url"><dt><a href="/pkg/net/url/">net/url</a></dt>
<dd>
<p><!-- CL 314850 -->
- TODO: <a href="https://golang.org/cl/314850">https://golang.org/cl/314850</a>: add Values.Has
+ The new method <a href="/pkg/net/url/#Values.Has"><code>Values.Has</code></a>
+ reports whether a query parameter is set.
</p>
</dd>
</dl><!-- net/url -->
</p>
<p><!-- CL 281233 -->
- TODO: <a href="https://golang.org/cl/281233">https://golang.org/cl/281233</a>: add VisibleFields function
+ The new <a href="/pkg/reflect/#VisibleFields"><code>VisibleFields</code></a> function
+ returns all the visible fields in a struct type, including fields inside anonymous struct members.
</p>
<p><!-- CL 284136 -->
- TODO: <a href="https://golang.org/cl/284136">https://golang.org/cl/284136</a>: panic if ArrayOf is called with negative length
+ The <a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a> function now panics when
+ called with a negative length.
</p>
</dd>
</dl><!-- reflect -->
+<dl id="runtime/metrics"><dt><a href="/pkg/runtime/metrics">runtime/metrics</a></dt>
+ <dd>
+ <p><!-- CL 308933, CL 312431, CL 312909 -->
+ New metrics were added that track total bytes and objects allocated and freed.
+ A new metric tracking the distribution of goroutine scheduling latencies was
+ also added.
+ </p>
+ </dd>
+</dl><!-- runtime/metrics -->
+
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
<dd>
<p><!-- CL 170079 -->
<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
<dd>
<p><!-- CL 295371 -->
- TODO: <a href="https://golang.org/cl/295371">https://golang.org/cl/295371</a>: do not overflow key memory in GetQueuedCompletionStatus
+ <p>
+ The <a href="/pkg/syscall/#GetQueuedCompletionStatus"><code>GetQueuedCompletionStatus</code></a> and
+ <a href="/pkg/syscall/#PostQueuedCompletionStatus"><code>PostQueuedCompletionStatus</code></a>
+ functions are now deprecated. These functions have incorrect signatures and are superseded by
+ equivalents in the <a href="https://godoc.org/golang.org/x/sys/windows"><code>golang.org/x/sys/windows</code></a> package.
</p>
<p><!-- CL 313653 -->
- TODO: <a href="https://golang.org/cl/313653">https://golang.org/cl/313653</a>: restore signal mask after setting foreground process group
+ On Unix-like systems, the process group of a child process is now set with signals blocked.
+ This avoids sending a <code>SIGTTOU</code> to the child when the parent is in a background process group.
+ </p>
+
+ <p><!-- CL 288298, CL 288300 -->
+ The Windows version of
+ <a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a>
+ has two new fields. <code>AdditionalInheritedHandles</code> is
+ a list of additional handles to be inherited by the new child
+ process. <code>ParentProcess</code> permits specifying the
+ parent process of the new process.
+
+ <p><!-- CL 311570 -->
+ The constant <code>MSG_CMSG_CLOEXEC</code> is now defined on
+ DragonFly and all OpenBSD systems (it was already defined on
+ some OpenBSD systems and all FreeBSD, NetBSD, and Linux systems).
</p>
</dd>
</dl><!-- syscall -->
<p><!-- CL 310033 -->
TODO: <a href="https://golang.org/cl/310033">https://golang.org/cl/310033</a>: add -shuffle=off|on|N to alter the execution order of tests and benchmarks
</p>
+
+ <p><!-- CL 260577 -->
+ The new
+ <a href="/pkg/testing/#T.Setenv"><code>T.Setenv</code></a>
+ and <a href="/pkg/testing/#B.Setenv"><code>B.Setenv</code></a>
+ methods support setting an environment variable for the duration
+ of the test or benchmark.
+ </p>
</dd>
</dl><!-- testing -->
<dl id="text/template/parse"><dt><a href="/pkg/text/template/parse/">text/template/parse</a></dt>
<dd>
<p><!-- CL 301493 -->
- TODO: <a href="https://golang.org/cl/301493">https://golang.org/cl/301493</a>: add a mode to skip func-check on parsing
+ The new <a href="/pkg/text/template/parse/#Mode"><code>SkipFuncCheck</code></a> <a href=><code>Mode</code></a>
+ value changes the template parser to not verify that functions are defined.
</p>
</dd>
</dl><!-- text/template/parse -->
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
<dd>
<p><!-- CL 260858 -->
- time.Time now has a <a href="/pkg/time/#Time.GoString">GoString</a>
- method that will return a more useful value for times when printed with
- the <code>"%#v"</code> format specifier in the fmt package.
+ The <a href="/pkg/time/#Time"><code>Time</code></a> type now has a
+ <a href="/pkg/time/#Time.GoString"><code>GoString</code></a> method that
+ will return a more useful value for times when printed with the
+ <code>%#v</code> format specifier in the <code>fmt</code> package.
</p>
<p><!-- CL 264077 -->
<p><!-- CL 300996 -->
TODO: <a href="https://golang.org/cl/300996">https://golang.org/cl/300996</a>: support "," as separator for fractional seconds
</p>
+
+ <p><!-- CL 320252 -->
+ The new constant <a href="/pkg/time/#Layout"><code>Layout</code></a>
+ defines the reference time.
+ </p>
</dd>
</dl><!-- time -->
return err
}
z.r = r
- z.File = make([]*File, 0, end.directoryRecords)
+ // Since the number of directory records is not validated, it is not
+ // safe to preallocate z.File without first checking that the specified
+ // number of files is reasonable, since a malformed archive may
+ // indicate it contains up to 1 << 128 - 1 files. Since each file has a
+ // header which will be _at least_ 30 bytes we can safely preallocate
+ // if (data size / 30) >= end.directoryRecords.
+ if (uint64(size)-end.directorySize)/30 >= end.directoryRecords {
+ z.File = make([]*File, 0, end.directoryRecords)
+ }
z.Comment = end.comment
rs := io.NewSectionReader(r, 0, size)
if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
})
}
}
+
+func TestCVE202133196(t *testing.T) {
+ // Archive that indicates it has 1 << 128 -1 files,
+ // this would previously cause a panic due to attempting
+ // to allocate a slice with 1 << 128 -1 elements.
+ data := []byte{
+ 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x08, 0x08,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x62, 0x61, 0x65, 0x03, 0x04, 0x00, 0x00,
+ 0xff, 0xff, 0x50, 0x4b, 0x07, 0x08, 0xbe, 0x20,
+ 0x5c, 0x6c, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00,
+ 0x14, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xbe, 0x20, 0x5c, 0x6c, 0x09, 0x00,
+ 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x03, 0x50, 0x4b, 0x06, 0x06, 0x2c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d,
+ 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x07, 0x00,
+ 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50,
+ 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0x00,
+ }
+ _, err := NewReader(bytes.NewReader(data), int64(len(data)))
+ if err != ErrFormat {
+ t.Fatalf("unexpected error, got: %v, want: %v", err, ErrFormat)
+ }
+
+ // Also check that an archive containing a handful of empty
+ // files doesn't cause an issue
+ b := bytes.NewBuffer(nil)
+ w := NewWriter(b)
+ for i := 0; i < 5; i++ {
+ _, err := w.Create("")
+ if err != nil {
+ t.Fatalf("Writer.Create failed: %s", err)
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Writer.Close failed: %s", err)
+ }
+ r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
+ if err != nil {
+ t.Fatalf("NewReader failed: %s", err)
+ }
+ if len(r.File) != 5 {
+ t.Errorf("Archive has unexpected number of files, got %d, want 5", len(r.File))
+ }
+}
import (
"cmd/compile/internal/abi"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
"cmd/internal/dwarf"
"cmd/internal/obj"
+ "cmd/internal/src"
"encoding/hex"
"fmt"
+ "internal/buildcfg"
"math/bits"
"sort"
"strings"
return strings.Join(strs, "")
}
+// slotCanonicalizer is a table used to lookup and canonicalize
+// LocalSlot's in a type insensitive way (e.g. taking into account the
+// base name, offset, and width of the slot, but ignoring the slot
+// type).
+type slotCanonicalizer struct {
+ slmap map[slotKey]SlKeyIdx
+ slkeys []LocalSlot
+}
+
+func newSlotCanonicalizer() *slotCanonicalizer {
+ return &slotCanonicalizer{
+ slmap: make(map[slotKey]SlKeyIdx),
+ slkeys: []LocalSlot{LocalSlot{N: nil}},
+ }
+}
+
+type SlKeyIdx uint32
+
+const noSlot = SlKeyIdx(0)
+
+// slotKey is a type-insensitive encapsulation of a LocalSlot; it
+// is used to key a map within slotCanonicalizer.
+type slotKey struct {
+ name *ir.Name
+ offset int64
+ width int64
+ splitOf SlKeyIdx // idx in slkeys slice in slotCanonicalizer
+ splitOffset int64
+}
+
+// lookup looks up a LocalSlot in the slot canonicalizer "sc", returning
+// a canonical index for the slot, and adding it to the table if need
+// be. Return value is the canonical slot index, and a boolean indicating
+// whether the slot was found in the table already (TRUE => found).
+func (sc *slotCanonicalizer) lookup(ls LocalSlot) (SlKeyIdx, bool) {
+ split := noSlot
+ if ls.SplitOf != nil {
+ split, _ = sc.lookup(*ls.SplitOf)
+ }
+ k := slotKey{
+ name: ls.N, offset: ls.Off, width: ls.Type.Width,
+ splitOf: split, splitOffset: ls.SplitOffset,
+ }
+ if idx, ok := sc.slmap[k]; ok {
+ return idx, true
+ }
+ rv := SlKeyIdx(len(sc.slkeys))
+ sc.slkeys = append(sc.slkeys, ls)
+ sc.slmap[k] = rv
+ return rv, false
+}
+
+func (sc *slotCanonicalizer) canonSlot(idx SlKeyIdx) LocalSlot {
+ return sc.slkeys[idx]
+}
+
+// PopulateABIInRegArgOps examines the entry block of the function
+// and looks for incoming parameters that have missing or partial
+// OpArg{Int,Float}Reg values, inserting additional values in
+// cases where they are missing. Example:
+//
+// func foo(s string, used int, notused int) int {
+// return len(s) + used
+// }
+//
+// In the function above, the incoming parameter "used" is fully live,
+// "notused" is not live, and "s" is partially live (only the length
+// field of the string is used). At the point where debug value
+// analysis runs, we might expect to see an entry block with:
+//
+// b1:
+// v4 = ArgIntReg <uintptr> {s+8} [0] : BX
+// v5 = ArgIntReg <int> {used} [0] : CX
+//
+// While this is an accurate picture of the live incoming params,
+// we also want to have debug locations for non-live params (or
+// their non-live pieces), e.g. something like
+//
+// b1:
+// v9 = ArgIntReg <*uint8> {s+0} [0] : AX
+// v4 = ArgIntReg <uintptr> {s+8} [0] : BX
+// v5 = ArgIntReg <int> {used} [0] : CX
+// v10 = ArgIntReg <int> {unused} [0] : DI
+//
+// This function examines the live OpArg{Int,Float}Reg values and
+// synthesizes new (dead) values for the non-live params or the
+// non-live pieces of partially live params.
+//
+func PopulateABIInRegArgOps(f *Func) {
+ pri := f.ABISelf.ABIAnalyzeFuncType(f.Type.FuncType())
+
+ // When manufacturing new slots that correspond to splits of
+ // composite parameters, we want to avoid creating a new sub-slot
+ // that differs from some existing sub-slot only by type, since
+ // the debug location analysis will treat that slot as a separate
+ // entity. To achieve this, create a lookup table of existing
+ // slots that is type-insenstitive.
+ sc := newSlotCanonicalizer()
+ for _, sl := range f.Names {
+ sc.lookup(*sl)
+ }
+
+ // Add slot -> value entry to f.NamedValues if not already present.
+ addToNV := func(v *Value, sl LocalSlot) {
+ values, ok := f.NamedValues[sl]
+ if !ok {
+ // Haven't seen this slot yet.
+ sla := f.localSlotAddr(sl)
+ f.Names = append(f.Names, sla)
+ } else {
+ for _, ev := range values {
+ if v == ev {
+ return
+ }
+ }
+ }
+ values = append(values, v)
+ f.NamedValues[sl] = values
+ }
+
+ newValues := []*Value{}
+
+ abiRegIndexToRegister := func(reg abi.RegIndex) int8 {
+ i := f.ABISelf.FloatIndexFor(reg)
+ if i >= 0 { // float PR
+ return f.Config.floatParamRegs[i]
+ } else {
+ return f.Config.intParamRegs[reg]
+ }
+ }
+
+ // Helper to construct a new OpArg{Float,Int}Reg op value.
+ var pos src.XPos
+ if len(f.Entry.Values) != 0 {
+ pos = f.Entry.Values[0].Pos
+ }
+ synthesizeOpIntFloatArg := func(n *ir.Name, t *types.Type, reg abi.RegIndex, sl LocalSlot) *Value {
+ aux := &AuxNameOffset{n, sl.Off}
+ op, auxInt := ArgOpAndRegisterFor(reg, f.ABISelf)
+ v := f.newValueNoBlock(op, t, pos)
+ v.AuxInt = auxInt
+ v.Aux = aux
+ v.Args = nil
+ v.Block = f.Entry
+ newValues = append(newValues, v)
+ addToNV(v, sl)
+ f.setHome(v, &f.Config.registers[abiRegIndexToRegister(reg)])
+ return v
+ }
+
+ // Make a pass through the entry block looking for
+ // OpArg{Int,Float}Reg ops. Record the slots they use in a table
+ // ("sc"). We use a type-insensitive lookup for the slot table,
+ // since the type we get from the ABI analyzer won't always match
+ // what the compiler uses when creating OpArg{Int,Float}Reg ops.
+ for _, v := range f.Entry.Values {
+ if v.Op == OpArgIntReg || v.Op == OpArgFloatReg {
+ aux := v.Aux.(*AuxNameOffset)
+ sl := LocalSlot{N: aux.Name, Type: v.Type, Off: aux.Offset}
+ // install slot in lookup table
+ idx, _ := sc.lookup(sl)
+ // add to f.NamedValues if not already present
+ addToNV(v, sc.canonSlot(idx))
+ } else if v.Op.IsCall() {
+ // if we hit a call, we've gone too far.
+ break
+ }
+ }
+
+ // Now make a pass through the ABI in-params, looking for params
+ // or pieces of params that we didn't encounter in the loop above.
+ for _, inp := range pri.InParams() {
+ if !isNamedRegParam(inp) {
+ continue
+ }
+ n := inp.Name.(*ir.Name)
+
+ // Param is spread across one or more registers. Walk through
+ // each piece to see whether we've seen an arg reg op for it.
+ types, offsets := inp.RegisterTypesAndOffsets()
+ for k, t := range types {
+ // Note: this recipe for creating a LocalSlot is designed
+ // to be compatible with the one used in expand_calls.go
+ // as opposed to decompose.go. The expand calls code just
+ // takes the base name and creates an offset into it,
+ // without using the SplitOf/SplitOffset fields. The code
+ // in decompose.go does the opposite -- it creates a
+ // LocalSlot object with "Off" set to zero, but with
+ // SplitOf pointing to a parent slot, and SplitOffset
+ // holding the offset into the parent object.
+ pieceSlot := LocalSlot{N: n, Type: t, Off: offsets[k]}
+
+ // Look up this piece to see if we've seen a reg op
+ // for it. If not, create one.
+ _, found := sc.lookup(pieceSlot)
+ if !found {
+ // This slot doesn't appear in the map, meaning it
+ // corresponds to an in-param that is not live, or
+ // a portion of an in-param that is not live/used.
+ // Add a new dummy OpArg{Int,Float}Reg for it.
+ synthesizeOpIntFloatArg(n, t, inp.Registers[k],
+ pieceSlot)
+ }
+ }
+ }
+
+ // Insert the new values into the head of the block.
+ f.Entry.Values = append(newValues, f.Entry.Values...)
+}
+
// BuildFuncDebug returns debug information for f.
// f must be fully processed, so that each Value is where it will be when
// machine code is emitted.
state.stackOffset = stackOffset
state.ctxt = ctxt
+ if buildcfg.Experiment.RegabiArgs {
+ PopulateABIInRegArgOps(f)
+ }
+
if state.loggingEnabled {
state.logf("Generating location lists for function %q\n", f.Name)
}
phiRegs[b.ID] = m
}
+ mustBeFirst := func(op Op) bool {
+ return op.isLoweredGetClosurePtr() || op == OpPhi || op == OpArgIntReg || op == OpArgFloatReg
+ }
+
// Start maps block IDs to the list of spills
// that go at the start of the block (but after any phis).
start := map[ID][]*Value{}
// Put the spill in the best block we found.
spill.Block = best
spill.AddArg(bestArg)
- if best == v.Block && v.Op != OpPhi {
+ if best == v.Block && !mustBeFirst(v.Op) {
// Place immediately after v.
after[v.ID] = append(after[v.ID], spill)
} else {
// Insert spill instructions into the block schedules.
var oldSched []*Value
for _, b := range s.visitOrder {
- nphi := 0
+ nfirst := 0
for _, v := range b.Values {
- if v.Op != OpPhi {
+ if !mustBeFirst(v.Op) {
break
}
- nphi++
+ nfirst++
}
- oldSched = append(oldSched[:0], b.Values[nphi:]...)
- b.Values = b.Values[:nphi]
+ oldSched = append(oldSched[:0], b.Values[nfirst:]...)
+ b.Values = b.Values[:nfirst]
b.Values = append(b.Values, start[b.ID]...)
for _, v := range oldSched {
b.Values = append(b.Values, v)
//
// Usage:
//
-// go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]
+// go doc [doc flags] [package|[package.]symbol[.methodOrField]]
//
// Doc prints the documentation comments associated with the item identified by its
// arguments (a package, const, func, type, var, method, or struct field)
var CmdDoc = &base.Command{
Run: runDoc,
- UsageLine: "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]",
+ UsageLine: "go doc [doc flags] [package|[package.]symbol[.methodOrField]]",
CustomFlags: true,
Short: "show documentation for package or symbol",
Long: `
sem := make(chan token, runtime.GOMAXPROCS(0))
infos, infosErr := modload.ListModules(ctx, args, 0)
if !haveExplicitArgs {
- // 'go mod download' is sometimes run without arguments to pre-populate
- // the module cache. It may fetch modules that aren't needed to build
- // packages in the main mdoule. This is usually not intended, so don't save
- // sums for downloaded modules (golang.org/issue/45332).
- // TODO(golang.org/issue/45551): For now, save sums needed to load the
- // build list (same as 1.15 behavior). In the future, report an error if
- // go.mod or go.sum need to be updated after loading the build list.
- modload.WriteGoMod(ctx)
+ // 'go mod download' is sometimes run without arguments to pre-populate the
+ // module cache. It may fetch modules that aren't needed to build packages
+ // in the main mdoule. This is usually not intended, so don't save sums for
+ // downloaded modules (golang.org/issue/45332).
+ // TODO(golang.org/issue/45551): For now, in ListModules, save sums needed
+ // to load the build list (same as 1.15 behavior). In the future, report an
+ // error if go.mod or go.sum need to be updated after loading the build
+ // list.
modload.DisallowWriteGoMod()
}
"cmd/go/internal/base"
"cmd/go/internal/imports"
"cmd/go/internal/load"
+ "cmd/go/internal/modfetch"
"cmd/go/internal/modload"
"cmd/go/internal/par"
"cmd/go/internal/search"
// checkPackageProblems reloads packages for the given patterns and reports
// missing and ambiguous package errors. It also reports retractions and
// deprecations for resolved modules and modules needed to build named packages.
+// It also adds a sum for each updated module in the build list if we had one
+// before and didn't get one while loading packages.
//
// We skip missing-package errors earlier in the process, since we want to
// resolve pathSets ourselves, but at that point, we don't have enough context
})
}
+ // Load sums for updated modules that had sums before. When we update a
+ // module, we may update another module in the build list that provides a
+ // package in 'all' that wasn't loaded as part of this 'go get' command.
+ // If we don't add a sum for that module, builds may fail later.
+ // Note that an incidentally updated package could still import packages
+ // from unknown modules or from modules in the build list that we didn't
+ // need previously. We can't handle that case without loading 'all'.
+ sumErrs := make([]error, len(r.buildList))
+ for i := range r.buildList {
+ i := i
+ m := r.buildList[i]
+ mActual := m
+ if mRepl := modload.Replacement(m); mRepl.Path != "" {
+ mActual = mRepl
+ }
+ old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
+ if old.Version == "" {
+ continue
+ }
+ oldActual := old
+ if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
+ oldActual = oldRepl
+ }
+ if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
+ continue
+ }
+ r.work.Add(func() {
+ if _, err := modfetch.DownloadZip(ctx, mActual); err != nil {
+ verb := "upgraded"
+ if semver.Compare(m.Version, old.Version) < 0 {
+ verb = "downgraded"
+ }
+ replaced := ""
+ if mActual != m {
+ replaced = fmt.Sprintf(" (replaced by %s)", mActual)
+ }
+ err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err)
+ sumErrs[i] = err
+ }
+ })
+ }
+
<-r.work.Idle()
- // Report deprecations, then retractions.
+ // Report deprecations, then retractions, then errors fetching sums.
+ // Only errors fetching sums are hard errors.
for _, mm := range deprecations {
if mm.message != "" {
fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message)
if retractPath != "" {
fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
}
+ for _, err := range sumErrs {
+ if err != nil {
+ base.Errorf("go: %v", err)
+ }
+ }
+ base.ExitIfErrors()
}
// reportChanges logs version changes to os.Stderr.
}
}
- if rs.depth == lazy && rs.graph.Load() == nil {
- // The main module is lazy and we haven't needed to load the module graph so
- // far. Don't incur the cost of loading it now — since we haven't loaded the
- // graph, we probably don't have any checksums to contribute to the distant
- // parts of the graph anyway. Instead, just request sums for the roots that
- // we know about.
+ if rs.graph.Load() == nil {
+ // The module graph was not loaded, possibly because the main module is lazy
+ // or possibly because we haven't needed to load the graph yet.
+ // Save sums for the root modules (or their replacements), but don't
+ // incur the cost of loading the graph just to find and retain the sums.
for _, m := range rs.rootModules {
r := resolveReplacement(m)
keep[modkey(r)] = true
+++ /dev/null
-# Tests Issue #12690
-
-[gccgo] skip 'gccgo does not have GOROOT'
-
-! stale runtime
-! stale os
-! stale io
-
-env GOROOT=$GOROOT'/'
-
-! stale runtime
-! stale os
-! stale io
\ No newline at end of file
--- /dev/null
+# golang.org/issue/46347: a stale runtime/cgo should only force a single rebuild
+
+[!cgo] skip
+[short] skip
+
+
+# If we set a unique CGO_CFLAGS, the installed copy of runtime/cgo
+# should be reported as stale.
+
+env CGO_CFLAGS=-DTestScript_cgo_stale=true
+stale runtime/cgo
+
+
+# If we then build a package that uses cgo, runtime/cgo should be rebuilt and
+# cached with the new flag, but not installed to GOROOT (and thus still stale).
+
+env GOCACHE=$WORK/cache # Use a fresh cache to avoid interference between runs.
+
+go build -x .
+stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
+stale runtime/cgo
+
+
+# After runtime/cgo has been rebuilt and cached, it should not be rebuilt again
+# even though it is still reported as stale.
+
+go build -x .
+! stderr '[/\\]cgo'$GOEXE'["]? .* -importpath runtime/cgo'
+stale runtime/cgo
+
+
+-- go.mod --
+module example.com/m
+
+go 1.17
+-- m.go --
+package m
+
+import "C"
+++ /dev/null
-# https://golang.org/issue/44725: packages in std should not be reported as stale,
-# regardless of whether they are listed from within or outside GOROOT/src.
-
-# Control case: net should not be stale at the start of the test,
-# and should depend on vendor/golang.org/… instead of golang.org/….
-
-! stale net
-
-go list -deps net
-stdout '^vendor/golang.org/x/net'
-! stdout '^golang.org/x/net'
-
-# Net should also not be stale when viewed from within GOROOT/src,
-# and should still report the same package dependencies.
-
-cd $GOROOT/src
-! stale net
-
-go list -deps net
-stdout '^vendor/golang.org/x/net'
-! stdout '^golang.org/x/net'
-
-
-# However, 'go mod' and 'go get' subcommands should report the original module
-# dependencies, not the vendored packages.
-
-[!net] stop
-
-env GOPROXY=
-go mod why -m golang.org/x/net
-stdout '^# golang.org/x/net\nnet\ngolang.org/x/net'
--- /dev/null
+# https://golang.org/issue/44725: packages in std should have the same
+# dependencies regardless of whether they are listed from within or outside
+# GOROOT/src.
+
+# Control case: net, viewed from outside the 'std' module,
+# should depend on vendor/golang.org/… instead of golang.org/….
+
+go list -deps net
+stdout '^vendor/golang.org/x/net'
+! stdout '^golang.org/x/net'
+cp stdout $WORK/net-deps.txt
+
+
+# It should still report the same package dependencies when viewed from
+# within GOROOT/src.
+
+cd $GOROOT/src
+
+go list -deps net
+stdout '^vendor/golang.org/x/net'
+! stdout '^golang.org/x/net'
+cmp stdout $WORK/net-deps.txt
+
+
+# However, 'go mod' and 'go get' subcommands should report the original module
+# dependencies, not the vendored packages.
+
+[!net] stop
+
+env GOPROXY=
+go mod why -m golang.org/x/net
+stdout '^# golang.org/x/net\nnet\ngolang.org/x/net'
-- update/go.sum.update --
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
-rsc.io/sampler v1.2.1/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
--- /dev/null
+# Check that 'go get' adds sums for updated modules if we had sums before,
+# even if we didn't load packages from them.
+# Verifies #44129.
+
+env fmt='{{.ImportPath}}: {{if .Error}}{{.Error.Err}}{{else}}ok{{end}}'
+
+# Control case: before upgrading, we have the sums we need.
+# go list -deps -e -f $fmt .
+# stdout '^rsc.io/quote: ok$'
+# ! stdout rsc.io/sampler # not imported by quote in this version
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+go mod tidy
+cmp go.mod.orig go.mod
+cmp go.sum.orig go.sum
+
+
+# Upgrade a module. This also upgrades rsc.io/quote, and though we didn't load
+# a package from it, we had the sum for its old version, so we need the
+# sum for the new version, too.
+go get -d example.com/upgrade@v0.0.2
+grep '^rsc.io/quote v1.5.2 ' go.sum
+
+# The upgrade still breaks the build because the new version of quote imports
+# rsc.io/sampler, and we don't have its zip sum.
+go list -deps -e -f $fmt
+stdout 'rsc.io/quote: ok'
+stdout 'rsc.io/sampler: missing go.sum entry for module providing package rsc.io/sampler'
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the old version with a directory before upgrading.
+# We didn't need a sum for it before (even though we had one), so we won't
+# fetch a new sum.
+go mod edit -replace rsc.io/quote@v1.0.0=./dummy
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the new version with a directory before upgrading.
+# We can't get a sum for a directory.
+go mod edit -replace rsc.io/quote@v1.5.2=./dummy
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Replace the new version with a different version.
+# We should get a sum for that version.
+go mod edit -replace rsc.io/quote@v1.5.2=rsc.io/quote@v1.5.1
+go get -d example.com/upgrade@v0.0.2
+! grep '^rsc.io/quote v1.5.2 ' go.sum
+grep '^rsc.io/quote v1.5.1 ' go.sum
+cp go.mod.orig go.mod
+cp go.sum.orig go.sum
+
+
+# Delete the new version's zip (but not mod) from the cache and go offline.
+# 'go get' should fail when fetching the zip.
+rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip
+env GOPROXY=off
+! go get -d example.com/upgrade@v0.0.2
+stderr '^go: upgraded rsc.io/quote v1.0.0 => v1.5.2: error finding sum for rsc.io/quote@v1.5.2: module lookup disabled by GOPROXY=off$'
+
+-- go.mod.orig --
+module m
+
+go 1.16
+
+require (
+ example.com/upgrade v0.0.1
+ rsc.io/quote v1.0.0
+)
+
+replace (
+ example.com/upgrade v0.0.1 => ./upgrade1
+ example.com/upgrade v0.0.2 => ./upgrade2
+)
+-- go.sum.orig --
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
+-- go.sum.want --
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+rsc.io/quote v1.0.0 h1:kQ3IZQzPTiDJxSZI98YaWgxFEhlNdYASHvh+MplbViw=
+rsc.io/quote v1.0.0/go.mod h1:v83Ri/njykPcgJltBc/gEkJTmjTsNgtO1Y7vyIK1CQA=
+rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
+rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+-- use.go --
+package use
+
+import (
+ _ "example.com/upgrade"
+ _ "rsc.io/quote"
+)
+-- upgrade1/go.mod --
+module example.com/upgrade
+
+go 1.16
+-- upgrade1/upgrade.go --
+package upgrade
+-- upgrade2/go.mod --
+module example.com/upgrade
+
+go 1.16
+
+require rsc.io/quote v1.5.2 // indirect
+-- upgrade2/upgrade.go --
+package upgrade
+-- dummy/go.mod --
+module rsc.io/quote
+
+go 1.16
+-- dummy/quote.go --
+package quote
+
[!race] skip
-[!darwin] ! stale cmd/cgo # The darwin builders are spuriously stale; see #33598.
-
env GOBIN=$WORK/bin
go install m/mtime m/sametime
# Build our simple toolexec program.
go build ./cmd/mytool
+# Use an ephemeral build cache so that our toolexec output is not cached
+# for any stale standard-library dependencies.
+#
+# TODO(#27628): This should not be necessary.
+env GOCACHE=$WORK/gocache
+
# Build the main package with our toolexec program. For each action, it will
# print the tool's name and the TOOLEXEC_IMPORTPATH value. We expect to compile
# each package once, and link the main package once.
"testing"
)
+// TestMain allows this test binary to run as a -toolexec wrapper for the 'go'
+// command. If LINK_TEST_TOOLEXEC is set, TestMain runs the binary as if it were
+// cmd/link, and otherwise runs the requested tool as a subprocess.
+//
+// This allows the test to verify the behavior of the current contents of the
+// cmd/link package even if the installed cmd/link binary is stale.
+func TestMain(m *testing.M) {
+ if os.Getenv("LINK_TEST_TOOLEXEC") == "" {
+ // Not running as a -toolexec wrapper. Just run the tests.
+ os.Exit(m.Run())
+ }
+
+ if strings.TrimSuffix(filepath.Base(os.Args[1]), ".exe") == "link" {
+ // Running as a -toolexec linker, and the tool is cmd/link.
+ // Substitute this test binary for the linker.
+ os.Args = os.Args[1:]
+ main()
+ os.Exit(0)
+ }
+
+ cmd := exec.Command(os.Args[1], os.Args[2:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ os.Exit(1)
+ }
+ os.Exit(0)
+}
+
func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string) {
testenv.MustHaveCGO(t)
testenv.MustHaveGoBuild(t)
t.Parallel()
- out, err := exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "cmd/link").CombinedOutput()
- if err != nil {
- t.Fatalf("go list: %v\n%s", err, out)
- }
- if string(out) != "false\n" {
- if strings.HasPrefix(testenv.Builder(), "darwin-") {
- t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598")
- }
- t.Fatalf("cmd/link is stale - run go install cmd/link")
- }
-
for _, prog := range []string{"testprog", "testprogcgo"} {
prog := prog
expectDWARF := expectDWARF
if extld == "" {
extld = "gcc"
}
+ var err error
expectDWARF, err = cmddwarf.IsDWARFEnabledOnAIXLd(extld)
if err != nil {
t.Fatal(err)
}
-
}
t.Run(prog, func(t *testing.T) {
exe := filepath.Join(tmpDir, prog+".exe")
dir := "../../runtime/testdata/" + prog
- cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-toolexec", os.Args[0], "-o", exe)
if buildmode != "" {
cmd.Args = append(cmd.Args, "-buildmode", buildmode)
}
cmd.Args = append(cmd.Args, dir)
- if env != nil {
- cmd.Env = append(os.Environ(), env...)
- cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
- }
+ cmd.Env = append(os.Environ(), env...)
+ cmd.Env = append(cmd.Env, "CGO_CFLAGS=") // ensure CGO_CFLAGS does not contain any flags. Issue #35459
+ cmd.Env = append(cmd.Env, "LINK_TEST_TOOLEXEC=1")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("go build -o %v %v: %v\n%s", exe, dir, err, out)
if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
// These symbols must have the same alignment as their section.
- // Otherwize, ld might change the layout of Go sections.
+ // Otherwise, ld might change the layout of Go sections.
ldr.SetSymAlign(ldr.Lookup("runtime.data", 0), state.dataMaxAlign[sym.SDATA])
ldr.SetSymAlign(ldr.Lookup("runtime.bss", 0), state.dataMaxAlign[sym.SBSS])
}
if err != nil {
t.Errorf("executable failed to run: %v\n%s", err, out)
}
- if string(out) != "hello\n" {
+ if string(out) != "hello\n" && string(out) != "hello\r\n" {
t.Errorf("unexpected output:\n%s", out)
}
if err != nil {
t.Errorf("executable failed to run: %v\n%s", err, out)
}
- if string(out) != "hello\n" {
+ if string(out) != "hello\n" && string(out) != "hello\r\n" {
t.Errorf("unexpected output:\n%s", out)
}
}
return x3.Equal(y2) == 1
}
-type p512Point struct {
+type p521Point struct {
x, y, z *fiat.P521Element
}
// affineFromJacobian brings a point in Jacobian coordinates back to affine
// coordinates, with (0, 0) representing infinity by convention. It also goes
// back to big.Int values to match the exposed API.
-func (curve p521Curve) affineFromJacobian(p *p512Point) (x, y *big.Int) {
+func (curve p521Curve) affineFromJacobian(p *p521Point) (x, y *big.Int) {
if p.z.IsZero() == 1 {
return new(big.Int), new(big.Int)
}
// jacobianFromAffine converts (x, y) affine coordinates into (x, y, z) Jacobian
// coordinates. It also converts from big.Int to fiat, which is necessarily a
// messy and variable-time operation, which we can't avoid due to the exposed API.
-func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p512Point {
+func (curve p521Curve) jacobianFromAffine(x, y *big.Int) *p521Point {
// (0, 0) is by convention the point at infinity, which can't be represented
// in affine coordinates, but is (0, 0, 0) in Jacobian.
if x.Sign() == 0 && y.Sign() == 0 {
- return &p512Point{
+ return &p521Point{
x: new(fiat.P521Element),
y: new(fiat.P521Element),
z: new(fiat.P521Element),
}
}
- return &p512Point{
+ return &p521Point{
x: bigIntToFiatP521(x),
y: bigIntToFiatP521(y),
z: new(fiat.P521Element).One(),
}
// addJacobian sets q = p1 + p2, and returns q. The points may overlap.
-func (q *p512Point) addJacobian(p1, p2 *p512Point) *p512Point {
+func (q *p521Point) addJacobian(p1, p2 *p521Point) *p521Point {
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
z1IsZero := p1.z.IsZero()
z2IsZero := p2.z.IsZero()
}
// doubleJacobian sets q = p + p, and returns q. The points may overlap.
-func (q *p512Point) doubleJacobian(p *p512Point) *p512Point {
+func (q *p521Point) doubleJacobian(p *p521Point) *p521Point {
// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
delta := new(fiat.P521Element).Square(p.z)
gamma := new(fiat.P521Element).Square(p.y)
func (curve p521Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
B := curve.jacobianFromAffine(Bx, By)
- p, t := &p512Point{
+ p, t := &p521Point{
x: new(fiat.P521Element),
y: new(fiat.P521Element),
z: new(fiat.P521Element),
- }, &p512Point{
+ }, &p521Point{
x: new(fiat.P521Element),
y: new(fiat.P521Element),
z: new(fiat.P521Element),
return token.NoPos
}
-// NumFields returns the number of (type) parameters or struct fields represented by a FieldList.
+// NumFields returns the number of parameters or struct fields represented by a FieldList.
func (f *FieldList) NumFields() int {
n := 0
if f != nil {
}
)
-func (f *FuncDecl) IsMethod() bool {
- return f.Recv.NumFields() != 0
-}
-
// Pos and End implementations for declaration nodes.
func (d *BadDecl) Pos() token.Pos { return d.From }
// A Config specifies the configuration for type checking.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
- // GoVersion describes the accepted Go language version. The string
+ // goVersion describes the accepted Go language version. The string
// must follow the format "go%d.%d" (e.g. "go1.12") or it must be
// empty; an empty string indicates the latest language version.
// If the format is invalid, invoking the type checker will cause a
// panic.
- GoVersion string
+ goVersion string
// If IgnoreFuncBodies is set, function bodies are not
// type-checked.
info = new(Info)
}
- version, err := parseGoVersion(conf.GoVersion)
+ version, err := parseGoVersion(conf.goVersion)
if err != nil {
- panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
+ panic(fmt.Sprintf("invalid Go version %q (%v)", conf.goVersion, err))
}
return &Checker{
// typecheck and collect typechecker errors
var conf Config
conf.Sizes = sizes
- conf.GoVersion = goVersion
+ SetGoVersion(&conf, goVersion)
// special case for importC.src
if len(filenames) == 1 {
checkFiles(t, &StdSizes{4, 4}, "", []string{"index.go"}, [][]byte{[]byte(src)}, false)
}
+func TestIssue46453(t *testing.T) {
+ if typeparams.Enabled {
+ t.Skip("type params are enabled")
+ }
+ const src = "package p\ntype _ comparable // ERROR \"undeclared name: comparable\""
+ checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false)
+}
+
func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "check") }
func TestExamples(t *testing.T) { testDir(t, "examples") }
func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") }
// n0.check != nil, the cycle is reported.
func (n0 *Named) under() Type {
u := n0.underlying
- if u == nil {
- return Typ[Invalid]
+
+ if u == Typ[Invalid] {
+ return u
}
// If the underlying type of a defined type is not a defined
- // type, then that is the desired underlying type.
+ // (incl. instance) type, then that is the desired underlying
+ // type.
+ switch u.(type) {
+ case nil:
+ return Typ[Invalid]
+ default:
+ // common case
+ return u
+ case *Named, *instance:
+ // handled below
+ }
+
+ if n0.check == nil {
+ panic("internal error: Named.check == nil but type is incomplete")
+ }
+
+ // Invariant: after this point n0 as well as any named types in its
+ // underlying chain should be set up when this function exits.
+ check := n0.check
+
+ // If we can't expand u at this point, it is invalid.
n := asNamed(u)
if n == nil {
- return u // common case
+ n0.underlying = Typ[Invalid]
+ return n0.underlying
}
// Otherwise, follow the forward chain.
u = Typ[Invalid]
break
}
- n1 := asNamed(u)
+ var n1 *Named
+ switch u1 := u.(type) {
+ case *Named:
+ n1 = u1
+ case *instance:
+ n1, _ = u1.expand().(*Named)
+ if n1 == nil {
+ u = Typ[Invalid]
+ }
+ }
if n1 == nil {
break // end of chain
}
if i, ok := seen[n]; ok {
// cycle
- // TODO(rFindley) revert this to a method on Checker. Having a possibly
- // nil Checker on Named and TypeParam is too subtle.
- if n0.check != nil {
- n0.check.cycleError(path[i:])
- }
+ check.cycleError(path[i:])
u = Typ[Invalid]
break
}
// We should never have to update the underlying type of an imported type;
// those underlying types should have been resolved during the import.
// Also, doing so would lead to a race condition (was issue #31749).
- // Do this check always, not just in debug more (it's cheap).
- if n0.check != nil && n.obj.pkg != n0.check.pkg {
+ // Do this check always, not just in debug mode (it's cheap).
+ if n.obj.pkg != check.pkg {
panic("internal error: imported type with unresolved underlying type")
}
n.underlying = u
} else {
// defined type declaration
- named := &Named{check: check, obj: obj}
+ named := check.newNamed(obj, nil, nil)
def.setUnderlying(named)
obj.typ = named // make sure recursive type declarations terminate
info := &declInfo{file: fileScope, fdecl: d.decl}
name := d.decl.Name.Name
obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil)
- if !d.decl.IsMethod() {
+ if d.decl.Recv.NumFields() == 0 {
// regular function
if d.decl.Recv != nil {
check.error(d.decl.Recv, _BadRecv, "method is missing receiver")
}
case *Named:
+ if debug && t.check != nil {
+ panic("internal error: Named.check != nil")
+ }
if orig := s.typ(t.orig); orig != t.orig {
t.orig = orig
}
// parse and type-check file
file, err := parser.ParseFile(fset, filename, nil, 0)
if err == nil {
- conf := Config{GoVersion: goVersion, Importer: stdLibImporter}
+ conf := Config{Importer: stdLibImporter}
+ SetGoVersion(&conf, goVersion)
_, err = conf.Check(filename, fset, []*ast.File{file}, nil)
}
// A Named represents a named (defined) type.
type Named struct {
- check *Checker // for Named.under implementation
+ check *Checker // for Named.under implementation; nilled once under has been called
info typeInfo // for cycle detection
obj *TypeName // corresponding declared object
orig Type // type (on RHS of declaration) this *Named type is derived of (for cycle reporting)
if _, ok := underlying.(*Named); ok {
panic("types.NewNamed: underlying type must not be *Named")
}
- typ := &Named{obj: obj, orig: underlying, underlying: underlying, methods: methods}
- if obj.typ == nil {
- obj.typ = typ
- }
- return typ
+ return (*Checker)(nil).newNamed(obj, underlying, methods)
}
func (check *Checker) newNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
if obj.typ == nil {
obj.typ = typ
}
+ // Ensure that typ is always expanded, at which point the check field can be
+ // nilled out.
+ //
+ // Note that currently we cannot nil out check inside typ.under(), because
+ // it's possible that typ is expanded multiple times.
+ //
+ // TODO(rFindley): clean this up so that under is the only function mutating
+ // named types.
+ if check != nil {
+ check.later(func() {
+ switch typ.under().(type) {
+ case *Named, *instance:
+ panic("internal error: unexpanded underlying type")
+ }
+ typ.check = nil
+ })
+ }
return typ
}
// for tests where we may want to have a consistent
// numbering for each individual test case.
func ResetId() { atomic.StoreUint32(&lastId, 0) }
+
+// SetGoVersion sets the unexported goVersion field on config, so that tests
+// which assert on behavior for older Go versions can set it.
+func SetGoVersion(config *Config, goVersion string) {
+ config.goVersion = goVersion
+}
import (
"go/constant"
+ "go/internal/typeparams"
"go/token"
"strings"
)
defPredeclaredConsts()
defPredeclaredNil()
defPredeclaredFuncs()
- defPredeclaredComparable()
+ if typeparams.Enabled {
+ defPredeclaredComparable()
+ }
universeIota = Universe.Lookup("iota").(*Const)
universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
return Word(qq), Word(r0 >> s)
}
-func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
- r = xn
- if len(x) == 1 {
- qq, rr := bits.Div(uint(r), uint(x[0]), uint(y))
- z[0] = Word(qq)
- return Word(rr)
- }
- rec := reciprocalWord(y)
- for i := len(z) - 1; i >= 0; i-- {
- z[i], r = divWW(r, x[i], y, rec)
- }
- return r
-}
-
// reciprocalWord return the reciprocal of the divisor. rec = floor(( _B^2 - 1 ) / u - _B). u = d1 << nlz(d1).
func reciprocalWord(d1 Word) Word {
u := uint(d1 << nlz(d1))
return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
}
-// q = (x-r)/y, with 0 <= r < y
-func (z nat) divW(x nat, y Word) (q nat, r Word) {
- m := len(x)
- switch {
- case y == 0:
- panic("division by zero")
- case y == 1:
- q = z.set(x) // result is x
- return
- case m == 0:
- q = z[:0] // result is 0
- return
- }
- // m > 0
- z = z.make(m)
- r = divWVW(z, 0, x, y)
- q = z.norm()
- return
-}
-
-func (z nat) div(z2, u, v nat) (q, r nat) {
- if len(v) == 0 {
- panic("division by zero")
- }
-
- if u.cmp(v) < 0 {
- q = z[:0]
- r = z2.set(u)
- return
- }
-
- if len(v) == 1 {
- var r2 Word
- q, r2 = z.divW(u, v[0])
- r = z2.setWord(r2)
- return
- }
-
- q, r = z.divLarge(z2, u, v)
- return
-}
-
// getNat returns a *nat of len n. The contents may not be zero.
// The pool holds *nat to avoid allocation when converting to interface{}.
func getNat(n int) *nat {
var natPool sync.Pool
-// q = (uIn-r)/vIn, with 0 <= r < vIn
-// Uses z as storage for q, and u as storage for r if possible.
-// See Knuth, Volume 2, section 4.3.1, Algorithm D.
-// Preconditions:
-// len(vIn) >= 2
-// len(uIn) >= len(vIn)
-// u must not alias z
-func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) {
- n := len(vIn)
- m := len(uIn) - n
-
- // D1.
- shift := nlz(vIn[n-1])
- // do not modify vIn, it may be used by another goroutine simultaneously
- vp := getNat(n)
- v := *vp
- shlVU(v, vIn, shift)
-
- // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used
- u = u.make(len(uIn) + 1)
- u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
-
- // z may safely alias uIn or vIn, both values were used already
- if alias(z, u) {
- z = nil // z is an alias for u - cannot reuse
- }
- q = z.make(m + 1)
-
- if n < divRecursiveThreshold {
- q.divBasic(u, v)
- } else {
- q.divRecursive(u, v)
- }
- putNat(vp)
-
- q = q.norm()
- shrVU(u, u, shift)
- r = u.norm()
-
- return q, r
-}
-
-// divBasic performs word-by-word division of u by v.
-// The quotient is written in pre-allocated q.
-// The remainder overwrites input u.
-//
-// Precondition:
-// - q is large enough to hold the quotient u / v
-// which has a maximum length of len(u)-len(v)+1.
-func (q nat) divBasic(u, v nat) {
- n := len(v)
- m := len(u) - n
-
- qhatvp := getNat(n + 1)
- qhatv := *qhatvp
-
- // D2.
- vn1 := v[n-1]
- rec := reciprocalWord(vn1)
- for j := m; j >= 0; j-- {
- // D3.
- qhat := Word(_M)
- var ujn Word
- if j+n < len(u) {
- ujn = u[j+n]
- }
- if ujn != vn1 {
- var rhat Word
- qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec)
-
- // x1 | x2 = q̂v_{n-2}
- vn2 := v[n-2]
- x1, x2 := mulWW(qhat, vn2)
- // test if q̂v_{n-2} > br̂ + u_{j+n-2}
- ujn2 := u[j+n-2]
- for greaterThan(x1, x2, rhat, ujn2) {
- qhat--
- prevRhat := rhat
- rhat += vn1
- // v[n-1] >= 0, so this tests for overflow.
- if rhat < prevRhat {
- break
- }
- x1, x2 = mulWW(qhat, vn2)
- }
- }
-
- // D4.
- // Compute the remainder u - (q̂*v) << (_W*j).
- // The subtraction may overflow if q̂ estimate was off by one.
- qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
- qhl := len(qhatv)
- if j+qhl > len(u) && qhatv[n] == 0 {
- qhl--
- }
- c := subVV(u[j:j+qhl], u[j:], qhatv)
- if c != 0 {
- c := addVV(u[j:j+n], u[j:], v)
- // If n == qhl, the carry from subVV and the carry from addVV
- // cancel out and don't affect u[j+n].
- if n < qhl {
- u[j+n] += c
- }
- qhat--
- }
-
- if j == m && m == len(q) && qhat == 0 {
- continue
- }
- q[j] = qhat
- }
-
- putNat(qhatvp)
-}
-
-const divRecursiveThreshold = 100
-
-// divRecursive performs word-by-word division of u by v.
-// The quotient is written in pre-allocated z.
-// The remainder overwrites input u.
-//
-// Precondition:
-// - len(z) >= len(u)-len(v)
-//
-// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2.
-func (z nat) divRecursive(u, v nat) {
- // Recursion depth is less than 2 log2(len(v))
- // Allocate a slice of temporaries to be reused across recursion.
- recDepth := 2 * bits.Len(uint(len(v)))
- // large enough to perform Karatsuba on operands as large as v
- tmp := getNat(3 * len(v))
- temps := make([]*nat, recDepth)
- z.clear()
- z.divRecursiveStep(u, v, 0, tmp, temps)
- for _, n := range temps {
- if n != nil {
- putNat(n)
- }
- }
- putNat(tmp)
-}
-
-// divRecursiveStep computes the division of u by v.
-// - z must be large enough to hold the quotient
-// - the quotient will overwrite z
-// - the remainder will overwrite u
-func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) {
- u = u.norm()
- v = v.norm()
-
- if len(u) == 0 {
- z.clear()
- return
- }
- n := len(v)
- if n < divRecursiveThreshold {
- z.divBasic(u, v)
- return
- }
- m := len(u) - n
- if m < 0 {
- return
- }
-
- // Produce the quotient by blocks of B words.
- // Division by v (length n) is done using a length n/2 division
- // and a length n/2 multiplication for each block. The final
- // complexity is driven by multiplication complexity.
- B := n / 2
-
- // Allocate a nat for qhat below.
- if temps[depth] == nil {
- temps[depth] = getNat(n)
- } else {
- *temps[depth] = temps[depth].make(B + 1)
- }
-
- j := m
- for j > B {
- // Divide u[j-B:j+n] by vIn. Keep remainder in u
- // for next block.
- //
- // The following property will be used (Lemma 2):
- // if u = u1 << s + u0
- // v = v1 << s + v0
- // then floor(u1/v1) >= floor(u/v)
- //
- // Moreover, the difference is at most 2 if len(v1) >= len(u/v)
- // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v)
- s := (B - 1)
- // Except for the first step, the top bits are always
- // a division remainder, so the quotient length is <= n.
- uu := u[j-B:]
-
- qhat := *temps[depth]
- qhat.clear()
- qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps)
- qhat = qhat.norm()
- // Adjust the quotient:
- // u = u_h << s + u_l
- // v = v_h << s + v_l
- // u_h = q̂ v_h + rh
- // u = q̂ (v - v_l) + rh << s + u_l
- // After the above step, u contains a remainder:
- // u = rh << s + u_l
- // and we need to subtract q̂ v_l
- //
- // But it may be a bit too large, in which case q̂ needs to be smaller.
- qhatv := tmp.make(3 * n)
- qhatv.clear()
- qhatv = qhatv.mul(qhat, v[:s])
- for i := 0; i < 2; i++ {
- e := qhatv.cmp(uu.norm())
- if e <= 0 {
- break
- }
- subVW(qhat, qhat, 1)
- c := subVV(qhatv[:s], qhatv[:s], v[:s])
- if len(qhatv) > s {
- subVW(qhatv[s:], qhatv[s:], c)
- }
- addAt(uu[s:], v[s:], 0)
- }
- if qhatv.cmp(uu.norm()) > 0 {
- panic("impossible")
- }
- c := subVV(uu[:len(qhatv)], uu[:len(qhatv)], qhatv)
- if c > 0 {
- subVW(uu[len(qhatv):], uu[len(qhatv):], c)
- }
- addAt(z, qhat, j-B)
- j -= B
- }
-
- // Now u < (v<<B), compute lower bits in the same way.
- // Choose shift = B-1 again.
- s := B - 1
- qhat := *temps[depth]
- qhat.clear()
- qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps)
- qhat = qhat.norm()
- qhatv := tmp.make(3 * n)
- qhatv.clear()
- qhatv = qhatv.mul(qhat, v[:s])
- // Set the correct remainder as before.
- for i := 0; i < 2; i++ {
- if e := qhatv.cmp(u.norm()); e > 0 {
- subVW(qhat, qhat, 1)
- c := subVV(qhatv[:s], qhatv[:s], v[:s])
- if len(qhatv) > s {
- subVW(qhatv[s:], qhatv[s:], c)
- }
- addAt(u[s:], v[s:], 0)
- }
- }
- if qhatv.cmp(u.norm()) > 0 {
- panic("impossible")
- }
- c := subVV(u[0:len(qhatv)], u[0:len(qhatv)], qhatv)
- if c > 0 {
- c = subVW(u[len(qhatv):], u[len(qhatv):], c)
- }
- if c > 0 {
- panic("impossible")
- }
-
- // Done!
- addAt(z, qhat.norm(), 0)
-}
-
// Length of x in bits. x must be normalized.
func (x nat) bitLen() int {
if i := len(x) - 1; i >= 0 {
return z.norm()
}
-// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
-func greaterThan(x1, x2, y1, y2 Word) bool {
- return x1 > y1 || x1 == y1 && x2 > y2
-}
-
-// modW returns x % d.
-func (x nat) modW(d Word) (r Word) {
- // TODO(agl): we don't actually need to store the q value.
- var q nat
- q = q.make(len(x))
- return divWVW(q, 0, x, d)
-}
-
// random creates a random integer in [0..limit), using the space in z if
// possible. n is the bit length of limit.
func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
--- /dev/null
+// Copyright 2009 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 big
+
+import "math/bits"
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+ if len(v) == 0 {
+ panic("division by zero")
+ }
+
+ if u.cmp(v) < 0 {
+ q = z[:0]
+ r = z2.set(u)
+ return
+ }
+
+ if len(v) == 1 {
+ var r2 Word
+ q, r2 = z.divW(u, v[0])
+ r = z2.setWord(r2)
+ return
+ }
+
+ q, r = z.divLarge(z2, u, v)
+ return
+}
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+ m := len(x)
+ switch {
+ case y == 0:
+ panic("division by zero")
+ case y == 1:
+ q = z.set(x) // result is x
+ return
+ case m == 0:
+ q = z[:0] // result is 0
+ return
+ }
+ // m > 0
+ z = z.make(m)
+ r = divWVW(z, 0, x, y)
+ q = z.norm()
+ return
+}
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+ // TODO(agl): we don't actually need to store the q value.
+ var q nat
+ q = q.make(len(x))
+ return divWVW(q, 0, x, d)
+}
+
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
+ r = xn
+ if len(x) == 1 {
+ qq, rr := bits.Div(uint(r), uint(x[0]), uint(y))
+ z[0] = Word(qq)
+ return Word(rr)
+ }
+ rec := reciprocalWord(y)
+ for i := len(z) - 1; i >= 0; i-- {
+ z[i], r = divWW(r, x[i], y, rec)
+ }
+ return r
+}
+
+// q = (uIn-r)/vIn, with 0 <= r < vIn
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+// len(vIn) >= 2
+// len(uIn) >= len(vIn)
+// u must not alias z
+func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) {
+ n := len(vIn)
+ m := len(uIn) - n
+
+ // D1.
+ shift := nlz(vIn[n-1])
+ // do not modify vIn, it may be used by another goroutine simultaneously
+ vp := getNat(n)
+ v := *vp
+ shlVU(v, vIn, shift)
+
+ // u may safely alias uIn or vIn, the value of uIn is used to set u and vIn was already used
+ u = u.make(len(uIn) + 1)
+ u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
+
+ // z may safely alias uIn or vIn, both values were used already
+ if alias(z, u) {
+ z = nil // z is an alias for u - cannot reuse
+ }
+ q = z.make(m + 1)
+
+ if n < divRecursiveThreshold {
+ q.divBasic(u, v)
+ } else {
+ q.divRecursive(u, v)
+ }
+ putNat(vp)
+
+ q = q.norm()
+ shrVU(u, u, shift)
+ r = u.norm()
+
+ return q, r
+}
+
+// divBasic performs word-by-word division of u by v.
+// The quotient is written in pre-allocated q.
+// The remainder overwrites input u.
+//
+// Precondition:
+// - q is large enough to hold the quotient u / v
+// which has a maximum length of len(u)-len(v)+1.
+func (q nat) divBasic(u, v nat) {
+ n := len(v)
+ m := len(u) - n
+
+ qhatvp := getNat(n + 1)
+ qhatv := *qhatvp
+
+ // D2.
+ vn1 := v[n-1]
+ rec := reciprocalWord(vn1)
+ for j := m; j >= 0; j-- {
+ // D3.
+ qhat := Word(_M)
+ var ujn Word
+ if j+n < len(u) {
+ ujn = u[j+n]
+ }
+ if ujn != vn1 {
+ var rhat Word
+ qhat, rhat = divWW(ujn, u[j+n-1], vn1, rec)
+
+ // x1 | x2 = q̂v_{n-2}
+ vn2 := v[n-2]
+ x1, x2 := mulWW(qhat, vn2)
+ // test if q̂v_{n-2} > br̂ + u_{j+n-2}
+ ujn2 := u[j+n-2]
+ for greaterThan(x1, x2, rhat, ujn2) {
+ qhat--
+ prevRhat := rhat
+ rhat += vn1
+ // v[n-1] >= 0, so this tests for overflow.
+ if rhat < prevRhat {
+ break
+ }
+ x1, x2 = mulWW(qhat, vn2)
+ }
+ }
+
+ // D4.
+ // Compute the remainder u - (q̂*v) << (_W*j).
+ // The subtraction may overflow if q̂ estimate was off by one.
+ qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+ qhl := len(qhatv)
+ if j+qhl > len(u) && qhatv[n] == 0 {
+ qhl--
+ }
+ c := subVV(u[j:j+qhl], u[j:], qhatv)
+ if c != 0 {
+ c := addVV(u[j:j+n], u[j:], v)
+ // If n == qhl, the carry from subVV and the carry from addVV
+ // cancel out and don't affect u[j+n].
+ if n < qhl {
+ u[j+n] += c
+ }
+ qhat--
+ }
+
+ if j == m && m == len(q) && qhat == 0 {
+ continue
+ }
+ q[j] = qhat
+ }
+
+ putNat(qhatvp)
+}
+
+// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool {
+ return x1 > y1 || x1 == y1 && x2 > y2
+}
+
+const divRecursiveThreshold = 100
+
+// divRecursive performs word-by-word division of u by v.
+// The quotient is written in pre-allocated z.
+// The remainder overwrites input u.
+//
+// Precondition:
+// - len(z) >= len(u)-len(v)
+//
+// See Burnikel, Ziegler, "Fast Recursive Division", Algorithm 1 and 2.
+func (z nat) divRecursive(u, v nat) {
+ // Recursion depth is less than 2 log2(len(v))
+ // Allocate a slice of temporaries to be reused across recursion.
+ recDepth := 2 * bits.Len(uint(len(v)))
+ // large enough to perform Karatsuba on operands as large as v
+ tmp := getNat(3 * len(v))
+ temps := make([]*nat, recDepth)
+ z.clear()
+ z.divRecursiveStep(u, v, 0, tmp, temps)
+ for _, n := range temps {
+ if n != nil {
+ putNat(n)
+ }
+ }
+ putNat(tmp)
+}
+
+// divRecursiveStep computes the division of u by v.
+// - z must be large enough to hold the quotient
+// - the quotient will overwrite z
+// - the remainder will overwrite u
+func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) {
+ u = u.norm()
+ v = v.norm()
+
+ if len(u) == 0 {
+ z.clear()
+ return
+ }
+ n := len(v)
+ if n < divRecursiveThreshold {
+ z.divBasic(u, v)
+ return
+ }
+ m := len(u) - n
+ if m < 0 {
+ return
+ }
+
+ // Produce the quotient by blocks of B words.
+ // Division by v (length n) is done using a length n/2 division
+ // and a length n/2 multiplication for each block. The final
+ // complexity is driven by multiplication complexity.
+ B := n / 2
+
+ // Allocate a nat for qhat below.
+ if temps[depth] == nil {
+ temps[depth] = getNat(n)
+ } else {
+ *temps[depth] = temps[depth].make(B + 1)
+ }
+
+ j := m
+ for j > B {
+ // Divide u[j-B:j+n] by vIn. Keep remainder in u
+ // for next block.
+ //
+ // The following property will be used (Lemma 2):
+ // if u = u1 << s + u0
+ // v = v1 << s + v0
+ // then floor(u1/v1) >= floor(u/v)
+ //
+ // Moreover, the difference is at most 2 if len(v1) >= len(u/v)
+ // We choose s = B-1 since len(v)-s >= B+1 >= len(u/v)
+ s := (B - 1)
+ // Except for the first step, the top bits are always
+ // a division remainder, so the quotient length is <= n.
+ uu := u[j-B:]
+
+ qhat := *temps[depth]
+ qhat.clear()
+ qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps)
+ qhat = qhat.norm()
+ // Adjust the quotient:
+ // u = u_h << s + u_l
+ // v = v_h << s + v_l
+ // u_h = q̂ v_h + rh
+ // u = q̂ (v - v_l) + rh << s + u_l
+ // After the above step, u contains a remainder:
+ // u = rh << s + u_l
+ // and we need to subtract q̂ v_l
+ //
+ // But it may be a bit too large, in which case q̂ needs to be smaller.
+ qhatv := tmp.make(3 * n)
+ qhatv.clear()
+ qhatv = qhatv.mul(qhat, v[:s])
+ for i := 0; i < 2; i++ {
+ e := qhatv.cmp(uu.norm())
+ if e <= 0 {
+ break
+ }
+ subVW(qhat, qhat, 1)
+ c := subVV(qhatv[:s], qhatv[:s], v[:s])
+ if len(qhatv) > s {
+ subVW(qhatv[s:], qhatv[s:], c)
+ }
+ addAt(uu[s:], v[s:], 0)
+ }
+ if qhatv.cmp(uu.norm()) > 0 {
+ panic("impossible")
+ }
+ c := subVV(uu[:len(qhatv)], uu[:len(qhatv)], qhatv)
+ if c > 0 {
+ subVW(uu[len(qhatv):], uu[len(qhatv):], c)
+ }
+ addAt(z, qhat, j-B)
+ j -= B
+ }
+
+ // Now u < (v<<B), compute lower bits in the same way.
+ // Choose shift = B-1 again.
+ s := B - 1
+ qhat := *temps[depth]
+ qhat.clear()
+ qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps)
+ qhat = qhat.norm()
+ qhatv := tmp.make(3 * n)
+ qhatv.clear()
+ qhatv = qhatv.mul(qhat, v[:s])
+ // Set the correct remainder as before.
+ for i := 0; i < 2; i++ {
+ if e := qhatv.cmp(u.norm()); e > 0 {
+ subVW(qhat, qhat, 1)
+ c := subVV(qhatv[:s], qhatv[:s], v[:s])
+ if len(qhatv) > s {
+ subVW(qhatv[s:], qhatv[s:], c)
+ }
+ addAt(u[s:], v[s:], 0)
+ }
+ }
+ if qhatv.cmp(u.norm()) > 0 {
+ panic("impossible")
+ }
+ c := subVV(u[0:len(qhatv)], u[0:len(qhatv)], qhatv)
+ if c > 0 {
+ c = subVW(u[len(qhatv):], u[len(qhatv):], c)
+ }
+ if c > 0 {
+ panic("impossible")
+ }
+
+ // Done!
+ addAt(z, qhat.norm(), 0)
+}
// Extensions are looked up first case-sensitively, then case-insensitively.
//
// The built-in table is small but on unix it is augmented by the local
-// system's mime.types file(s) if available under one or more of these
-// names:
+// system's MIME-info database or mime.types file(s) if available under one or
+// more of these names:
//
+// /usr/local/share/mime/globs2
+// /usr/share/mime/globs2
// /etc/mime.types
// /etc/apache2/mime.types
// /etc/apache/mime.types
return r, nil
},
}
+
r := Resolver{PreferGo: true, Dial: fake.DialContext}
+ // Change the default resolver to match our manipulated resolver
+ originalDefault := DefaultResolver
+ DefaultResolver = &r
+ defer func() {
+ DefaultResolver = originalDefault
+ }()
_, err := r.LookupCNAME(context.Background(), "golang.org")
- if expected := "lookup golang.org: CNAME target is invalid"; err.Error() != expected {
+ if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected)
+ }
+ _, err = LookupCNAME("golang.org")
+ if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err.Error(), expected)
}
+
_, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
- if expected := "lookup golang.org: SRV target is invalid"; err.Error() != expected {
+ if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
+ }
+ _, _, err = LookupSRV("target", "tcp", "golang.org")
+ if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
}
+
_, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org")
- if expected := "lookup golang.org: SRV header name is invalid"; err.Error() != expected {
+ if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
+ }
+ _, _, err = LookupSRV("hdr", "tcp", "golang.org")
+ if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err.Error(), expected)
}
+
_, err = r.LookupMX(context.Background(), "golang.org")
- if expected := "lookup golang.org: MX target is invalid"; err.Error() != expected {
+ if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err.Error(), expected)
+ }
+ _, err = LookupMX("golang.org")
+ if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupMX returned unexpected error, got %q, want %q", err.Error(), expected)
}
+
_, err = r.LookupNS(context.Background(), "golang.org")
- if expected := "lookup golang.org: NS target is invalid"; err.Error() != expected {
+ if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err.Error(), expected)
+ }
+ _, err = LookupNS("golang.org")
+ if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupNS returned unexpected error, got %q, want %q", err.Error(), expected)
}
+
_, err = r.LookupAddr(context.Background(), "1.2.3.4")
- if expected := "lookup 1.2.3.4: PTR target is invalid"; err.Error() != expected {
+ if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected {
+ t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected)
+ }
+ _, err = LookupAddr("1.2.3.4")
+ if expected := "lookup 1.2.3.4: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err.Error(), expected)
}
}
// An error is returned if there were too many redirects or if there
// was an HTTP protocol error. A non-2xx response doesn't cause an
// error. Any returned error will be of type *url.Error. The url.Error
-// value's Timeout method will report true if request timed out or was
-// canceled.
+// value's Timeout method will report true if the request timed out.
//
// When err is nil, resp always contains a non-nil resp.Body.
// Caller should close resp.Body when done reading from it.
// standard library body types.
//
// Any returned error will be of type *url.Error. The url.Error
-// value's Timeout method will report true if request timed out or was
-// canceled.
+// value's Timeout method will report true if the request timed out.
func (c *Client) Do(req *Request) (*Response, error) {
return c.do(req)
}
reqBodyClosed = true
if !deadline.IsZero() && didTimeout() {
err = &httpError{
- // TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
timeout: true,
}
// important is "Connection" because we want a persistent
// connection, regardless of what the client sent to us.
for _, h := range hopHeaders {
- hv := outreq.Header.Get(h)
- if hv == "" {
- continue
- }
- if h == "Te" && hv == "trailers" {
- // Issue 21096: tell backend applications that
- // care about trailer support that we support
- // trailers. (We do, but we don't go out of
- // our way to advertise that unless the
- // incoming client request thought it was
- // worth mentioning)
- continue
- }
outreq.Header.Del(h)
}
+ // Issue 21096: tell backend applications that care about trailer support
+ // that we support trailers. (We do, but we don't go out of our way to
+ // advertise that unless the incoming client request thought it was worth
+ // mentioning.) Note that we look at req.Header, not outreq.Header, since
+ // the latter has passed through removeConnectionHeaders.
+ if httpguts.HeaderValuesContainsToken(req.Header["Te"], "trailers") {
+ outreq.Header.Set("Te", "trailers")
+ }
+
// After stripping all the hop-by-hop connection headers above, add back any
// necessary for protocol upgrades, such as for websockets.
if reqUpType != "" {
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
getReq.Host = "some-name"
- getReq.Header.Set("Connection", "close")
- getReq.Header.Set("Te", "trailers")
+ getReq.Header.Set("Connection", "close, TE")
+ getReq.Header.Add("Te", "foo")
+ getReq.Header.Add("Te", "bar, trailers")
getReq.Header.Set("Proxy-Connection", "should be deleted")
getReq.Header.Set("Upgrade", "foo")
getReq.Close = true
}
}
+func TestReverseProxyStripEmptyConnection(t *testing.T) {
+ // See Issue 46313.
+ const backendResponse = "I am the backend"
+
+ // someConnHeader is some arbitrary header to be declared as a hop-by-hop header
+ // in the Request's Connection header.
+ const someConnHeader = "X-Some-Conn-Header"
+
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if c := r.Header.Values("Connection"); len(c) != 0 {
+ t.Errorf("handler got header %q = %v; want empty", "Connection", c)
+ }
+ if c := r.Header.Get(someConnHeader); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", someConnHeader, c)
+ }
+ w.Header().Add("Connection", "")
+ w.Header().Add("Connection", someConnHeader)
+ w.Header().Set(someConnHeader, "should be deleted")
+ io.WriteString(w, backendResponse)
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ proxyHandler.ServeHTTP(w, r)
+ if c := r.Header.Get(someConnHeader); c != "should be deleted" {
+ t.Errorf("handler modified header %q = %q; want %q", someConnHeader, c, "should be deleted")
+ }
+ }))
+ defer frontend.Close()
+
+ getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+ getReq.Header.Add("Connection", "")
+ getReq.Header.Add("Connection", someConnHeader)
+ getReq.Header.Set(someConnHeader, "should be deleted")
+ res, err := frontend.Client().Do(getReq)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ defer res.Body.Close()
+ bodyBytes, err := io.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("reading body: %v", err)
+ }
+ if got, want := string(bodyBytes), backendResponse; got != want {
+ t.Errorf("got body %q; want %q", got, want)
+ }
+ if c := res.Header.Get("Connection"); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", "Connection", c)
+ }
+ if c := res.Header.Get(someConnHeader); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", someConnHeader, c)
+ }
+}
+
func TestXForwardedFor(t *testing.T) {
const prevForwardedFor = "client ip"
const backendResponse = "I am the backend"
// LookupCNAME uses context.Background internally; to specify the context, use
// Resolver.LookupCNAME.
func LookupCNAME(host string) (cname string, err error) {
- return DefaultResolver.lookupCNAME(context.Background(), host)
+ return DefaultResolver.LookupCNAME(context.Background(), host)
}
// LookupCNAME returns the canonical name for the given host.
// The returned service names are validated to be properly
// formatted presentation-format domain names.
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
- return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
+ return DefaultResolver.LookupSRV(context.Background(), service, proto, name)
}
// LookupSRV tries to resolve an SRV query of the given service,
// LookupMX uses context.Background internally; to specify the context, use
// Resolver.LookupMX.
func LookupMX(name string) ([]*MX, error) {
- return DefaultResolver.lookupMX(context.Background(), name)
+ return DefaultResolver.LookupMX(context.Background(), name)
}
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
// LookupNS uses context.Background internally; to specify the context, use
// Resolver.LookupNS.
func LookupNS(name string) ([]*NS, error) {
- return DefaultResolver.lookupNS(context.Background(), name)
+ return DefaultResolver.LookupNS(context.Background(), name)
}
// LookupNS returns the DNS NS records for the given domain name.
// LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address.
//
+// The returned names are validated to be properly formatted presentation-format
+// domain names.
+//
// When using the host C library resolver, at most one result will be
// returned. To bypass the host resolver, use a custom Resolver.
//
// LookupAddr uses context.Background internally; to specify the context, use
// Resolver.LookupAddr.
func LookupAddr(addr string) (names []string, err error) {
- return DefaultResolver.lookupAddr(context.Background(), addr)
+ return DefaultResolver.LookupAddr(context.Background(), addr)
}
// LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address.
//
-// The returned names are validated to be properly
-// formatted presentation-format domain names.
+// The returned names are validated to be properly formatted presentation-format
+// domain names.
func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
names, err := r.lookupAddr(ctx, addr)
if err != nil {
defer r.Close()
defer w.Close()
- c := make(chan bool)
+ const count = 10
+
+ c := make(chan bool, 1)
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
- var buf [10]byte
+ var buf [count]byte
r.SetReadDeadline(time.Now().Add(time.Minute))
c <- true
if _, err := r.Read(buf[:]); os.IsTimeout(err) {
r.Fd()
// The bug was that Fd would hang until Read timed out.
- // If the bug is fixed, then closing r here will cause
- // the Read to exit before the timeout expires.
+ // If the bug is fixed, then writing to w and closing r here
+ // will cause the Read to exit before the timeout expires.
+ w.Write(make([]byte, count))
r.Close()
}()
// high addresses if viewed as unsigned).
//
// On aix/ppc64, this offset allows to keep the heapAddrBits to
- // 48. Otherwize, it would be 60 in order to handle mmap addresses
+ // 48. Otherwise, it would be 60 in order to handle mmap addresses
// (in range 0x0a00000000000000 - 0x0afffffffffffff). But in this
// case, the memory reserved in (s *pageAlloc).init for chunks
// is causing important slowdowns.