Merge "[dev.cmdgo] all: merge master (9eee0ed) into dev.cmdgo" into dev.cmdgo

This commit is contained in:
Gerrit Code Review 2021-07-30 21:29:29 +00:00
commit 8e2ab05dd3
109 changed files with 1332 additions and 440 deletions

View file

@ -80,6 +80,7 @@ pkg net/url, method (Values) Has(string) bool
pkg reflect, func VisibleFields(Type) []StructField pkg reflect, func VisibleFields(Type) []StructField
pkg reflect, method (Method) IsExported() bool pkg reflect, method (Method) IsExported() bool
pkg reflect, method (StructField) IsExported() bool pkg reflect, method (StructField) IsExported() bool
pkg reflect, method (Value) CanConvert(Type) bool
pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle pkg runtime/cgo (darwin-amd64-cgo), func NewHandle(interface{}) Handle
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete() pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Delete()
pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{} pkg runtime/cgo (darwin-amd64-cgo), method (Handle) Value() interface{}

View file

@ -827,10 +827,6 @@ The other codes are <code>-&gt;</code> (arithmetic right shift),
<h3 id="arm64">ARM64</h3> <h3 id="arm64">ARM64</h3>
<p>
The ARM64 port is in an experimental state.
</p>
<p> <p>
<code>R18</code> is the "platform register", reserved on the Apple platform. <code>R18</code> is the "platform register", reserved on the Apple platform.
To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>. To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.

View file

@ -119,6 +119,17 @@ Do not send CLs removing the interior tags from such phrases.
stack frame pointers only on Linux, macOS, and iOS. stack frame pointers only on Linux, macOS, and iOS.
</p> </p>
<h3 id="loong64">loong64 GOARCH value reserved</h3>
<p><!-- CL 333909 -->
The main Go compiler does not yet support the LoongArch
architecture, but we've reserved the <code>GOARCH</code> value
"<code>loong64</code>".
This means that Go files named <code>*_loong64.go</code> will now
be <a href="/pkg/go/build/#hdr-Build_Constraints">ignored by Go
tools</a> except when that GOARCH value is being used.
</p>
<h2 id="tools">Tools</h2> <h2 id="tools">Tools</h2>
<h3 id="go-command">Go command</h3> <h3 id="go-command">Go command</h3>
@ -401,30 +412,37 @@ func Foo() bool {
<p><!-- golang.org/issue/40724 --> <p><!-- golang.org/issue/40724 -->
Go 1.17 implements a new way of passing function arguments and results using 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 registers instead of the stack.
Windows on the 64-bit x86 architecture (the <code>linux/amd64</code>, Benchmarks for a representative set of Go packages and programs show
<code>darwin/amd64</code>, <code>windows/amd64</code> ports). For a performance improvements of about 5%, and a typical reduction in
representative set of Go packages and programs, benchmarking has shown binary size of about 2%.
performance improvements of about 5%, and a typical reduction in binary size This is currently enabled for Linux, macOS, and Windows on the
of about 2%. 64-bit x86 architecture (the <code>linux/amd64</code>,
<code>darwin/amd64</code>, and <code>windows/amd64</code> ports).
</p> </p>
<p> <p>
This change does not affect the functionality of any safe Go code. It can affect This change does not affect the functionality of any safe Go code
code outside the <a href="/doc/go1compat">compatibility guidelines</a> with and is designed to have no impact on most assembly code.
minimal impact. To maintain compatibility with existing assembly functions, It may affect code that violates
adapter functions converting between the new register-based calling convention the <a href="/pkg/unsafe#Pointer"><code>unsafe.Pointer</code></a>
and the previous stack-based calling convention (also known as ABI wrappers) rules when accessing function arguments, or that depends on
are sometimes used. This is mostly invisible to users, except for assembly undocumented behavior involving comparing function code pointers.
functions that have their addresses taken in Go. Using <code>reflect.ValueOf(fn).Pointer()</code> To maintain compatibility with existing assembly functions, the
(or similar approaches such as via <code>unsafe.Pointer</code>) to get the address compiler generates adapter functions that convert between the new
of an assembly function will now return the address of the ABI wrapper. This is register-based calling convention and the previous stack-based
mostly harmless, except for special-purpose assembly code (such as accessing calling convention.
thread-local storage or requiring a special stack alignment). Assembly functions These adapters are typically invisible to users, except that taking
called indirectly from Go via <code>func</code> values will now be made through the address of a Go function in assembly code or taking the address
ABI wrappers, which may cause a very small performance overhead. Also, calling of an assembly function in Go code
Go functions from assembly may now go through ABI wrappers, with a very small using <code>reflect.ValueOf(fn).Pointer()</code>
performance overhead. or <code>unsafe.Pointer</code> will now return the address of the
adapter.
Code that depends on the value of these code pointers may no longer
behave as expected.
Adapters also may cause a very small performance overhead in two
cases: calling an assembly function indirectly from Go via
a <code>func</code> value, and calling Go functions from assembly.
</p> </p>
<p><!-- CL 304470 --> <p><!-- CL 304470 -->
@ -440,11 +458,14 @@ func Foo() bool {
</p> </p>
<p><!-- CL 283112, golang.org/issue/28727 --> <p><!-- CL 283112, golang.org/issue/28727 -->
Functions containing closures can now be inlined. One effect of this change is Functions containing closures can now be inlined.
that a function with a closure may actually produce a distinct closure function One effect of this change is that a function with a closure may
for each place that the function is inlined. Hence, this change could reveal produce a distinct closure code pointer for each place that the
bugs where Go functions are compared (incorrectly) by pointer value. Go function is inlined.
functions are by definition not comparable. Go function values are not directly comparable, but this change
could reveal bugs in code that uses <code>reflect</code>
or <code>unsafe.Pointer</code> to bypass this language restriction
and compare functions by code pointer.
</p> </p>
<h2 id="library">Core library</h2> <h2 id="library">Core library</h2>
@ -865,8 +886,8 @@ func Foo() bool {
<dd> <dd>
<p><!-- CL 272668 --> <p><!-- CL 272668 -->
The new method <a href="/pkg/net/#IP.IsPrivate"><code>IP.IsPrivate</code></a> reports whether an address is 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> a private IPv4 address according to <a href="https://datatracker.ietf.org/doc/rfc1918">RFC 1918</a>
or a local IPv6 address according <a href="http://tools.ietf.org/html/rfc4193">RFC 4193</a>. or a local IPv6 address according <a href="https://datatracker.ietf.org/doc/rfc4193">RFC 4193</a>.
</p> </p>
<p><!-- CL 301709 --> <p><!-- CL 301709 -->
@ -968,6 +989,18 @@ func Foo() bool {
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt> <dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
<dd> <dd>
<p><!-- CL 334669 -->
The new
<a href="/pkg/reflect/#Value.CanConvert"><code>Value.CanConvert</code></a>
method reports whether a value can be converted to a type.
This may be used to avoid a panic when converting a slice to an
array pointer type if the slice is too short.
Previously it was sufficient to use
<a href="/pkg/reflect/#Type.ConvertibleTo"><code>Type.ConvertibleTo</code></a>
for this, but the newly permitted conversion from slice to array
pointer type can panic even if the types are convertible.
</p>
<p><!-- CL 266197 --> <p><!-- CL 266197 -->
The new The new
<a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a> <a href="/pkg/reflect/#StructField.IsExported"><code>StructField.IsExported</code></a>
@ -1132,10 +1165,13 @@ func Foo() bool {
<p><!-- CL 293349 --> <p><!-- CL 293349 -->
The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and The new <a href="/pkg/time/#Time.UnixMilli"><code>Time.UnixMilli</code></a> and
<a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a> methods return the number of milliseconds and <a href="/pkg/time/#Time.UnixMicro"><code>Time.UnixMicro</code></a>
microseconds elapsed since January 1, 1970 UTC respectively.<br> methods return the number of milliseconds and microseconds elapsed since
The new <code>UnixMilli</code> and <code>UnixMicro</code> functions return local Time corresponding to given January 1, 1970 UTC respectively.
Unix time. <br />
The new <a href="/pkg/time/#UnixMilli"><code>UnixMilli</code></a> and
<a href="/pkg/time/#UnixMicro"><code>UnixMicro</code></a> functions
return the local <code>Time</code> corresponding to the given Unix time.
</p> </p>
<p><!-- CL 300996 --> <p><!-- CL 300996 -->

View file

@ -1,6 +1,6 @@
<!--{ <!--{
"Title": "The Go Programming Language Specification", "Title": "The Go Programming Language Specification",
"Subtitle": "Version of Jul 1, 2021", "Subtitle": "Version of Jul 26, 2021",
"Path": "/ref/spec" "Path": "/ref/spec"
}--> }-->
@ -490,8 +490,8 @@ After a backslash, certain single-character escapes represent special values:
\n U+000A line feed or newline \n U+000A line feed or newline
\r U+000D carriage return \r U+000D carriage return
\t U+0009 horizontal tab \t U+0009 horizontal tab
\v U+000b vertical tab \v U+000B vertical tab
\\ U+005c backslash \\ U+005C backslash
\' U+0027 single quote (valid escape only within rune literals) \' U+0027 single quote (valid escape only within rune literals)
\" U+0022 double quote (valid escape only within string literals) \" U+0022 double quote (valid escape only within string literals)
</pre> </pre>
@ -4334,7 +4334,10 @@ s4 := (*[4]byte)(s) // panics: len([4]byte) > len(s)
var t []string var t []string
t0 := (*[0]string)(t) // t0 == nil t0 := (*[0]string)(t) // t0 == nil
t1 := (*[1]string)(t) // panics: len([1]string) > len(s) t1 := (*[1]string)(t) // panics: len([1]string) > len(t)
u := make([]byte, 0)
u0 = (*[0]byte)(u) // u0 != nil
</pre> </pre>
<h3 id="Constant_expressions">Constant expressions</h3> <h3 id="Constant_expressions">Constant expressions</h3>

View file

@ -446,35 +446,20 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResul
return result return result
} }
// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields)
var parameterUpdateMu sync.Mutex
// FieldOffsetOf returns a concurrency-safe version of f.Offset
func FieldOffsetOf(f *types.Field) int64 {
parameterUpdateMu.Lock()
defer parameterUpdateMu.Unlock()
return f.Offset
}
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) { func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location. // Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
if !isReturn || len(a.Registers) == 0 { if !isReturn || len(a.Registers) == 0 {
// The type frame offset DOES NOT show effects of minimum frame size. // The type frame offset DOES NOT show effects of minimum frame size.
// Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set // Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set
parameterUpdateMu.Lock()
defer parameterUpdateMu.Unlock()
off := a.FrameOffset(result) off := a.FrameOffset(result)
fOffset := f.Offset fOffset := f.Offset
if fOffset == types.BOGUS_FUNARG_OFFSET { if fOffset == types.BOGUS_FUNARG_OFFSET {
// Set the Offset the first time. After that, we may recompute it, but it should never change. if setNname && f.Nname != nil {
f.Offset = off
if f.Nname != nil {
// always set it in this case.
f.Nname.(*ir.Name).SetFrameOffset(off) f.Nname.(*ir.Name).SetFrameOffset(off)
f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false) f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
} }
} else if fOffset != off { } else {
base.Fatalf("offset for %s at %s changed from %d to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset, off) base.Fatalf("field offset for %s at %s has been set to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset)
} }
} else { } else {
if setNname && f.Nname != nil { if setNname && f.Nname != nil {

View file

@ -148,7 +148,7 @@ func dumpdata() {
if reflectdata.ZeroSize > 0 { if reflectdata.ZeroSize > 0 {
zero := base.PkgLinksym("go.map", "zero", obj.ABI0) zero := base.PkgLinksym("go.map", "zero", obj.ABI0)
objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA) objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
zero.Set(obj.AttrContentAddressable, true) zero.Set(obj.AttrStatic, true)
} }
staticdata.WriteFuncSyms() staticdata.WriteFuncSyms()

View file

@ -669,7 +669,7 @@ var kinds = []int{
// tflag is documented in reflect/type.go. // tflag is documented in reflect/type.go.
// //
// tflag values must be kept in sync with copies in: // tflag values must be kept in sync with copies in:
// cmd/compile/internal/gc/reflect.go // cmd/compile/internal/reflectdata/reflect.go
// cmd/link/internal/ld/decodesym.go // cmd/link/internal/ld/decodesym.go
// reflect/type.go // reflect/type.go
// runtime/type.go // runtime/type.go

View file

@ -1296,7 +1296,7 @@ func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrument
if f.Sym.IsBlank() { if f.Sym.IsBlank() {
continue continue
} }
offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr) offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
s.instrumentFields(f.Type, offptr, kind) s.instrumentFields(f.Type, offptr, kind)
} }
} }
@ -5053,19 +5053,23 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
ft := fn.Type() ft := fn.Type()
off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset. off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset.
args := n.Args args := n.Args
i0 := 0
// Set receiver (for interface calls). Always a pointer. // Set receiver (for interface calls). Always a pointer.
if rcvr != nil { if rcvr != nil {
p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr) p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
s.store(types.Types[types.TUINTPTR], p, rcvr) s.store(types.Types[types.TUINTPTR], p, rcvr)
i0 = 1
} }
// Set receiver (for method calls). // Set receiver (for method calls).
if n.Op() == ir.OCALLMETH { if n.Op() == ir.OCALLMETH {
base.Fatalf("OCALLMETH missed by walkCall") base.Fatalf("OCALLMETH missed by walkCall")
} }
// Set other args. // Set other args.
for _, f := range ft.Params().Fields().Slice() { // This code is only used when RegabiDefer is not enabled, and arguments are always
s.storeArgWithBase(args[0], f.Type, addr, off+abi.FieldOffsetOf(f)) // passed on stack.
for i, f := range ft.Params().Fields().Slice() {
s.storeArgWithBase(args[0], f.Type, addr, off+params.InParam(i+i0).FrameOffset(params))
args = args[1:] args = args[1:]
} }
@ -5078,7 +5082,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
if stksize < int64(types.PtrSize) { if stksize < int64(types.PtrSize) {
// We need room for both the call to deferprocStack and the call to // We need room for both the call to deferprocStack and the call to
// the deferred function. // the deferred function.
// TODO(register args) Revisit this if/when we pass args in registers.
stksize = int64(types.PtrSize) stksize = int64(types.PtrSize)
} }
call.AuxInt = stksize call.AuxInt = stksize
@ -6598,6 +6601,7 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI)) x := base.Ctxt.Lookup(fmt.Sprintf("%s.arginfo%d", f.LSym.Name, f.ABI))
PtrSize := int64(types.PtrSize) PtrSize := int64(types.PtrSize)
uintptrTyp := types.Types[types.TUINTPTR]
isAggregate := func(t *types.Type) bool { isAggregate := func(t *types.Type) bool {
return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice() return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice()
@ -6641,12 +6645,8 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
n := 0 n := 0
writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) } writebyte := func(o uint8) { wOff = objw.Uint8(x, wOff, o) }
// Write one non-aggrgate arg/field/element if there is room. // Write one non-aggrgate arg/field/element.
// Returns whether to continue. write1 := func(sz, offset int64) {
write1 := func(sz, offset int64) bool {
if n >= limit {
return false
}
if offset >= _special { if offset >= _special {
writebyte(_offsetTooLarge) writebyte(_offsetTooLarge)
} else { } else {
@ -6654,7 +6654,6 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
writebyte(uint8(sz)) writebyte(uint8(sz))
} }
n++ n++
return true
} }
// Visit t recursively and write it out. // Visit t recursively and write it out.
@ -6662,10 +6661,12 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
var visitType func(baseOffset int64, t *types.Type, depth int) bool var visitType func(baseOffset int64, t *types.Type, depth int) bool
visitType = func(baseOffset int64, t *types.Type, depth int) bool { visitType = func(baseOffset int64, t *types.Type, depth int) bool {
if n >= limit { if n >= limit {
writebyte(_dotdotdot)
return false return false
} }
if !isAggregate(t) { if !isAggregate(t) {
return write1(t.Size(), baseOffset) write1(t.Size(), baseOffset)
return true
} }
writebyte(_startAgg) writebyte(_startAgg)
depth++ depth++
@ -6675,58 +6676,47 @@ func EmitArgInfo(f *ir.Func, abiInfo *abi.ABIParamResultInfo) *obj.LSym {
n++ n++
return true return true
} }
var r bool
switch { switch {
case t.IsInterface(), t.IsString(): case t.IsInterface(), t.IsString():
r = write1(PtrSize, baseOffset) && _ = visitType(baseOffset, uintptrTyp, depth) &&
write1(PtrSize, baseOffset+PtrSize) visitType(baseOffset+PtrSize, uintptrTyp, depth)
case t.IsSlice(): case t.IsSlice():
r = write1(PtrSize, baseOffset) && _ = visitType(baseOffset, uintptrTyp, depth) &&
write1(PtrSize, baseOffset+PtrSize) && visitType(baseOffset+PtrSize, uintptrTyp, depth) &&
write1(PtrSize, baseOffset+PtrSize*2) visitType(baseOffset+PtrSize*2, uintptrTyp, depth)
case t.IsComplex(): case t.IsComplex():
r = write1(t.Size()/2, baseOffset) && _ = visitType(baseOffset, types.FloatForComplex(t), depth) &&
write1(t.Size()/2, baseOffset+t.Size()/2) visitType(baseOffset+t.Size()/2, types.FloatForComplex(t), depth)
case t.IsArray(): case t.IsArray():
r = true
if t.NumElem() == 0 { if t.NumElem() == 0 {
n++ // {} counts as a component n++ // {} counts as a component
break break
} }
for i := int64(0); i < t.NumElem(); i++ { for i := int64(0); i < t.NumElem(); i++ {
if !visitType(baseOffset, t.Elem(), depth) { if !visitType(baseOffset, t.Elem(), depth) {
r = false
break break
} }
baseOffset += t.Elem().Size() baseOffset += t.Elem().Size()
} }
case t.IsStruct(): case t.IsStruct():
r = true
if t.NumFields() == 0 { if t.NumFields() == 0 {
n++ // {} counts as a component n++ // {} counts as a component
break break
} }
for _, field := range t.Fields().Slice() { for _, field := range t.Fields().Slice() {
if !visitType(baseOffset+field.Offset, field.Type, depth) { if !visitType(baseOffset+field.Offset, field.Type, depth) {
r = false
break break
} }
} }
} }
if !r {
writebyte(_dotdotdot)
}
writebyte(_endAgg) writebyte(_endAgg)
return r return true
} }
c := true
for _, a := range abiInfo.InParams() { for _, a := range abiInfo.InParams() {
if !c { if !visitType(a.FrameOffset(abiInfo), a.Type, 0) {
writebyte(_dotdotdot)
break break
} }
c = visitType(a.FrameOffset(abiInfo), a.Type, 0)
} }
writebyte(_endSeq) writebyte(_endSeq)
if wOff > maxLen { if wOff > maxLen {

View file

@ -106,7 +106,17 @@ func Export(n *ir.Name) {
// Redeclared emits a diagnostic about symbol s being redeclared at pos. // Redeclared emits a diagnostic about symbol s being redeclared at pos.
func Redeclared(pos src.XPos, s *types.Sym, where string) { func Redeclared(pos src.XPos, s *types.Sym, where string) {
if !s.Lastlineno.IsKnown() { if !s.Lastlineno.IsKnown() {
pkgName := DotImportRefs[s.Def.(*ir.Ident)] var pkgName *ir.PkgName
if s.Def == nil {
for id, pkg := range DotImportRefs {
if id.Sym().Name == s.Name {
pkgName = pkg
break
}
}
} else {
pkgName = DotImportRefs[s.Def.(*ir.Ident)]
}
base.ErrorfAt(pos, "%v redeclared %s\n"+ base.ErrorfAt(pos, "%v redeclared %s\n"+
"\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path) "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
} else { } else {

View file

@ -1540,7 +1540,7 @@ func (r *importReader) exprsOrNil() (a, b ir.Node) {
func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr { func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
if go117ExportTypes { if go117ExportTypes {
// These should all be encoded as direct ops, not OCALL. // These should all be encoded as direct ops, not OCALL.
base.Fatalf("builtinCall should not be invoked when types are included in inport/export") base.Fatalf("builtinCall should not be invoked when types are included in import/export")
} }
return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil) return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
} }

View file

@ -109,14 +109,18 @@ func sconv(s *Sym, verb rune, mode fmtMode) string {
return "<S>" return "<S>"
} }
if s.Name == "_" { q := pkgqual(s.Pkg, verb, mode)
return "_" if q == "" {
return s.Name
} }
buf := fmtBufferPool.Get().(*bytes.Buffer) buf := fmtBufferPool.Get().(*bytes.Buffer)
buf.Reset() buf.Reset()
defer fmtBufferPool.Put(buf) defer fmtBufferPool.Put(buf)
symfmt(buf, s, verb, mode) buf.WriteString(q)
buf.WriteByte('.')
buf.WriteString(s.Name)
return InternString(buf.Bytes()) return InternString(buf.Bytes())
} }
@ -128,56 +132,49 @@ func sconv2(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
b.WriteString("<S>") b.WriteString("<S>")
return return
} }
if s.Name == "_" {
b.WriteString("_")
return
}
symfmt(b, s, verb, mode) symfmt(b, s, verb, mode)
} }
func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) { func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
if q := pkgqual(s.Pkg, verb, mode); q != "" {
b.WriteString(q)
b.WriteByte('.')
}
b.WriteString(s.Name)
}
// pkgqual returns the qualifier that should be used for printing
// symbols from the given package in the given mode.
// If it returns the empty string, no qualification is needed.
func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
if verb != 'S' { if verb != 'S' {
switch mode { switch mode {
case fmtGo: // This is for the user case fmtGo: // This is for the user
if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg { if pkg == BuiltinPkg || pkg == LocalPkg {
b.WriteString(s.Name) return ""
return
} }
// If the name was used by multiple packages, display the full path, // If the name was used by multiple packages, display the full path,
if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 { if pkg.Name != "" && NumImport[pkg.Name] > 1 {
fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name) return strconv.Quote(pkg.Path)
return
} }
b.WriteString(s.Pkg.Name) return pkg.Name
b.WriteByte('.')
b.WriteString(s.Name)
return
case fmtDebug: case fmtDebug:
b.WriteString(s.Pkg.Name) return pkg.Name
b.WriteByte('.')
b.WriteString(s.Name)
return
case fmtTypeIDName: case fmtTypeIDName:
// dcommontype, typehash // dcommontype, typehash
b.WriteString(s.Pkg.Name) return pkg.Name
b.WriteByte('.')
b.WriteString(s.Name)
return
case fmtTypeID: case fmtTypeID:
// (methodsym), typesym, weaksym // (methodsym), typesym, weaksym
b.WriteString(s.Pkg.Prefix) return pkg.Prefix
b.WriteByte('.')
b.WriteString(s.Name)
return
} }
} }
b.WriteString(s.Name) return ""
} }
// Type // Type

View file

@ -1087,7 +1087,7 @@
// //
// Usage: // Usage:
// //
// go mod edit [editing flags] [go.mod] // go mod edit [editing flags] [-fmt|-print|-json] [go.mod]
// //
// Edit provides a command-line interface for editing go.mod, // Edit provides a command-line interface for editing go.mod,
// for use primarily by tools or scripts. It reads only go.mod; // for use primarily by tools or scripts. It reads only go.mod;
@ -1202,7 +1202,7 @@
// and one of its requirements. Each module is identified as a string of the form // and one of its requirements. Each module is identified as a string of the form
// path@version, except for the main module, which has no @version suffix. // path@version, except for the main module, which has no @version suffix.
// //
// The -go flag causes graph to report the module graph as loaded by by the // The -go flag causes graph to report the module graph as loaded by the
// given Go version, instead of the version indicated by the 'go' directive // given Go version, instead of the version indicated by the 'go' directive
// in the go.mod file. // in the go.mod file.
// //
@ -1213,7 +1213,7 @@
// //
// Usage: // Usage:
// //
// go mod init [module] // go mod init [module-path]
// //
// Init initializes and writes a new go.mod file in the current directory, in // Init initializes and writes a new go.mod file in the current directory, in
// effect creating a new module rooted at the current directory. The go.mod file // effect creating a new module rooted at the current directory. The go.mod file

View file

@ -2848,3 +2848,35 @@ func TestExecInDeletedDir(t *testing.T) {
// `go version` should not fail // `go version` should not fail
tg.run("version") tg.run("version")
} }
// A missing C compiler should not force the net package to be stale.
// Issue 47215.
func TestMissingCC(t *testing.T) {
if !canCgo {
t.Skip("test is only meaningful on systems with cgo")
}
cc := os.Getenv("CC")
if cc == "" {
cc = "gcc"
}
if filepath.IsAbs(cc) {
t.Skipf(`"CC" (%s) is an absolute path`, cc)
}
_, err := exec.LookPath(cc)
if err != nil {
t.Skipf(`"CC" (%s) not on PATH`, cc)
}
tg := testgo(t)
defer tg.cleanup()
netStale, _ := tg.isStale("net")
if netStale {
t.Skip(`skipping test because "net" package is currently stale`)
}
tg.setenv("PATH", "") // No C compiler on PATH.
netStale, _ = tg.isStale("net")
if netStale {
t.Error(`clearing "PATH" causes "net" to be stale`)
}
}

View file

@ -11,7 +11,6 @@ import (
"io/fs" "io/fs"
"os" "os"
"cmd/go/internal/fsys"
"cmd/go/internal/lockedfile/internal/filelock" "cmd/go/internal/lockedfile/internal/filelock"
) )
@ -21,7 +20,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
// calls for Linux and Windows anyway, so it's simpler to use that approach // calls for Linux and Windows anyway, so it's simpler to use that approach
// consistently. // consistently.
f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm) f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -13,8 +13,6 @@ import (
"os" "os"
"strings" "strings"
"time" "time"
"cmd/go/internal/fsys"
) )
// Opening an exclusive-use file returns an error. // Opening an exclusive-use file returns an error.
@ -59,7 +57,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
// If the file was unpacked or created by some other program, it might not // If the file was unpacked or created by some other program, it might not
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we // have the ModeExclusive bit set. Set it before we call OpenFile, so that we
// can be confident that a successful OpenFile implies exclusive use. // can be confident that a successful OpenFile implies exclusive use.
if fi, err := fsys.Stat(name); err == nil { if fi, err := os.Stat(name); err == nil {
if fi.Mode()&fs.ModeExclusive == 0 { if fi.Mode()&fs.ModeExclusive == 0 {
if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
return nil, err return nil, err
@ -72,7 +70,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
nextSleep := 1 * time.Millisecond nextSleep := 1 * time.Millisecond
const maxSleep = 500 * time.Millisecond const maxSleep = 500 * time.Millisecond
for { for {
f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive) f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive)
if err == nil { if err == nil {
return f, nil return f, nil
} }

View file

@ -25,7 +25,7 @@ import (
) )
var cmdEdit = &base.Command{ var cmdEdit = &base.Command{
UsageLine: "go mod edit [editing flags] [go.mod]", UsageLine: "go mod edit [editing flags] [-fmt|-print|-json] [go.mod]",
Short: "edit go.mod from tools or scripts", Short: "edit go.mod from tools or scripts",
Long: ` Long: `
Edit provides a command-line interface for editing go.mod, Edit provides a command-line interface for editing go.mod,

View file

@ -26,7 +26,7 @@ in text form. Each line in the output has two space-separated fields: a module
and one of its requirements. Each module is identified as a string of the form and one of its requirements. Each module is identified as a string of the form
path@version, except for the main module, which has no @version suffix. path@version, except for the main module, which has no @version suffix.
The -go flag causes graph to report the module graph as loaded by by the The -go flag causes graph to report the module graph as loaded by the
given Go version, instead of the version indicated by the 'go' directive given Go version, instead of the version indicated by the 'go' directive
in the go.mod file. in the go.mod file.

View file

@ -13,7 +13,7 @@ import (
) )
var cmdInit = &base.Command{ var cmdInit = &base.Command{
UsageLine: "go mod init [module]", UsageLine: "go mod init [module-path]",
Short: "initialize new module in current directory", Short: "initialize new module in current directory",
Long: ` Long: `
Init initializes and writes a new go.mod file in the current directory, in Init initializes and writes a new go.mod file in the current directory, in

View file

@ -8,7 +8,6 @@ import (
"archive/zip" "archive/zip"
"bytes" "bytes"
"flag" "flag"
"fmt"
"internal/testenv" "internal/testenv"
"io" "io"
"io/fs" "io/fs"
@ -47,12 +46,6 @@ var altRepos = []string{
var localGitRepo string var localGitRepo string
func testMain(m *testing.M) int { func testMain(m *testing.M) int {
if _, err := exec.LookPath("git"); err != nil {
fmt.Fprintln(os.Stderr, "skipping because git binary not found")
fmt.Println("PASS")
return 0
}
dir, err := os.MkdirTemp("", "gitrepo-test-") dir, err := os.MkdirTemp("", "gitrepo-test-")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -60,6 +53,7 @@ func testMain(m *testing.M) int {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
if testenv.HasExternalNetwork() && testenv.HasExec() { if testenv.HasExternalNetwork() && testenv.HasExec() {
if _, err := exec.LookPath("git"); err == nil {
// Clone gitrepo1 into a local directory. // Clone gitrepo1 into a local directory.
// If we use a file:// URL to access the local directory, // If we use a file:// URL to access the local directory,
// then git starts up all the usual protocol machinery, // then git starts up all the usual protocol machinery,
@ -72,11 +66,12 @@ func testMain(m *testing.M) int {
log.Fatal(err) log.Fatal(err)
} }
} }
}
return m.Run() return m.Run()
} }
func testRepo(remote string) (Repo, error) { func testRepo(t *testing.T, remote string) (Repo, error) {
if remote == "localGitRepo" { if remote == "localGitRepo" {
// Convert absolute path to file URL. LocalGitRepo will not accept // Convert absolute path to file URL. LocalGitRepo will not accept
// Windows absolute paths because they look like a host:path remote. // Windows absolute paths because they look like a host:path remote.
@ -87,15 +82,17 @@ func testRepo(remote string) (Repo, error) {
} else { } else {
url = "file:///" + filepath.ToSlash(localGitRepo) url = "file:///" + filepath.ToSlash(localGitRepo)
} }
testenv.MustHaveExecPath(t, "git")
return LocalGitRepo(url) return LocalGitRepo(url)
} }
kind := "git" vcs := "git"
for _, k := range []string{"hg"} { for _, k := range []string{"hg"} {
if strings.Contains(remote, "/"+k+"/") { if strings.Contains(remote, "/"+k+"/") {
kind = k vcs = k
} }
} }
return NewRepo(kind, remote) testenv.MustHaveExecPath(t, vcs)
return NewRepo(vcs, remote)
} }
var tagsTests = []struct { var tagsTests = []struct {
@ -116,7 +113,7 @@ func TestTags(t *testing.T) {
for _, tt := range tagsTests { for _, tt := range tagsTests {
f := func(t *testing.T) { f := func(t *testing.T) {
r, err := testRepo(tt.repo) r, err := testRepo(t, tt.repo)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -168,7 +165,7 @@ func TestLatest(t *testing.T) {
for _, tt := range latestTests { for _, tt := range latestTests {
f := func(t *testing.T) { f := func(t *testing.T) {
r, err := testRepo(tt.repo) r, err := testRepo(t, tt.repo)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -221,7 +218,7 @@ func TestReadFile(t *testing.T) {
for _, tt := range readFileTests { for _, tt := range readFileTests {
f := func(t *testing.T) { f := func(t *testing.T) {
r, err := testRepo(tt.repo) r, err := testRepo(t, tt.repo)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -412,7 +409,7 @@ func TestReadZip(t *testing.T) {
for _, tt := range readZipTests { for _, tt := range readZipTests {
f := func(t *testing.T) { f := func(t *testing.T) {
r, err := testRepo(tt.repo) r, err := testRepo(t, tt.repo)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -581,7 +578,7 @@ func TestStat(t *testing.T) {
for _, tt := range statTests { for _, tt := range statTests {
f := func(t *testing.T) { f := func(t *testing.T) {
r, err := testRepo(tt.repo) r, err := testRepo(t, tt.repo)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -864,22 +864,25 @@ func (r *codeRepo) GoMod(version string) (data []byte, err error) {
data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod) data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return r.legacyGoMod(rev, dir), nil return LegacyGoMod(r.modPath), nil
} }
return nil, err return nil, err
} }
return data, nil return data, nil
} }
func (r *codeRepo) legacyGoMod(rev, dir string) []byte { // LegacyGoMod generates a fake go.mod file for a module that doesn't have one.
// The go.mod file contains a module directive and nothing else: no go version,
// no requirements.
//
// We used to try to build a go.mod reflecting pre-existing // We used to try to build a go.mod reflecting pre-existing
// package management metadata files, but the conversion // package management metadata files, but the conversion
// was inherently imperfect (because those files don't have // was inherently imperfect (because those files don't have
// exactly the same semantics as go.mod) and, when done // exactly the same semantics as go.mod) and, when done
// for dependencies in the middle of a build, impossible to // for dependencies in the middle of a build, impossible to
// correct. So we stopped. // correct. So we stopped.
// Return a fake go.mod that simply declares the module path. func LegacyGoMod(modPath string) []byte {
return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(r.modPath))) return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(modPath)))
} }
func (r *codeRepo) modPrefix(rev string) string { func (r *codeRepo) modPrefix(rev string) string {

View file

@ -22,6 +22,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/lockedfile" "cmd/go/internal/lockedfile"
"cmd/go/internal/par" "cmd/go/internal/par"
"cmd/go/internal/robustio" "cmd/go/internal/robustio"
@ -416,7 +417,18 @@ func initGoSum() (bool, error) {
goSum.m = make(map[module.Version][]string) goSum.m = make(map[module.Version][]string)
goSum.status = make(map[modSum]modSumStatus) goSum.status = make(map[modSum]modSumStatus)
data, err := lockedfile.Read(GoSumFile) var (
data []byte
err error
)
if actualSumFile, ok := fsys.OverlayPath(GoSumFile); ok {
// Don't lock go.sum if it's part of the overlay.
// On Plan 9, locking requires chmod, and we don't want to modify any file
// in the overlay. See #44700.
data, err = os.ReadFile(actualSumFile)
} else {
data, err = lockedfile.Read(GoSumFile)
}
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return false, err return false, err
} }
@ -718,6 +730,9 @@ Outer:
if readonly { if readonly {
return ErrGoSumDirty return ErrGoSumDirty
} }
if _, ok := fsys.OverlayPath(GoSumFile); ok {
base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
}
// Make a best-effort attempt to acquire the side lock, only to exclude // Make a best-effort attempt to acquire the side lock, only to exclude
// previous versions of the 'go' command from making simultaneous edits. // previous versions of the 'go' command from making simultaneous edits.

View file

@ -191,7 +191,7 @@ type Root int
const ( const (
// AutoRoot is the default for most commands. modload.Init will look for // AutoRoot is the default for most commands. modload.Init will look for
// a go.mod file in the current directory or any parent. If none is found, // a go.mod file in the current directory or any parent. If none is found,
// modules may be disabled (GO111MODULE=on) or commands may run in a // modules may be disabled (GO111MODULE=auto) or commands may run in a
// limited module mode. // limited module mode.
AutoRoot Root = iota AutoRoot Root = iota
@ -1364,6 +1364,13 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
} }
return return
} }
gomod := ModFilePath()
if _, ok := fsys.OverlayPath(gomod); ok {
if dirty {
base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay")
}
return
}
new, err := modFile.Format() new, err := modFile.Format()
if err != nil { if err != nil {

View file

@ -715,20 +715,6 @@ func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path s
return ".", module.Version{} return ".", module.Version{}
} }
// TargetPackages returns the list of packages in the target (top-level) module
// matching pattern, which may be relative to the working directory, under all
// build tag settings.
func TargetPackages(ctx context.Context, pattern string) *search.Match {
// TargetPackages is relative to the main module, so ensure that the main
// module is a thing that can contain packages.
LoadModFile(ctx) // Sets Target.
ModRoot() // Emits an error if Target cannot contain packages.
m := search.NewMatch(pattern)
matchPackages(ctx, m, imports.AnyTags(), omitStd, MainModules.Versions())
return m
}
// ImportMap returns the actual package import path // ImportMap returns the actual package import path
// for an import path found in source code. // for an import path found in source code.
// If the given import path does not appear in the source code // If the given import path does not appear in the source code
@ -760,29 +746,6 @@ func PackageModule(path string) module.Version {
return pkg.mod return pkg.mod
} }
// PackageImports returns the imports for the package named by the import path.
// Test imports will be returned as well if tests were loaded for the package
// (i.e., if "all" was loaded or if LoadTests was set and the path was matched
// by a command line argument). PackageImports will return nil for
// unknown package paths.
func PackageImports(path string) (imports, testImports []string) {
pkg, ok := loaded.pkgCache.Get(path).(*loadPkg)
if !ok {
return nil, nil
}
imports = make([]string, len(pkg.imports))
for i, p := range pkg.imports {
imports[i] = p.path
}
if pkg.test != nil {
testImports = make([]string, len(pkg.test.imports))
for i, p := range pkg.test.imports {
testImports[i] = p.path
}
}
return imports, testImports
}
// Lookup returns the source directory, import path, and any loading error for // Lookup returns the source directory, import path, and any loading error for
// the package at path as imported from the package in parentDir. // the package at path as imported from the package in parentDir.
// Lookup requires that one of the Load functions in this package has already // Lookup requires that one of the Load functions in this package has already
@ -1883,7 +1846,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion) fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", ld.TidyCompatibleVersion, goFlag, ld.GoVersion)
// TODO(#46141): Populate the linked wiki page. // TODO(#46141): Populate the linked wiki page.
fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/wiki/PruningModules\n") fmt.Fprintf(os.Stderr, "For other options, see:\n\thttps://golang.org/doc/modules/pruning\n")
} }
mg, err := rs.Graph(ctx) mg, err := rs.Graph(ctx)

View file

@ -8,6 +8,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
@ -15,6 +16,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/lockedfile" "cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch" "cmd/go/internal/modfetch"
"cmd/go/internal/par" "cmd/go/internal/par"
@ -614,39 +616,14 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
} }
c := rawGoModSummaryCache.Do(m, func() interface{} { c := rawGoModSummaryCache.Do(m, func() interface{} {
summary := new(modFileSummary) summary := new(modFileSummary)
var f *modfile.File name, data, err := rawGoModData(m)
if m.Version == "" {
// m is a replacement module with only a file path.
dir := m.Path
if !filepath.IsAbs(dir) {
dir = filepath.Join(ModRoot(), dir)
}
gomod := filepath.Join(dir, "go.mod")
data, err := lockedfile.Read(gomod)
if err != nil {
return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))}
}
f, err = modfile.ParseLax(gomod, data, nil)
if err != nil {
return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(gomod), err))}
}
} else {
if !semver.IsValid(m.Version) {
// Disallow the broader queries supported by fetch.Lookup.
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
}
data, err := modfetch.GoMod(m.Path, m.Version)
if err != nil { if err != nil {
return cached{nil, err} return cached{nil, err}
} }
f, err = modfile.ParseLax("go.mod", data, nil) f, err := modfile.ParseLax(name, data, nil)
if err != nil { if err != nil {
return cached{nil, module.VersionError(m, fmt.Errorf("parsing go.mod: %v", err))} return cached{nil, module.VersionError(m, fmt.Errorf("parsing %s: %v", base.ShortPath(name), err))}
} }
}
if f.Module != nil { if f.Module != nil {
summary.module = f.Module.Mod summary.module = f.Module.Mod
summary.deprecated = f.Module.Deprecated summary.deprecated = f.Module.Deprecated
@ -682,6 +659,43 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result
// rawGoModData returns the content of the go.mod file for module m, ignoring
// all replacements that may apply to m.
//
// rawGoModData cannot be used on the Target module.
//
// Unlike rawGoModSummary, rawGoModData does not cache its results in memory.
// Use rawGoModSummary instead unless you specifically need these bytes.
func rawGoModData(m module.Version) (name string, data []byte, err error) {
if m.Version == "" {
// m is a replacement module with only a file path.
dir := m.Path
if !filepath.IsAbs(dir) {
dir = filepath.Join(ModRoot(), dir)
}
name = filepath.Join(dir, "go.mod")
if gomodActual, ok := fsys.OverlayPath(name); ok {
// Don't lock go.mod if it's part of the overlay.
// On Plan 9, locking requires chmod, and we don't want to modify any file
// in the overlay. See #44700.
data, err = os.ReadFile(gomodActual)
} else {
data, err = lockedfile.Read(gomodActual)
}
if err != nil {
return "", nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(name), err))
}
} else {
if !semver.IsValid(m.Version) {
// Disallow the broader queries supported by fetch.Lookup.
base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", m.Path, m.Version)
}
name = "go.mod"
data, err = modfetch.GoMod(m.Path, m.Version)
}
return name, data, err
}
// queryLatestVersionIgnoringRetractions looks up the latest version of the // queryLatestVersionIgnoringRetractions looks up the latest version of the
// module with the given path without considering retracted or excluded // module with the given path without considering retracted or excluded
// versions. // versions.

View file

@ -5,13 +5,13 @@
package modload package modload
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/fs" "io/fs"
"os" "os"
pathpkg "path" pathpkg "path"
"path/filepath"
"sort" "sort"
"strings" "strings"
"sync" "sync"
@ -933,8 +933,8 @@ func (e *PackageNotInModuleError) ImportPath() string {
return "" return ""
} }
// ModuleHasRootPackage returns whether module m contains a package m.Path. // moduleHasRootPackage returns whether module m contains a package m.Path.
func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) { func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
needSum := false needSum := false
root, isLocal, err := fetch(ctx, m, needSum) root, isLocal, err := fetch(ctx, m, needSum)
if err != nil { if err != nil {
@ -944,14 +944,32 @@ func ModuleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
return ok, err return ok, err
} }
func versionHasGoMod(ctx context.Context, m module.Version) (bool, error) { // versionHasGoMod returns whether a version has a go.mod file.
needSum := false //
root, _, err := fetch(ctx, m, needSum) // versionHasGoMod fetches the go.mod file (possibly a fake) and true if it
// contains anything other than a module directive with the same path. When a
// module does not have a real go.mod file, the go command acts as if it had one
// that only contained a module directive. Normal go.mod files created after
// 1.12 at least have a go directive.
//
// This function is a heuristic, since it's possible to commit a file that would
// pass this test. However, we only need a heurstic for determining whether
// +incompatible versions may be "latest", which is what this function is used
// for.
//
// This heuristic is useful for two reasons: first, when using a proxy,
// this lets us fetch from the .mod endpoint which is much faster than the .zip
// endpoint. The .mod file is used anyway, even if the .zip file contains a
// go.mod with different content. Second, if we don't fetch the .zip, then
// we don't need to verify it in go.sum. This makes 'go list -m -u' faster
// and simpler.
func versionHasGoMod(_ context.Context, m module.Version) (bool, error) {
_, data, err := rawGoModData(m)
if err != nil { if err != nil {
return false, err return false, err
} }
fi, err := os.Stat(filepath.Join(root, "go.mod")) isFake := bytes.Equal(data, modfetch.LegacyGoMod(m.Path))
return err == nil && !fi.IsDir(), nil return !isFake, nil
} }
// A versionRepo is a subset of modfetch.Repo that can report information about // A versionRepo is a subset of modfetch.Repo that can report information about

View file

@ -252,9 +252,16 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
ccExe := b.ccExe() ccExe := b.ccExe()
fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags) fmt.Fprintf(h, "CC=%q %q %q %q\n", ccExe, cppflags, cflags, ldflags)
// Include the C compiler tool ID so that if the C
// compiler changes we rebuild the package.
// But don't do that for standard library packages like net,
// so that the prebuilt .a files from a Go binary install
// don't need to be rebuilt with the local compiler.
if !p.Standard {
if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil { if ccID, err := b.gccToolID(ccExe[0], "c"); err == nil {
fmt.Fprintf(h, "CC ID=%q\n", ccID) fmt.Fprintf(h, "CC ID=%q\n", ccID)
} }
}
if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 { if len(p.CXXFiles)+len(p.SwigCXXFiles) > 0 {
cxxExe := b.cxxExe() cxxExe := b.cxxExe()
fmt.Fprintf(h, "CXX=%q %q\n", cxxExe, cxxflags) fmt.Fprintf(h, "CXX=%q %q\n", cxxExe, cxxflags)

View file

@ -21,7 +21,7 @@ go list -deps -overlay overlay.json .
cd $WORK/gopath/src/get-doesnt-add-dep cd $WORK/gopath/src/get-doesnt-add-dep
cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
! go get -d -overlay overlay.json . ! go get -d -overlay overlay.json .
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
# Content of overlaid go.sum is used. # Content of overlaid go.sum is used.
@ -41,10 +41,10 @@ go mod verify -overlay overlay.json
# attempting to update the file # attempting to update the file
cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
! go get -d -overlay overlay.json . ! go get -d -overlay overlay.json .
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
! go mod tidy -overlay overlay.json ! go mod tidy -overlay overlay.json
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
# -overlay works with -modfile. # -overlay works with -modfile.
@ -56,7 +56,7 @@ go list -modfile=alternate.mod -overlay overlay.json .
stdout 'found.the/module' stdout 'found.the/module'
# Even with -modfile, overlaid files can't be opened for write. # Even with -modfile, overlaid files can't be opened for write.
! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote ! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
# Carving out a module by adding an overlaid go.mod file # Carving out a module by adding an overlaid go.mod file
cd $WORK/gopath/src/carve cd $WORK/gopath/src/carve
@ -78,7 +78,7 @@ go list -overlay overlay.json all
stdout ^carve2/nomod$ stdout ^carve2/nomod$
# Editing go.mod file fails because overlay is read only # Editing go.mod file fails because overlay is read only
! go get -overlay overlay.json -d rsc.io/quote ! go get -overlay overlay.json -d rsc.io/quote
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod
# Editing go.mod file succeeds because we use -modfile to redirect to same file # Editing go.mod file succeeds because we use -modfile to redirect to same file
go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote

View file

@ -23,7 +23,7 @@ cp go.mod go.mod.orig
stderr '^example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n' stderr '^example\.com/m imports\n\texample\.net/indirect imports\n\texample\.net/ambiguous/nested/pkg loaded from example\.net/ambiguous/nested@v0\.1\.0,\n\tbut go 1.16 would fail to locate it:\n\tambiguous import: found package example\.net/ambiguous/nested/pkg in multiple modules:\n\texample\.net/ambiguous v0.1.0 \(.*\)\n\texample\.net/ambiguous/nested v0.1.0 \(.*\)\n\n'
stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' stderr '\n\nTo proceed despite packages unresolved in go 1\.16:\n\tgo mod tidy -e\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
cmp go.mod go.mod.orig cmp go.mod go.mod.orig

View file

@ -19,7 +19,7 @@ cp go.mod go.mod.orig
stderr '^example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n' stderr '^example\.com/m imports\n\texample\.net/deleted loaded from example\.net/deleted@v0\.1\.0,\n\tbut go 1\.16 would fail to locate it in example\.net/deleted@v0\.2\.0\n\n'
stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' stderr '\n\nTo upgrade to the versions selected by go 1.16, leaving some packages unresolved:\n\tgo mod tidy -e -go=1\.16 && go mod tidy -e -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1\.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
# The suggested 'go mod tidy -e' command should proceed anyway. # The suggested 'go mod tidy -e' command should proceed anyway.

View file

@ -33,7 +33,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
cp go.mod go.mod.orig cp go.mod go.mod.orig
! go mod tidy ! go mod tidy
stderr '^example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' stderr '^example\.com/m imports\n\texample\.net/lazy tested by\n\texample\.net/lazy.test imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n'
stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
cmp go.mod go.mod.orig cmp go.mod go.mod.orig

View file

@ -33,7 +33,7 @@ env MODFMT='{{with .Module}}{{.Path}} {{.Version}}{{end}}'
cp go.mod go.mod.orig cp go.mod go.mod.orig
! go mod tidy ! go mod tidy
stderr '^example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n' stderr '^example\.com/m imports\n\texample\.net/lazy imports\n\texample\.com/retract/incompatible loaded from example\.com/retract/incompatible@v1\.0\.0,\n\tbut go 1\.16 would select v2\.0\.0\+incompatible\n\n'
stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/wiki/PruningModules\n' stderr '\n\nTo upgrade to the versions selected by go 1\.16:\n\tgo mod tidy -go=1\.16 && go mod tidy -go=1\.17\nIf reproducibility with go 1\.16 is not needed:\n\tgo mod tidy -compat=1.17\nFor other options, see:\n\thttps://golang\.org/doc/modules/pruning\n'
cmp go.mod go.mod.orig cmp go.mod go.mod.orig

View file

@ -0,0 +1,34 @@
# When finding the latest version of a module, we should not download version
# contents. Previously, we downloaded .zip files to determine whether a real
# .mod file was present in order to decide whether +incompatible versions
# could be "latest".
#
# Verifies #47377.
# rsc.io/breaker has two versions, neither of which has a .mod file.
go list -m -versions rsc.io/breaker
stdout '^rsc.io/breaker v1.0.0 v2.0.0\+incompatible$'
go mod download rsc.io/breaker@v1.0.0
! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.mod
go mod download rsc.io/breaker@v2.0.0+incompatible
! grep '^go' $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.mod
# Delete downloaded .zip files.
go clean -modcache
# Check for updates.
go list -m -u rsc.io/breaker
stdout '^rsc.io/breaker v1.0.0 \[v2.0.0\+incompatible\]$'
# We should not have downloaded zips.
! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v1.0.0.zip
! exists $GOPATH/pkg/mod/cache/download/rsc.io/breaker/@v/v2.0.0+incompatible.zip
-- go.mod --
module m
go 1.16
require rsc.io/breaker v1.0.0
-- go.sum --
rsc.io/breaker v1.0.0/go.mod h1:s5yxDXvD88U1/ESC23I2FK3Lkv4YIKaB1ij/Hbm805g=

View file

@ -16,12 +16,12 @@ import (
// Decoding the type.* symbols. This has to be in sync with // Decoding the type.* symbols. This has to be in sync with
// ../../runtime/type.go, or more specifically, with what // ../../runtime/type.go, or more specifically, with what
// cmd/compile/internal/gc/reflect.go stuffs in these. // cmd/compile/internal/reflectdata/reflect.go stuffs in these.
// tflag is documented in reflect/type.go. // tflag is documented in reflect/type.go.
// //
// tflag values must be kept in sync with copies in: // tflag values must be kept in sync with copies in:
// cmd/compile/internal/gc/reflect.go // cmd/compile/internal/reflectdata/reflect.go
// cmd/link/internal/ld/decodesym.go // cmd/link/internal/ld/decodesym.go
// reflect/type.go // reflect/type.go
// runtime/type.go // runtime/type.go

View file

@ -459,6 +459,15 @@ func (st *loadState) addSym(name string, ver int, r *oReader, li uint32, kind in
if l.flags&FlagStrictDups != 0 { if l.flags&FlagStrictDups != 0 {
l.checkdup(name, r, li, oldi) l.checkdup(name, r, li, oldi)
} }
// Fix for issue #47185 -- given two dupok symbols with
// different sizes, favor symbol with larger size. See
// also issue #46653.
szdup := l.SymSize(oldi)
sz := int64(r.Sym(li).Siz())
if szdup < sz {
// new symbol overwrites old symbol.
l.objSyms[oldi] = objSym{r.objidx, li}
}
return oldi return oldi
} }
oldr, oldli := l.toLocal(oldi) oldr, oldli := l.toLocal(oldi)

View file

@ -1,3 +1,7 @@
// Copyright 2012 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 package main
import ( import (

View file

@ -1,3 +1,7 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package copylock package copylock
import "sync" import "sync"

View file

@ -1,3 +1,7 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package httpresponse package httpresponse
import ( import (

View file

@ -1 +1,5 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package testdata package testdata

View file

@ -1,3 +1,7 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package testdata package testdata
func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"

View file

@ -86,7 +86,11 @@ func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello
return nil, nil, err return nil, nil, err
} }
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
}
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View file

@ -8,7 +8,7 @@ package x509
// argument to the latest security_certificates version from // argument to the latest security_certificates version from
// https://opensource.apple.com/source/security_certificates/ // https://opensource.apple.com/source/security_certificates/
// and run "go generate". See https://golang.org/issue/38843. // and run "go generate". See https://golang.org/issue/38843.
//go:generate go run root_ios_gen.go -version 55188.40.9 //go:generate go run root_ios_gen.go -version 55188.120.1.0.1
import "sync" import "sync"

View file

@ -1,4 +1,4 @@
// Code generated by root_ios_gen.go -version 55188.40.9; DO NOT EDIT. // Code generated by root_ios_gen.go -version 55188.120.1.0.1; DO NOT EDIT.
// Update the version in root.go and regenerate with "go generate". // Update the version in root.go and regenerate with "go generate".
//go:build ios && !x509omitbundledroots //go:build ios && !x509omitbundledroots
@ -2223,6 +2223,41 @@ uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
ewv4n4Q= ewv4n4Q=
-----END CERTIFICATE----- -----END CERTIFICATE-----
# "GlobalSign"
# 2C AB EA FE 37 D0 6C A2 2A BA 73 91 C0 03 3D 25
# 98 29 52 C4 53 64 73 49 76 3A 3A B5 AD 6C CF 69
-----BEGIN CERTIFICATE-----
MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET
MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI
xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k
ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD
aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw
LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw
1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX
k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2
SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h
bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n
WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY
rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce
MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu
bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt
Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61
55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj
vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf
cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz
oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp
nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs
pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v
JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
-----END CERTIFICATE-----
# "GlobalSign Root CA" # "GlobalSign Root CA"
# EB D4 10 40 E4 BB 3E C7 42 C9 E3 81 D3 1E F2 A4 # EB D4 10 40 E4 BB 3E C7 42 C9 E3 81 D3 1E F2 A4
# 1A 48 B6 68 5C 96 E7 CE F3 C1 DF 6C D4 33 1C 99 # 1A 48 B6 68 5C 96 E7 CE F3 C1 DF 6C D4 33 1C 99

View file

@ -8,4 +8,4 @@ package build
// Do not remove from this list, as these are used for go/build filename matching. // Do not remove from this list, as these are used for go/build filename matching.
const goosList = "aix android darwin dragonfly freebsd hurd illumos ios js linux nacl netbsd openbsd plan9 solaris windows zos " const goosList = "aix android darwin dragonfly freebsd hurd illumos ios js linux nacl netbsd openbsd plan9 solaris windows zos "
const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm " const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le loong64 mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "

View file

@ -322,6 +322,18 @@ func TestTypesInfo(t *testing.T) {
`[][]struct{}`, `[][]struct{}`,
}, },
// issue 47243
{`package issue47243_a; var x int32; var _ = x << 3`, `3`, `untyped int`},
{`package issue47243_b; var x int32; var _ = x << 3.`, `3.`, `uint`}, // issue 47410: should be untyped float
{`package issue47243_c; var x int32; var _ = 1 << x`, `1 << x`, `int`},
{`package issue47243_d; var x int32; var _ = 1 << x`, `1`, `int`},
{`package issue47243_e; var x int32; var _ = 1 << 2`, `1`, `untyped int`},
{`package issue47243_f; var x int32; var _ = 1 << 2`, `2`, `untyped int`},
{`package issue47243_g; var x int32; var _ = int(1) << 2`, `2`, `untyped int`},
{`package issue47243_h; var x int32; var _ = 1 << (2 << x)`, `1`, `int`},
{`package issue47243_i; var x int32; var _ = 1 << (2 << x)`, `(2 << x)`, `untyped int`},
{`package issue47243_j; var x int32; var _ = 1 << (2 << x)`, `2`, `untyped int`},
// tests for broken code that doesn't parse or type-check // tests for broken code that doesn't parse or type-check
{broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`}, {broken + `x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
{broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`}, {broken + `x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},

View file

@ -344,6 +344,13 @@ func TestIssue46453(t *testing.T) {
checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil) checkFiles(t, nil, "", []string{"issue46453.go"}, [][]byte{[]byte(src)}, false, nil)
} }
func TestIssue47243_TypedRHS(t *testing.T) {
// The RHS of the shift expression below overflows uint on 32bit platforms,
// but this is OK as it is explicitly typed.
const src = "package issue47243\n\nvar a uint64; var _ = a << uint64(4294967296)" // uint64(1<<32)
checkFiles(t, &StdSizes{4, 4}, "", []string{"p.go"}, [][]byte{[]byte(src)}, false, nil)
}
func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "check") } func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDir(t, "check") }
func TestExamples(t *testing.T) { testDir(t, "examples") } func TestExamples(t *testing.T) { testDir(t, "examples") }
func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") } func TestFixedbugs(t *testing.T) { testDir(t, "fixedbugs") }

View file

@ -778,32 +778,48 @@ func (check *Checker) shift(x, y *operand, e ast.Expr, op token.Token) {
// spec: "The right operand in a shift expression must have integer type // spec: "The right operand in a shift expression must have integer type
// or be an untyped constant representable by a value of type uint." // or be an untyped constant representable by a value of type uint."
// Provide a good error message for negative shift counts. // Check that constants are representable by uint, but do not convert them
// (see also issue #47243).
if y.mode == constant_ { if y.mode == constant_ {
// Provide a good error message for negative shift counts.
yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1 yval := constant.ToInt(y.val) // consider -1, 1.0, but not -1.1
if yval.Kind() == constant.Int && constant.Sign(yval) < 0 { if yval.Kind() == constant.Int && constant.Sign(yval) < 0 {
check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y) check.invalidOp(y, _InvalidShiftCount, "negative shift count %s", y)
x.mode = invalid x.mode = invalid
return return
} }
if isUntyped(y.typ) {
// Caution: Check for representability here, rather than in the switch
// below, because isInteger includes untyped integers (was bug #43697).
check.representable(y, Typ[Uint])
if y.mode == invalid {
x.mode = invalid
return
}
}
} }
// Caution: Check for isUntyped first because isInteger includes untyped // Check that RHS is otherwise at least of integer type.
// integers (was bug #43697). switch {
if isUntyped(y.typ) { case isInteger(y.typ):
if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
x.mode = invalid
return
}
case isUntyped(y.typ):
// This is incorrect, but preserves pre-existing behavior.
// See also bug #47410.
check.convertUntyped(y, Typ[Uint]) check.convertUntyped(y, Typ[Uint])
if y.mode == invalid { if y.mode == invalid {
x.mode = invalid x.mode = invalid
return return
} }
} else if !isInteger(y.typ) { default:
check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y) check.invalidOp(y, _InvalidShiftCount, "shift count %s must be integer", y)
x.mode = invalid x.mode = invalid
return return
} else if !isUnsigned(y.typ) && !check.allowVersion(check.pkg, 1, 13) {
check.invalidOp(y, _InvalidShiftCount, "signed shift count %s requires go1.13 or later", y)
x.mode = invalid
return
} }
if x.mode == constant_ { if x.mode == constant_ {

View file

@ -68,7 +68,7 @@ type Type interface {
} }
/* /*
* These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go).
* A few are known to ../runtime/type.go to convey to debuggers. * A few are known to ../runtime/type.go to convey to debuggers.
* They are also known to ../runtime/type.go. * They are also known to ../runtime/type.go.
*/ */
@ -111,7 +111,7 @@ const (
// available in the memory directly following the rtype value. // available in the memory directly following the rtype value.
// //
// tflag values must be kept in sync with copies in: // tflag values must be kept in sync with copies in:
// cmd/compile/internal/gc/reflect.go // cmd/compile/internal/reflectdata/reflect.go
// cmd/link/internal/ld/decodesym.go // cmd/link/internal/ld/decodesym.go
// runtime/type.go // runtime/type.go
type tflag uint8 type tflag uint8

View file

@ -1846,6 +1846,17 @@ func TestCVE202133195(t *testing.T) {
Target: dnsmessage.MustNewName("<html>.golang.org."), Target: dnsmessage.MustNewName("<html>.golang.org."),
}, },
}, },
dnsmessage.Resource{
Header: dnsmessage.ResourceHeader{
Name: n,
Type: dnsmessage.TypeSRV,
Class: dnsmessage.ClassINET,
Length: 4,
},
Body: &dnsmessage.SRVResource{
Target: dnsmessage.MustNewName("good.golang.org."),
},
},
) )
case dnsmessage.TypeMX: case dnsmessage.TypeMX:
r.Answers = append(r.Answers, r.Answers = append(r.Answers,
@ -1860,6 +1871,17 @@ func TestCVE202133195(t *testing.T) {
MX: dnsmessage.MustNewName("<html>.golang.org."), MX: dnsmessage.MustNewName("<html>.golang.org."),
}, },
}, },
dnsmessage.Resource{
Header: dnsmessage.ResourceHeader{
Name: dnsmessage.MustNewName("good.golang.org."),
Type: dnsmessage.TypeMX,
Class: dnsmessage.ClassINET,
Length: 4,
},
Body: &dnsmessage.MXResource{
MX: dnsmessage.MustNewName("good.golang.org."),
},
},
) )
case dnsmessage.TypeNS: case dnsmessage.TypeNS:
r.Answers = append(r.Answers, r.Answers = append(r.Answers,
@ -1874,6 +1896,17 @@ func TestCVE202133195(t *testing.T) {
NS: dnsmessage.MustNewName("<html>.golang.org."), NS: dnsmessage.MustNewName("<html>.golang.org."),
}, },
}, },
dnsmessage.Resource{
Header: dnsmessage.ResourceHeader{
Name: dnsmessage.MustNewName("good.golang.org."),
Type: dnsmessage.TypeNS,
Class: dnsmessage.ClassINET,
Length: 4,
},
Body: &dnsmessage.NSResource{
NS: dnsmessage.MustNewName("good.golang.org."),
},
},
) )
case dnsmessage.TypePTR: case dnsmessage.TypePTR:
r.Answers = append(r.Answers, r.Answers = append(r.Answers,
@ -1888,6 +1921,17 @@ func TestCVE202133195(t *testing.T) {
PTR: dnsmessage.MustNewName("<html>.golang.org."), PTR: dnsmessage.MustNewName("<html>.golang.org."),
}, },
}, },
dnsmessage.Resource{
Header: dnsmessage.ResourceHeader{
Name: dnsmessage.MustNewName("good.golang.org."),
Type: dnsmessage.TypePTR,
Class: dnsmessage.ClassINET,
Length: 4,
},
Body: &dnsmessage.PTRResource{
PTR: dnsmessage.MustNewName("good.golang.org."),
},
},
) )
} }
return r, nil return r, nil
@ -1903,25 +1947,53 @@ func TestCVE202133195(t *testing.T) {
defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
testHookHostsPath = "testdata/hosts" testHookHostsPath = "testdata/hosts"
tests := []struct {
name string
f func(*testing.T)
}{
{
name: "CNAME",
f: func(t *testing.T) {
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
_, err := r.LookupCNAME(context.Background(), "golang.org") _, err := r.LookupCNAME(context.Background(), "golang.org")
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { if err.Error() != expectedErr.Error() {
t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected) t.Fatalf("unexpected error: %s", err)
} }
_, err = LookupCNAME("golang.org") _, err = LookupCNAME("golang.org")
if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { if err.Error() != expectedErr.Error() {
t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected) t.Fatalf("unexpected error: %s", err)
} }
},
_, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") },
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, expected) name: "SRV (bad record)",
f: func(t *testing.T) {
expected := []*SRV{
{
Target: "good.golang.org.",
},
} }
_, _, err = LookupSRV("target", "tcp", "golang.org") expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { _, records, err := r.LookupSRV(context.Background(), "target", "tcp", "golang.org")
t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
} }
if !reflect.DeepEqual(records, expected) {
_, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.") t.Error("Unexpected record set")
}
_, records, err = LookupSRV("target", "tcp", "golang.org")
if err.Error() != expectedErr.Error() {
t.Errorf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
},
},
{
name: "SRV (bad header)",
f: func(t *testing.T) {
_, _, err := r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org.")
if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || 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, expected) t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected)
} }
@ -1929,33 +2001,85 @@ func TestCVE202133195(t *testing.T) {
if expected := "lookup golang.org.: SRV header name is invalid"; err == nil || err.Error() != expected { 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, expected) t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected)
} }
},
_, err = r.LookupMX(context.Background(), "golang.org") },
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, expected) name: "MX",
f: func(t *testing.T) {
expected := []*MX{
{
Host: "good.golang.org.",
},
} }
_, err = LookupMX("golang.org") expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { records, err := r.LookupMX(context.Background(), "golang.org")
t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected) if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
records, err = LookupMX("golang.org")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
},
},
{
name: "NS",
f: func(t *testing.T) {
expected := []*NS{
{
Host: "good.golang.org.",
},
}
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
records, err := r.LookupNS(context.Background(), "golang.org")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
records, err = LookupNS("golang.org")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
},
},
{
name: "Addr",
f: func(t *testing.T) {
expected := []string{"good.golang.org."}
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "192.0.2.42"}
records, err := r.LookupAddr(context.Background(), "192.0.2.42")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
records, err = LookupAddr("192.0.2.42")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
if !reflect.DeepEqual(records, expected) {
t.Error("Unexpected record set")
}
},
},
} }
_, err = r.LookupNS(context.Background(), "golang.org") for _, tc := range tests {
if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { t.Run(tc.name, tc.f)
t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, 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, expected)
} }
_, err = r.LookupAddr(context.Background(), "192.0.2.42")
if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected)
}
_, err = LookupAddr("192.0.2.42")
if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected {
t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected)
}
} }
func TestNullMX(t *testing.T) { func TestNullMX(t *testing.T) {

View file

@ -951,7 +951,7 @@ func (c *Client) CloseIdleConnections() {
} }
// cancelTimerBody is an io.ReadCloser that wraps rc with two features: // cancelTimerBody is an io.ReadCloser that wraps rc with two features:
// 1) on Read error or close, the stop func is called. // 1) On Read error or close, the stop func is called.
// 2) On Read failure, if reqDidTimeout is true, the error is wrapped and // 2) On Read failure, if reqDidTimeout is true, the error is wrapped and
// marked as net.Error that hit its timeout. // marked as net.Error that hit its timeout.
type cancelTimerBody struct { type cancelTimerBody struct {

View file

@ -424,7 +424,7 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
return "", err return "", err
} }
if !isDomainName(cname) { if !isDomainName(cname) {
return "", &DNSError{Err: "CNAME target is invalid", Name: host} return "", &DNSError{Err: errMalformedDNSRecordsDetail, Name: host}
} }
return cname, nil return cname, nil
} }
@ -440,7 +440,9 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error)
// and proto are empty strings, LookupSRV looks up name directly. // and proto are empty strings, LookupSRV looks up name directly.
// //
// The returned service names are validated to be properly // The returned service names are validated to be properly
// formatted presentation-format domain names. // formatted presentation-format domain names. If the response contains
// invalid names, those records are filtered out and an error
// will be returned alongside the the remaining results, if any.
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 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)
} }
@ -456,7 +458,9 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
// and proto are empty strings, LookupSRV looks up name directly. // and proto are empty strings, LookupSRV looks up name directly.
// //
// The returned service names are validated to be properly // The returned service names are validated to be properly
// formatted presentation-format domain names. // formatted presentation-format domain names. If the response contains
// invalid names, those records are filtered out and an error
// will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
cname, addrs, err := r.lookupSRV(ctx, service, proto, name) cname, addrs, err := r.lookupSRV(ctx, service, proto, name)
if err != nil { if err != nil {
@ -465,21 +469,28 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (
if cname != "" && !isDomainName(cname) { if cname != "" && !isDomainName(cname) {
return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name}
} }
filteredAddrs := make([]*SRV, 0, len(addrs))
for _, addr := range addrs { for _, addr := range addrs {
if addr == nil { if addr == nil {
continue continue
} }
if !isDomainName(addr.Target) { if !isDomainName(addr.Target) {
return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} continue
} }
filteredAddrs = append(filteredAddrs, addr)
} }
return cname, addrs, nil if len(addrs) != len(filteredAddrs) {
return cname, filteredAddrs, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
}
return cname, filteredAddrs, nil
} }
// LookupMX returns the DNS MX records for the given domain name sorted by preference. // LookupMX returns the DNS MX records for the given domain name sorted by preference.
// //
// The returned mail server names are validated to be properly // The returned mail server names are validated to be properly
// formatted presentation-format domain names. // formatted presentation-format domain names. If the response contains
// invalid names, those records are filtered out and an error
// will be returned alongside the the remaining results, if any.
// //
// LookupMX uses context.Background internally; to specify the context, use // LookupMX uses context.Background internally; to specify the context, use
// Resolver.LookupMX. // Resolver.LookupMX.
@ -490,12 +501,15 @@ func LookupMX(name string) ([]*MX, error) {
// LookupMX returns the DNS MX records for the given domain name sorted by preference. // LookupMX returns the DNS MX records for the given domain name sorted by preference.
// //
// The returned mail server names are validated to be properly // The returned mail server names are validated to be properly
// formatted presentation-format domain names. // formatted presentation-format domain names. If the response contains
// invalid names, those records are filtered out and an error
// will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
records, err := r.lookupMX(ctx, name) records, err := r.lookupMX(ctx, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
filteredMX := make([]*MX, 0, len(records))
for _, mx := range records { for _, mx := range records {
if mx == nil { if mx == nil {
continue continue
@ -503,16 +517,22 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
// Bypass the hostname validity check for targets which contain only a dot, // Bypass the hostname validity check for targets which contain only a dot,
// as this is used to represent a 'Null' MX record. // as this is used to represent a 'Null' MX record.
if mx.Host != "." && !isDomainName(mx.Host) { if mx.Host != "." && !isDomainName(mx.Host) {
return nil, &DNSError{Err: "MX target is invalid", Name: name} continue
} }
filteredMX = append(filteredMX, mx)
} }
return records, nil if len(records) != len(filteredMX) {
return filteredMX, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
}
return filteredMX, nil
} }
// LookupNS returns the DNS NS records for the given domain name. // LookupNS returns the DNS NS records for the given domain name.
// //
// The returned name server names are validated to be properly // The returned name server names are validated to be properly
// formatted presentation-format domain names. // formatted presentation-format domain names. If the response contains
// invalid names, those records are filtered out and an error
// will be returned alongside the the remaining results, if any.
// //
// LookupNS uses context.Background internally; to specify the context, use // LookupNS uses context.Background internally; to specify the context, use
// Resolver.LookupNS. // Resolver.LookupNS.
@ -523,21 +543,28 @@ func LookupNS(name string) ([]*NS, error) {
// LookupNS returns the DNS NS records for the given domain name. // LookupNS returns the DNS NS records for the given domain name.
// //
// The returned name server names are validated to be properly // The returned name server names are validated to be properly
// formatted presentation-format domain names. // formatted presentation-format domain names. If the response contains
// invalid names, those records are filtered out and an error
// will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
records, err := r.lookupNS(ctx, name) records, err := r.lookupNS(ctx, name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
filteredNS := make([]*NS, 0, len(records))
for _, ns := range records { for _, ns := range records {
if ns == nil { if ns == nil {
continue continue
} }
if !isDomainName(ns.Host) { if !isDomainName(ns.Host) {
return nil, &DNSError{Err: "NS target is invalid", Name: name} continue
} }
filteredNS = append(filteredNS, ns)
} }
return records, nil if len(records) != len(filteredNS) {
return filteredNS, &DNSError{Err: errMalformedDNSRecordsDetail, Name: name}
}
return filteredNS, nil
} }
// LookupTXT returns the DNS TXT records for the given domain name. // LookupTXT returns the DNS TXT records for the given domain name.
@ -557,7 +584,8 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error)
// of names mapping to that address. // of names mapping to that address.
// //
// The returned names are validated to be properly formatted presentation-format // The returned names are validated to be properly formatted presentation-format
// domain names. // domain names. If the response contains invalid names, those records are filtered
// out and an error will be returned alongside the the remaining results, if any.
// //
// When using the host C library resolver, at most one result will be // When using the host C library resolver, at most one result will be
// returned. To bypass the host resolver, use a custom Resolver. // returned. To bypass the host resolver, use a custom Resolver.
@ -572,16 +600,26 @@ func LookupAddr(addr string) (names []string, err error) {
// of names mapping to that address. // of names mapping to that address.
// //
// The returned names are validated to be properly formatted presentation-format // The returned names are validated to be properly formatted presentation-format
// domain names. // domain names. If the response contains invalid names, those records are filtered
// out and an error will be returned alongside the the remaining results, if any.
func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) {
names, err := r.lookupAddr(ctx, addr) names, err := r.lookupAddr(ctx, addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
filteredNames := make([]string, 0, len(names))
for _, name := range names { for _, name := range names {
if !isDomainName(name) { if isDomainName(name) {
return nil, &DNSError{Err: "PTR target is invalid", Name: addr} filteredNames = append(filteredNames, name)
} }
} }
return names, nil if len(names) != len(filteredNames) {
return filteredNames, &DNSError{Err: errMalformedDNSRecordsDetail, Name: addr}
} }
return filteredNames, nil
}
// errMalformedDNSRecordsDetail is the DNSError detail which is returned when a Resolver.Lookup...
// method recieves DNS records which contain invalid DNS names. This may be returned alongside
// results which have had the malformed records filtered out.
var errMalformedDNSRecordsDetail = "DNS response contained records which contain invalid names"

View file

@ -4304,6 +4304,9 @@ func TestConvert(t *testing.T) {
// vout1 represents the in value converted to the in type. // vout1 represents the in value converted to the in type.
v1 := tt.in v1 := tt.in
if !v1.CanConvert(t1) {
t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t1)
}
vout1 := v1.Convert(t1) vout1 := v1.Convert(t1)
out1 := vout1.Interface() out1 := vout1.Interface()
if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) { if vout1.Type() != tt.in.Type() || !DeepEqual(out1, tt.in.Interface()) {
@ -4311,6 +4314,9 @@ func TestConvert(t *testing.T) {
} }
// vout2 represents the in value converted to the out type. // vout2 represents the in value converted to the out type.
if !v1.CanConvert(t2) {
t.Errorf("ValueOf(%T(%[1]v)).CanConvert(%s) = false, want true", tt.in.Interface(), t2)
}
vout2 := v1.Convert(t2) vout2 := v1.Convert(t2)
out2 := vout2.Interface() out2 := vout2.Interface()
if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) { if vout2.Type() != tt.out.Type() || !DeepEqual(out2, tt.out.Interface()) {
@ -4371,6 +4377,9 @@ func TestConvertPanic(t *testing.T) {
if !v.Type().ConvertibleTo(pt) { if !v.Type().ConvertibleTo(pt) {
t.Errorf("[]byte should be convertible to *[8]byte") t.Errorf("[]byte should be convertible to *[8]byte")
} }
if v.CanConvert(pt) {
t.Errorf("slice with length 4 should not be convertible to *[8]byte")
}
shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() { shouldPanic("reflect: cannot convert slice with length 4 to pointer to array with length 8", func() {
_ = v.Convert(pt) _ = v.Convert(pt)
}) })

View file

@ -228,7 +228,7 @@ type Type interface {
// See https://golang.org/issue/4876 for more details. // See https://golang.org/issue/4876 for more details.
/* /*
* These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go).
* A few are known to ../runtime/type.go to convey to debuggers. * A few are known to ../runtime/type.go to convey to debuggers.
* They are also known to ../runtime/type.go. * They are also known to ../runtime/type.go.
*/ */
@ -271,7 +271,7 @@ const (
// available in the memory directly following the rtype value. // available in the memory directly following the rtype value.
// //
// tflag values must be kept in sync with copies in: // tflag values must be kept in sync with copies in:
// cmd/compile/internal/gc/reflect.go // cmd/compile/internal/reflectdata/reflect.go
// cmd/link/internal/ld/decodesym.go // cmd/link/internal/ld/decodesym.go
// runtime/type.go // runtime/type.go
type tflag uint8 type tflag uint8
@ -1910,7 +1910,7 @@ func MapOf(key, elem Type) Type {
// Make a map type. // Make a map type.
// Note: flag values must match those used in the TMAP case // Note: flag values must match those used in the TMAP case
// in ../cmd/compile/internal/gc/reflect.go:writeType. // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap)) mt := **(**mapType)(unsafe.Pointer(&imap))
mt.str = resolveReflectName(newName(s, "", false)) mt.str = resolveReflectName(newName(s, "", false))
@ -2841,7 +2841,7 @@ func runtimeStructField(field StructField) (structField, string) {
// typeptrdata returns the length in bytes of the prefix of t // typeptrdata returns the length in bytes of the prefix of t
// containing pointer data. Anything after this offset is scalar data. // containing pointer data. Anything after this offset is scalar data.
// keep in sync with ../cmd/compile/internal/gc/reflect.go // keep in sync with ../cmd/compile/internal/reflectdata/reflect.go
func typeptrdata(t *rtype) uintptr { func typeptrdata(t *rtype) uintptr {
switch t.Kind() { switch t.Kind() {
case Struct: case Struct:
@ -2865,7 +2865,7 @@ func typeptrdata(t *rtype) uintptr {
} }
} }
// See cmd/compile/internal/gc/reflect.go for derivation of constant. // See cmd/compile/internal/reflectdata/reflect.go for derivation of constant.
const maxPtrmaskBytes = 2048 const maxPtrmaskBytes = 2048
// ArrayOf returns the array type with the given length and element type. // ArrayOf returns the array type with the given length and element type.

View file

@ -2811,6 +2811,26 @@ func (v Value) Convert(t Type) Value {
return op(v, t) return op(v, t)
} }
// CanConvert reports whether the value v can be converted to type t.
// If v.CanConvert(t) returns true then v.Convert(t) will not panic.
func (v Value) CanConvert(t Type) bool {
vt := v.Type()
if !vt.ConvertibleTo(t) {
return false
}
// Currently the only conversion that is OK in terms of type
// but that can panic depending on the value is converting
// from slice to pointer-to-array.
if vt.Kind() == Slice && t.Kind() == Ptr && t.Elem().Kind() == Array {
n := t.Elem().Len()
h := (*unsafeheader.Slice)(v.ptr)
if n > h.Len {
return false
}
}
return true
}
// convertOp returns the function to convert a value of type src // convertOp returns the function to convert a value of type src
// to a value of type dst. If the conversion is illegal, convertOp returns nil. // to a value of type dst. If the conversion is illegal, convertOp returns nil.
func convertOp(dst, src *rtype) func(Value, Type) Value { func convertOp(dst, src *rtype) func(Value, Type) Value {

View file

@ -1,3 +1,7 @@
// 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 reflect package reflect
// VisibleFields returns all the visible fields in t, which must be a // VisibleFields returns all the visible fields in t, which must be a

View file

@ -1,3 +1,7 @@
// 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 reflect_test package reflect_test
import ( import (

View file

@ -7,6 +7,11 @@ package runtime
import "unsafe" import "unsafe"
func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) { func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) {
// nil pointer is always suitably aligned (#47430).
if p == nil {
return
}
// Check that (*[n]elem)(p) is appropriately aligned. // Check that (*[n]elem)(p) is appropriately aligned.
// Note that we allow unaligned pointers if the types they point to contain // Note that we allow unaligned pointers if the types they point to contain
// no pointers themselves. See issue 37298. // no pointers themselves. See issue 37298.
@ -29,10 +34,12 @@ func checkptrStraddles(ptr unsafe.Pointer, size uintptr) bool {
return false return false
} }
end := add(ptr, size-1) // Check that add(ptr, size-1) won't overflow. This avoids the risk
if uintptr(end) < uintptr(ptr) { // of producing an illegal pointer value (assuming ptr is legal).
if uintptr(ptr) >= -(size - 1) {
return true return true
} }
end := add(ptr, size-1)
// TODO(mdempsky): Detect when [ptr, end] contains Go allocations, // TODO(mdempsky): Detect when [ptr, end] contains Go allocations,
// but neither ptr nor end point into one themselves. // but neither ptr nor end point into one themselves.

View file

@ -26,6 +26,7 @@ func TestCheckPtr(t *testing.T) {
}{ }{
{"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"}, {"CheckPtrAlignmentPtr", "fatal error: checkptr: misaligned pointer conversion\n"},
{"CheckPtrAlignmentNoPtr", ""}, {"CheckPtrAlignmentNoPtr", ""},
{"CheckPtrAlignmentNilPtr", ""},
{"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"}, {"CheckPtrArithmetic", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
{"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"}, {"CheckPtrArithmetic2", "fatal error: checkptr: pointer arithmetic result points to invalid allocation\n"},
{"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"}, {"CheckPtrSize", "fatal error: checkptr: converted pointer straddles multiple allocations\n"},

View file

@ -24,6 +24,9 @@ func TestPanicOnFault(t *testing.T) {
if runtime.GOOS == "ios" { if runtime.GOOS == "ios" {
t.Skip("iOS doesn't provide fault addresses") t.Skip("iOS doesn't provide fault addresses")
} }
if runtime.GOOS == "netbsd" && runtime.GOARCH == "arm" {
t.Skip("netbsd-arm doesn't provide fault address (golang.org/issue/45026)")
}
m, err := syscall.Mmap(-1, 0, 0x1000, syscall.PROT_READ /* Note: no PROT_WRITE */, syscall.MAP_SHARED|syscall.MAP_ANON) m, err := syscall.Mmap(-1, 0, 0x1000, syscall.PROT_READ /* Note: no PROT_WRITE */, syscall.MAP_SHARED|syscall.MAP_ANON)
if err != nil { if err != nil {
t.Fatalf("can't map anonymous memory: %s", err) t.Fatalf("can't map anonymous memory: %s", err)

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 1
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 1 const GoarchArm64be = 1
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -0,0 +1,33 @@
// Code generated by gengoos.go using 'go generate'. DO NOT EDIT.
//go:build loong64
// +build loong64
package sys
const GOARCH = `loong64`
const Goarch386 = 0
const GoarchAmd64 = 0
const GoarchAmd64p32 = 0
const GoarchArm = 0
const GoarchArmbe = 0
const GoarchArm64 = 0
const GoarchArm64be = 0
const GoarchPpc64 = 0
const GoarchPpc64le = 0
const GoarchLoong64 = 1
const GoarchMips = 0
const GoarchMipsle = 0
const GoarchMips64 = 0
const GoarchMips64le = 0
const GoarchMips64p32 = 0
const GoarchMips64p32le = 0
const GoarchPpc = 0
const GoarchRiscv = 0
const GoarchRiscv64 = 0
const GoarchS390 = 0
const GoarchS390x = 0
const GoarchSparc = 0
const GoarchSparc64 = 0
const GoarchWasm = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 1 const GoarchMips = 1
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 1 const GoarchMips64 = 1

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 1 const GoarchMipsle = 1
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 1 const GoarchPpc64 = 1
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 1 const GoarchPpc64le = 1
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -16,6 +16,7 @@ const GoarchArm64 = 0
const GoarchArm64be = 0 const GoarchArm64be = 0
const GoarchPpc64 = 0 const GoarchPpc64 = 0
const GoarchPpc64le = 0 const GoarchPpc64le = 0
const GoarchLoong64 = 0
const GoarchMips = 0 const GoarchMips = 0
const GoarchMipsle = 0 const GoarchMipsle = 0
const GoarchMips64 = 0 const GoarchMips64 = 0

View file

@ -1135,13 +1135,21 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
msanmalloc(x, size) msanmalloc(x, size)
} }
if rate := MemProfileRate; rate > 0 {
// Note cache c only valid while m acquired; see #47302
if rate != 1 && size < c.nextSample {
c.nextSample -= size
} else {
profilealloc(mp, x, size)
}
}
mp.mallocing = 0 mp.mallocing = 0
releasem(mp) releasem(mp)
// Pointerfree data can be zeroed late in a context where preemption can occur. // Pointerfree data can be zeroed late in a context where preemption can occur.
// x will keep the memory alive. // x will keep the memory alive.
if !isZeroed && needzero { if !isZeroed && needzero {
memclrNoHeapPointersChunked(size, x) memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302
} }
if debug.malloc { if debug.malloc {
@ -1155,16 +1163,6 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
} }
} }
if rate := MemProfileRate; rate > 0 {
if rate != 1 && size < c.nextSample {
c.nextSample -= size
} else {
mp := acquirem()
profilealloc(mp, x, size)
releasem(mp)
}
}
if assistG != nil { if assistG != nil {
// Account for internal fragmentation in the assist // Account for internal fragmentation in the assist
// debt now that we know it. // debt now that we know it.

View file

@ -86,6 +86,17 @@ func TestMemoryProfiler(t *testing.T) {
runtime.GC() // materialize stats runtime.GC() // materialize stats
// TODO(mknyszek): Fix #45315 and remove this extra call.
//
// Unfortunately, it's possible for the sweep termination condition
// to flap, so with just one runtime.GC call, a freed object could be
// missed, leading this test to fail. A second call reduces the chance
// of this happening to zero, because sweeping actually has to finish
// to move on to the next GC, during which nothing will happen.
//
// See #46500 for more details.
runtime.GC()
memoryProfilerRun++ memoryProfilerRun++
tests := []struct { tests := []struct {

View file

@ -4919,7 +4919,6 @@ func (pp *p) destroy() {
moveTimers(plocal, pp.timers) moveTimers(plocal, pp.timers)
pp.timers = nil pp.timers = nil
pp.numTimers = 0 pp.numTimers = 0
pp.adjustTimers = 0
pp.deletedTimers = 0 pp.deletedTimers = 0
atomic.Store64(&pp.timer0When, 0) atomic.Store64(&pp.timer0When, 0)
unlock(&pp.timersLock) unlock(&pp.timersLock)

View file

@ -343,7 +343,7 @@ func racereadrangepc1(addr, size, pc uintptr)
func racewriterangepc1(addr, size, pc uintptr) func racewriterangepc1(addr, size, pc uintptr)
func racecallbackthunk(uintptr) func racecallbackthunk(uintptr)
// racecall allows calling an arbitrary function f from C race runtime // racecall allows calling an arbitrary function fn from C race runtime
// with up to 4 uintptr arguments. // with up to 4 uintptr arguments.
func racecall(fn *byte, arg0, arg1, arg2, arg3 uintptr) func racecall(fn *byte, arg0, arg1, arg2, arg3 uintptr)

View file

@ -681,7 +681,7 @@ type p struct {
// timerModifiedEarlier status. Because the timer may have been // timerModifiedEarlier status. Because the timer may have been
// modified again, there need not be any timer with this value. // modified again, there need not be any timer with this value.
// This is updated using atomic functions. // This is updated using atomic functions.
// This is 0 if the value is unknown. // This is 0 if there are no timerModifiedEarlier timers.
timerModifiedEarliest uint64 timerModifiedEarliest uint64
// Per-P GC state // Per-P GC state
@ -727,12 +727,6 @@ type p struct {
// Modified using atomic instructions. // Modified using atomic instructions.
numTimers uint32 numTimers uint32
// Number of timerModifiedEarlier timers on P's heap.
// This should only be modified while holding timersLock,
// or while the timer status is in a transient state
// such as timerModifying.
adjustTimers uint32
// Number of timerDeleted timers in P's heap. // Number of timerDeleted timers in P's heap.
// Modified using atomic instructions. // Modified using atomic instructions.
deletedTimers uint32 deletedTimers uint32
@ -895,7 +889,7 @@ type funcinl struct {
// layout of Itab known to compilers // layout of Itab known to compilers
// allocated in non-garbage-collected memory // allocated in non-garbage-collected memory
// Needs to be in sync with // Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.WriteTabs. // ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs.
type itab struct { type itab struct {
inter *interfacetype inter *interfacetype
_type *_type _type *_type
@ -940,7 +934,7 @@ func extendRandom(r []byte, n int) {
// A _defer holds an entry on the list of deferred calls. // A _defer holds an entry on the list of deferred calls.
// If you add a field here, add code to clear it in freedefer and deferProcStack // If you add a field here, add code to clear it in freedefer and deferProcStack
// This struct must match the code in cmd/compile/internal/gc/reflect.go:deferstruct // This struct must match the code in cmd/compile/internal/reflectdata/reflect.go:deferstruct
// and cmd/compile/internal/gc/ssa.go:(*state).call. // and cmd/compile/internal/gc/ssa.go:(*state).call.
// Some defers will be allocated on the stack and some on the heap. // Some defers will be allocated on the stack and some on the heap.
// All defers are logically part of the stack, so write barriers to // All defers are logically part of the stack, so write barriers to

View file

@ -15,7 +15,7 @@ const debugSelect = false
// Select case descriptor. // Select case descriptor.
// Known to compiler. // Known to compiler.
// Changes here must also be made in src/cmd/internal/gc/select.go's scasetype. // Changes here must also be made in src/cmd/compile/internal/walk/select.go's scasetype.
type scase struct { type scase struct {
c *hchan // chan c *hchan // chan
elem unsafe.Pointer // data element elem unsafe.Pointer // data element

View file

@ -4,11 +4,16 @@
package main package main
import "unsafe" import (
"runtime"
"time"
"unsafe"
)
func init() { func init() {
register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr) register("CheckPtrAlignmentNoPtr", CheckPtrAlignmentNoPtr)
register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr) register("CheckPtrAlignmentPtr", CheckPtrAlignmentPtr)
register("CheckPtrAlignmentNilPtr", CheckPtrAlignmentNilPtr)
register("CheckPtrArithmetic", CheckPtrArithmetic) register("CheckPtrArithmetic", CheckPtrArithmetic)
register("CheckPtrArithmetic2", CheckPtrArithmetic2) register("CheckPtrArithmetic2", CheckPtrArithmetic2)
register("CheckPtrSize", CheckPtrSize) register("CheckPtrSize", CheckPtrSize)
@ -29,6 +34,35 @@ func CheckPtrAlignmentPtr() {
sink2 = (**int64)(unsafe.Pointer(uintptr(p) + 1)) sink2 = (**int64)(unsafe.Pointer(uintptr(p) + 1))
} }
// CheckPtrAlignmentNilPtr tests that checkptrAlignment doesn't crash
// on nil pointers (#47430).
func CheckPtrAlignmentNilPtr() {
var do func(int)
do = func(n int) {
// Inflate the stack so runtime.shrinkstack gets called during GC
if n > 0 {
do(n - 1)
}
var p unsafe.Pointer
_ = (*int)(p)
}
go func() {
for {
runtime.GC()
}
}()
go func() {
for i := 0; ; i++ {
do(i % 1024)
}
}()
time.Sleep(time.Second)
}
func CheckPtrArithmetic() { func CheckPtrArithmetic() {
var x int var x int
i := uintptr(unsafe.Pointer(&x)) i := uintptr(unsafe.Pointer(&x))

View file

@ -333,7 +333,6 @@ func deltimer(t *timer) bool {
// Must fetch t.pp before setting status // Must fetch t.pp before setting status
// to timerDeleted. // to timerDeleted.
tpp := t.pp.ptr() tpp := t.pp.ptr()
atomic.Xadd(&tpp.adjustTimers, -1)
if !atomic.Cas(&t.status, timerModifying, timerDeleted) { if !atomic.Cas(&t.status, timerModifying, timerDeleted) {
badTimer() badTimer()
} }
@ -510,20 +509,9 @@ loop:
tpp := t.pp.ptr() tpp := t.pp.ptr()
// Update the adjustTimers field. Subtract one if we
// are removing a timerModifiedEarlier, add one if we
// are adding a timerModifiedEarlier.
adjust := int32(0)
if status == timerModifiedEarlier {
adjust--
}
if newStatus == timerModifiedEarlier { if newStatus == timerModifiedEarlier {
adjust++
updateTimerModifiedEarliest(tpp, when) updateTimerModifiedEarliest(tpp, when)
} }
if adjust != 0 {
atomic.Xadd(&tpp.adjustTimers, adjust)
}
// Set the new status of the timer. // Set the new status of the timer.
if !atomic.Cas(&t.status, timerModifying, newStatus) { if !atomic.Cas(&t.status, timerModifying, newStatus) {
@ -591,9 +579,6 @@ func cleantimers(pp *p) {
// Move t to the right position. // Move t to the right position.
dodeltimer0(pp) dodeltimer0(pp)
doaddtimer(pp, t) doaddtimer(pp, t)
if s == timerModifiedEarlier {
atomic.Xadd(&pp.adjustTimers, -1)
}
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
badTimer() badTimer()
} }
@ -664,25 +649,13 @@ func moveTimers(pp *p, timers []*timer) {
// it also moves timers that have been modified to run later, // it also moves timers that have been modified to run later,
// and removes deleted timers. The caller must have locked the timers for pp. // and removes deleted timers. The caller must have locked the timers for pp.
func adjusttimers(pp *p, now int64) { func adjusttimers(pp *p, now int64) {
if atomic.Load(&pp.adjustTimers) == 0 {
if verifyTimers {
verifyTimerHeap(pp)
}
// There are no timers to adjust, so it is safe to clear
// timerModifiedEarliest. Do so in case it is stale.
// Everything will work if we don't do this,
// but clearing here may save future calls to adjusttimers.
atomic.Store64(&pp.timerModifiedEarliest, 0)
return
}
// If we haven't yet reached the time of the first timerModifiedEarlier // If we haven't yet reached the time of the first timerModifiedEarlier
// timer, don't do anything. This speeds up programs that adjust // timer, don't do anything. This speeds up programs that adjust
// a lot of timers back and forth if the timers rarely expire. // a lot of timers back and forth if the timers rarely expire.
// We'll postpone looking through all the adjusted timers until // We'll postpone looking through all the adjusted timers until
// one would actually expire. // one would actually expire.
if first := atomic.Load64(&pp.timerModifiedEarliest); first != 0 { first := atomic.Load64(&pp.timerModifiedEarliest)
if int64(first) > now { if first == 0 || int64(first) > now {
if verifyTimers { if verifyTimers {
verifyTimerHeap(pp) verifyTimerHeap(pp)
} }
@ -691,10 +664,8 @@ func adjusttimers(pp *p, now int64) {
// We are going to clear all timerModifiedEarlier timers. // We are going to clear all timerModifiedEarlier timers.
atomic.Store64(&pp.timerModifiedEarliest, 0) atomic.Store64(&pp.timerModifiedEarliest, 0)
}
var moved []*timer var moved []*timer
loop:
for i := 0; i < len(pp.timers); i++ { for i := 0; i < len(pp.timers); i++ {
t := pp.timers[i] t := pp.timers[i]
if t.pp.ptr() != pp { if t.pp.ptr() != pp {
@ -721,11 +692,6 @@ loop:
// loop to skip some other timer. // loop to skip some other timer.
dodeltimer(pp, i) dodeltimer(pp, i)
moved = append(moved, t) moved = append(moved, t)
if s == timerModifiedEarlier {
if n := atomic.Xadd(&pp.adjustTimers, -1); int32(n) <= 0 {
break loop
}
}
// Look at this heap position again. // Look at this heap position again.
i-- i--
} }
@ -824,9 +790,6 @@ func runtimer(pp *p, now int64) int64 {
t.when = t.nextwhen t.when = t.nextwhen
dodeltimer0(pp) dodeltimer0(pp)
doaddtimer(pp, t) doaddtimer(pp, t)
if s == timerModifiedEarlier {
atomic.Xadd(&pp.adjustTimers, -1)
}
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
badTimer() badTimer()
} }
@ -921,7 +884,6 @@ func clearDeletedTimers(pp *p) {
atomic.Store64(&pp.timerModifiedEarliest, 0) atomic.Store64(&pp.timerModifiedEarliest, 0)
cdel := int32(0) cdel := int32(0)
cearlier := int32(0)
to := 0 to := 0
changedHeap := false changedHeap := false
timers := pp.timers timers := pp.timers
@ -946,9 +908,6 @@ nextTimer:
if !atomic.Cas(&t.status, timerMoving, timerWaiting) { if !atomic.Cas(&t.status, timerMoving, timerWaiting) {
badTimer() badTimer()
} }
if s == timerModifiedEarlier {
cearlier++
}
continue nextTimer continue nextTimer
} }
case timerDeleted: case timerDeleted:
@ -985,7 +944,6 @@ nextTimer:
atomic.Xadd(&pp.deletedTimers, -cdel) atomic.Xadd(&pp.deletedTimers, -cdel)
atomic.Xadd(&pp.numTimers, -cdel) atomic.Xadd(&pp.numTimers, -cdel)
atomic.Xadd(&pp.adjustTimers, -cearlier)
timers = timers[:to] timers = timers[:to]
pp.timers = timers pp.timers = timers

View file

@ -19,8 +19,8 @@ func TestTracebackArgs(t *testing.T) {
}{ }{
// simple ints // simple ints
{ {
func() int { return testTracebackArgs1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) }, func() int { return testTracebackArgs1(1, 2, 3, 4, 5) },
"testTracebackArgs1(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...)", "testTracebackArgs1(0x1, 0x2, 0x3, 0x4, 0x5)",
}, },
// some aggregates // some aggregates
{ {
@ -53,6 +53,58 @@ func TestTracebackArgs(t *testing.T) {
}, },
"testTracebackArgs5(0x0, {0x1, {}, {{}, {}}}, {}, {}, {}, {}, {}, ...)", "testTracebackArgs5(0x0, {0x1, {}, {{}, {}}}, {}, {}, {}, {}, {}, ...)",
}, },
// edge cases for ...
// no ... for 10 args
{
func() int { return testTracebackArgs6a(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) },
"testTracebackArgs6a(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa)",
},
// has ... for 11 args
{
func() int { return testTracebackArgs6b(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) },
"testTracebackArgs6b(0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...)",
},
// no ... for aggregates with 10 words
{
func() int { return testTracebackArgs7a([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) },
"testTracebackArgs7a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa})",
},
// has ... for aggregates with 11 words
{
func() int { return testTracebackArgs7b([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}) },
"testTracebackArgs7b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...})",
},
// no ... for aggregates, but with more args
{
func() int { return testTracebackArgs7c([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 11) },
"testTracebackArgs7c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}, ...)",
},
// has ... for aggregates and also for more args
{
func() int { return testTracebackArgs7d([11]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 12) },
"testTracebackArgs7d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, ...}, ...)",
},
// nested aggregates, no ...
{
func() int { return testTracebackArgs8a(testArgsType8a{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}}) },
"testTracebackArgs8a({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}})",
},
// nested aggregates, ... in inner but not outer
{
func() int { return testTracebackArgs8b(testArgsType8b{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}}) },
"testTracebackArgs8b({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}})",
},
// nested aggregates, ... in outer but not inner
{
func() int { return testTracebackArgs8c(testArgsType8c{1, 2, 3, 4, 5, 6, 7, 8, [2]int{9, 10}, 11}) },
"testTracebackArgs8c({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa}, ...})",
},
// nested aggregates, ... in both inner and outer
{
func() int { return testTracebackArgs8d(testArgsType8d{1, 2, 3, 4, 5, 6, 7, 8, [3]int{9, 10, 11}, 12}) },
"testTracebackArgs8d({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, {0x9, 0xa, ...}, ...})",
},
} }
for _, test := range tests { for _, test := range tests {
n := test.fn() n := test.fn()
@ -64,11 +116,11 @@ func TestTracebackArgs(t *testing.T) {
} }
//go:noinline //go:noinline
func testTracebackArgs1(a, b, c, d, e, f, g, h, i, j, k, l int) int { func testTracebackArgs1(a, b, c, d, e int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false) n := runtime.Stack(testTracebackArgsBuf[:], false)
if a < 0 { if a < 0 {
// use in-reg args to keep them alive // use in-reg args to keep them alive
return a + b + c + d + e + f + g + h + i + j + k + l return a + b + c + d + e
} }
return n return n
} }
@ -119,3 +171,122 @@ func testTracebackArgs5(a bool, x struct {
} }
return n return n
} }
//go:noinline
func testTracebackArgs6a(a, b, c, d, e, f, g, h, i, j int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a < 0 {
// use in-reg args to keep them alive
return a + b + c + d + e + f + g + h + i + j
}
return n
}
//go:noinline
func testTracebackArgs6b(a, b, c, d, e, f, g, h, i, j, k int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a < 0 {
// use in-reg args to keep them alive
return a + b + c + d + e + f + g + h + i + j + k
}
return n
}
//go:noinline
func testTracebackArgs7a(a [10]int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a[0] < 0 {
// use in-reg args to keep them alive
return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9]
}
return n
}
//go:noinline
func testTracebackArgs7b(a [11]int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a[0] < 0 {
// use in-reg args to keep them alive
return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10]
}
return n
}
//go:noinline
func testTracebackArgs7c(a [10]int, b int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a[0] < 0 {
// use in-reg args to keep them alive
return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + b
}
return n
}
//go:noinline
func testTracebackArgs7d(a [11]int, b int) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a[0] < 0 {
// use in-reg args to keep them alive
return a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] + a[8] + a[9] + a[10] + b
}
return n
}
type testArgsType8a struct {
a, b, c, d, e, f, g, h int
i [2]int
}
type testArgsType8b struct {
a, b, c, d, e, f, g, h int
i [3]int
}
type testArgsType8c struct {
a, b, c, d, e, f, g, h int
i [2]int
j int
}
type testArgsType8d struct {
a, b, c, d, e, f, g, h int
i [3]int
j int
}
//go:noinline
func testTracebackArgs8a(a testArgsType8a) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a.a < 0 {
// use in-reg args to keep them alive
return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1]
}
return n
}
//go:noinline
func testTracebackArgs8b(a testArgsType8b) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a.a < 0 {
// use in-reg args to keep them alive
return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2]
}
return n
}
//go:noinline
func testTracebackArgs8c(a testArgsType8c) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a.a < 0 {
// use in-reg args to keep them alive
return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.j
}
return n
}
//go:noinline
func testTracebackArgs8d(a testArgsType8d) int {
n := runtime.Stack(testTracebackArgsBuf[:], false)
if a.a < 0 {
// use in-reg args to keep them alive
return a.b + a.c + a.d + a.e + a.f + a.g + a.h + a.i[0] + a.i[1] + a.i[2] + a.j
}
return n
}

View file

@ -11,7 +11,7 @@ import "unsafe"
// tflag is documented in reflect/type.go. // tflag is documented in reflect/type.go.
// //
// tflag values must be kept in sync with copies in: // tflag values must be kept in sync with copies in:
// cmd/compile/internal/gc/reflect.go // cmd/compile/internal/reflectdata/reflect.go
// cmd/link/internal/ld/decodesym.go // cmd/link/internal/ld/decodesym.go
// reflect/type.go // reflect/type.go
// internal/reflectlite/type.go // internal/reflectlite/type.go
@ -25,7 +25,7 @@ const (
) )
// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
// ../reflect/type.go:/^type.rtype. // ../reflect/type.go:/^type.rtype.
// ../internal/reflectlite/type.go:/^type.rtype. // ../internal/reflectlite/type.go:/^type.rtype.
type _type struct { type _type struct {
@ -383,7 +383,7 @@ type maptype struct {
} }
// Note: flag values must match those used in the TMAP case // Note: flag values must match those used in the TMAP case
// in ../cmd/compile/internal/gc/reflect.go:writeType. // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
return mt.flags&1 != 0 return mt.flags&1 != 0
} }

View file

@ -233,6 +233,8 @@
// os.Exit(m.Run()) // os.Exit(m.Run())
// } // }
// //
// TestMain is a low-level primitive and should not be necessary for casual
// testing needs, where ordinary test functions suffice.
package testing package testing
import ( import (
@ -678,7 +680,11 @@ type T struct {
func (c *common) private() {} func (c *common) private() {}
// Name returns the name of the running test or benchmark. // Name returns the name of the running (sub-) test or benchmark.
//
// The name will include the name of the test along with the names of
// any nested sub-tests. If two sibling sub-tests have the same name,
// Name will append a suffix to guarantee the returned name is unique.
func (c *common) Name() string { func (c *common) Name() string {
return c.name return c.name
} }

View file

@ -23,7 +23,7 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// A source position is represented by a Position value. // Position is a value that represents a source position.
// A position is valid if Line > 0. // A position is valid if Line > 0.
type Position struct { type Position struct {
Filename string // filename, if any Filename string // filename, if any

View file

@ -527,6 +527,40 @@ func TestZeroTimer(t *testing.T) {
} }
} }
// Test that rapidly moving a timer earlier doesn't cause it to get dropped.
// Issue 47329.
func TestTimerModifiedEarlier(t *testing.T) {
past := Until(Unix(0, 0))
count := 1000
fail := 0
for i := 0; i < count; i++ {
timer := NewTimer(Hour)
for j := 0; j < 10; j++ {
if !timer.Stop() {
<-timer.C
}
timer.Reset(past)
}
deadline := NewTimer(10 * Second)
defer deadline.Stop()
now := Now()
select {
case <-timer.C:
if since := Since(now); since > 8*Second {
t.Errorf("timer took too long (%v)", since)
fail++
}
case <-deadline.C:
t.Error("deadline expired")
}
}
if fail > 0 {
t.Errorf("%d failures", fail)
}
}
// Benchmark timer latency when the thread that creates the timer is busy with // Benchmark timer latency when the thread that creates the timer is busy with
// other work and the timers must be serviced by other threads. // other work and the timers must be serviced by other threads.
// https://golang.org/issue/38860 // https://golang.org/issue/38860

View file

@ -1334,7 +1334,7 @@ func UnixMilli(msec int64) Time {
} }
// UnixMicro returns the local Time corresponding to the given Unix time, // UnixMicro returns the local Time corresponding to the given Unix time,
// usec milliseconds since January 1, 1970 UTC. // usec microseconds since January 1, 1970 UTC.
func UnixMicro(usec int64) Time { func UnixMicro(usec int64) Time {
return Unix(usec/1e6, (usec%1e6)*1e3) return Unix(usec/1e6, (usec%1e6)*1e3)
} }

View file

@ -53,7 +53,7 @@ func BenchmarkRegexpMatchEasy0_32(b *testing.B) { benchmark(b, easy0, 32<<0) }
func BenchmarkRegexpMatchEasy0_1K(b *testing.B) { benchmark(b, easy0, 1<<10) } func BenchmarkRegexpMatchEasy0_1K(b *testing.B) { benchmark(b, easy0, 1<<10) }
func BenchmarkRegexpMatchEasy1_32(b *testing.B) { benchmark(b, easy1, 32<<0) } func BenchmarkRegexpMatchEasy1_32(b *testing.B) { benchmark(b, easy1, 32<<0) }
func BenchmarkRegexpMatchEasy1_1K(b *testing.B) { benchmark(b, easy1, 1<<10) } func BenchmarkRegexpMatchEasy1_1K(b *testing.B) { benchmark(b, easy1, 1<<10) }
func BenchmarkRegexpMatchMedium_32(b *testing.B) { benchmark(b, medium, 1<<0) } func BenchmarkRegexpMatchMedium_32(b *testing.B) { benchmark(b, medium, 32<<0) }
func BenchmarkRegexpMatchMedium_1K(b *testing.B) { benchmark(b, medium, 1<<10) } func BenchmarkRegexpMatchMedium_1K(b *testing.B) { benchmark(b, medium, 1<<10) }
func BenchmarkRegexpMatchHard_32(b *testing.B) { benchmark(b, hard, 32<<0) } func BenchmarkRegexpMatchHard_32(b *testing.B) { benchmark(b, hard, 32<<0) }
func BenchmarkRegexpMatchHard_1K(b *testing.B) { benchmark(b, hard, 1<<10) } func BenchmarkRegexpMatchHard_1K(b *testing.B) { benchmark(b, hard, 1<<10) }

View file

@ -0,0 +1,9 @@
// 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 a
func F() interface{} { return struct{ _ []int }{} }
var X = F()

View file

@ -0,0 +1,9 @@
// 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 b
func F() interface{} { return struct{ _ []int }{} }
var X = F()

View file

@ -0,0 +1,19 @@
// 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
import (
"a"
"b"
)
func main() {
if a.F() == b.F() {
panic("FAIL")
}
if a.X == b.X {
panic("FAIL")
}
}

View file

@ -0,0 +1,7 @@
// rundir
// 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 ignored

Some files were not shown because too many files have changed in this diff Show more