diff options
author | Ian Lance Taylor <iant@golang.org> | 2020-07-11 12:43:49 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2020-07-11 12:43:49 -0700 |
commit | 4854d721be78358e59367982bdd94461b4be3c5a (patch) | |
tree | 8ead189e618f8ef1456c8b02c81de0cc1585d8a6 /libgo | |
parent | 3cdc95b9f8d6c90c4a279783fd3da961c5afb22c (diff) | |
parent | e109f6e438b72ef3e403162971068d28d09b82f5 (diff) | |
download | gcc-4854d721be78358e59367982bdd94461b4be3c5a.zip gcc-4854d721be78358e59367982bdd94461b4be3c5a.tar.gz gcc-4854d721be78358e59367982bdd94461b4be3c5a.tar.bz2 |
Merge from trunk revision e109f6e438b72ef3e403162971068d28d09b82f5
Diffstat (limited to 'libgo')
40 files changed, 598 insertions, 116 deletions
diff --git a/libgo/MERGE b/libgo/MERGE index 8cae45f..07547d0 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -96745b980cfde139e8611772e2bc0c59a8e6cdf7 +83b181c68bf332ac7948f145f33d128377a09c42 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index dea09de..5b18072 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -967,6 +967,12 @@ endif # Also use -fno-inline to get better results from the memory profiler. runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline +if HAVE_STATIC_LINK +# Use -static for the syscall tests if possible, because otherwise when +# running as root the re-execs ignore LD_LIBRARY_PATH. +syscall_check_GOCFLAGS = -static +endif + extra_go_files_runtime_internal_sys = version.go runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys) diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 607b88c..b2712eb 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -1104,6 +1104,10 @@ runtime_internal_sys_lo_check_GOCFLAGS = -fgo-compiling-runtime # otherwise we can't get the line numbers. # Also use -fno-inline to get better results from the memory profiler. runtime_pprof_check_GOCFLAGS = -static-libgo -fno-inline + +# Use -static for the syscall tests if possible, because otherwise when +# running as root the re-execs ignore LD_LIBRARY_PATH. +@HAVE_STATIC_LINK_TRUE@syscall_check_GOCFLAGS = -static extra_go_files_runtime_internal_sys = version.go extra_go_files_internal_cpu = cpugen.go extra_go_files_golang_org_x_sys_cpu = gcpugen.go diff --git a/libgo/VERSION b/libgo/VERSION index 864916e..d8281a2 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.14.2 +go1.14.4 diff --git a/libgo/configure b/libgo/configure index 2f78739..2a9c7e6 100755 --- a/libgo/configure +++ b/libgo/configure @@ -633,6 +633,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +HAVE_STATIC_LINK_FALSE +HAVE_STATIC_LINK_TRUE HAVE_STAT_TIMESPEC_FALSE HAVE_STAT_TIMESPEC_TRUE STRUCT_EPOLL_EVENT_FD_OFFSET @@ -11490,7 +11492,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11493 "configure" +#line 11495 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11596,7 +11598,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11599 "configure" +#line 11601 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -15788,6 +15790,44 @@ $as_echo "#define HAVE_AS_X86_AES 1" >>confdefs.h fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -static is supported" >&5 +$as_echo_n "checking whether -static is supported... " >&6; } +if ${libgo_cv_ld_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + LDFLAGS_hold=$LDFLAGS +LDFLAGS="$LDFLAGS -static" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + libgo_cv_ld_static=yes +else + libgo_cv_ld_static=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LDFLAGS=$LDFLAGS_hold +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_ld_static" >&5 +$as_echo "$libgo_cv_ld_static" >&6; } + if test "$libgo_cv_ld_static" = yes; then + HAVE_STATIC_LINK_TRUE= + HAVE_STATIC_LINK_FALSE='#' +else + HAVE_STATIC_LINK_TRUE='#' + HAVE_STATIC_LINK_FALSE= +fi + + cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -16108,6 +16148,10 @@ if test -z "${HAVE_STAT_TIMESPEC_TRUE}" && test -z "${HAVE_STAT_TIMESPEC_FALSE}" as_fn_error $? "conditional \"HAVE_STAT_TIMESPEC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${HAVE_STATIC_LINK_TRUE}" && test -z "${HAVE_STATIC_LINK_FALSE}"; then + as_fn_error $? "conditional \"HAVE_STATIC_LINK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 diff --git a/libgo/configure.ac b/libgo/configure.ac index f800d44..235d867 100644 --- a/libgo/configure.ac +++ b/libgo/configure.ac @@ -881,6 +881,17 @@ if test "x$libgo_cv_as_x86_aes" = xyes; then [Define if your assembler supports AES instructions.]) fi +dnl Test whether the linker supports the -static option. +AC_CACHE_CHECK([whether -static is supported], +[libgo_cv_ld_static], +[LDFLAGS_hold=$LDFLAGS +LDFLAGS="$LDFLAGS -static" +AC_LINK_IFELSE([AC_LANG_PROGRAM(,)], +[libgo_cv_ld_static=yes], +[libgo_cv_ld_static=no]) +LDFLAGS=$LDFLAGS_hold]) +AM_CONDITIONAL(HAVE_STATIC_LINK, test "$libgo_cv_ld_static" = yes) + AC_CACHE_SAVE if test ${multilib} = yes; then diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index 310316b..e389729 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -2082,6 +2082,10 @@ var goIdent = make(map[string]*ast.Ident) // that may contain a pointer. This is used for cgo pointer checking. var unionWithPointer = make(map[ast.Expr]bool) +// anonymousStructTag provides a consistent tag for an anonymous struct. +// The same dwarf.StructType pointer will always get the same tag. +var anonymousStructTag = make(map[*dwarf.StructType]string) + func (c *typeConv) Init(ptrSize, intSize int64) { c.ptrSize = ptrSize c.intSize = intSize @@ -2430,8 +2434,12 @@ func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Typ break } if tag == "" { - tag = "__" + strconv.Itoa(tagGen) - tagGen++ + tag = anonymousStructTag[dt] + if tag == "" { + tag = "__" + strconv.Itoa(tagGen) + tagGen++ + anonymousStructTag[dt] = tag + } } else if t.C.Empty() { t.C.Set(dt.Kind + " " + tag) } diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index b434846..b60e2bb 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -1217,6 +1217,11 @@ func (d *decodeState) unquoteBytes(s []byte) (t []byte, ok bool) { if r == -1 { return s, true } + // Only perform up to one safe unquote for each re-scanned string + // literal. In some edge cases, the decoder unquotes a literal a second + // time, even after another literal has been re-scanned. Thus, only the + // first unquote can safely use safeUnquote. + d.safeUnquote = 0 b := make([]byte, len(s)+2*utf8.UTFMax) w := copy(b, s[0:r]) diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index 498bd97..a49181e 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -2419,7 +2419,7 @@ func (m *textUnmarshalerString) UnmarshalText(text []byte) error { return nil } -// Test unmarshal to a map, with map key is a user defined type. +// Test unmarshal to a map, where the map key is a user defined type. // See golang.org/issues/34437. func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) { var p map[textUnmarshalerString]string @@ -2428,6 +2428,35 @@ func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) { } if _, ok := p["foo"]; !ok { - t.Errorf(`Key "foo" is not existed in map: %v`, p) + t.Errorf(`Key "foo" does not exist in map: %v`, p) + } +} + +func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) { + // See golang.org/issues/38105. + var p map[textUnmarshalerString]string + if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil { + t.Fatalf("Unmarshal unexpected error: %v", err) + } + if _, ok := p["开源"]; !ok { + t.Errorf(`Key "开源" does not exist in map: %v`, p) + } + + // See golang.org/issues/38126. + type T struct { + F1 string `json:"F1,string"` + } + t1 := T{"aaa\tbbb"} + + b, err := Marshal(t1) + if err != nil { + t.Fatalf("Marshal unexpected error: %v", err) + } + var t2 T + if err := Unmarshal(b, &t2); err != nil { + t.Fatalf("Unmarshal unexpected error: %v", err) + } + if t1 != t2 { + t.Errorf("Marshal and Unmarshal roundtrip mismatch: want %q got %q", t1, t2) } } diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index 39cdaeb..b351cf3 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -635,11 +635,12 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { return } if opts.quoted { - b := make([]byte, 0, v.Len()+2) - b = append(b, '"') - b = append(b, []byte(v.String())...) - b = append(b, '"') - e.stringBytes(b, opts.escapeHTML) + e2 := newEncodeState() + // Since we encode the string twice, we only need to escape HTML + // the first time. + e2.string(v.String(), opts.escapeHTML) + e.stringBytes(e2.Bytes(), false) + encodeStatePool.Put(e2) } else { e.string(v.String(), opts.escapeHTML) } diff --git a/libgo/go/encoding/json/encode_test.go b/libgo/go/encoding/json/encode_test.go index 5110c7d..7290eca 100644 --- a/libgo/go/encoding/json/encode_test.go +++ b/libgo/go/encoding/json/encode_test.go @@ -79,37 +79,66 @@ type StringTag struct { NumberStr Number `json:",string"` } -var stringTagExpected = `{ - "BoolStr": "true", - "IntStr": "42", - "UintptrStr": "44", - "StrStr": "\"xzbit\"", - "NumberStr": "46" -}` - -func TestStringTag(t *testing.T) { - var s StringTag - s.BoolStr = true - s.IntStr = 42 - s.UintptrStr = 44 - s.StrStr = "xzbit" - s.NumberStr = "46" - got, err := MarshalIndent(&s, "", " ") - if err != nil { - t.Fatal(err) - } - if got := string(got); got != stringTagExpected { - t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected) +func TestRoundtripStringTag(t *testing.T) { + tests := []struct { + name string + in StringTag + want string // empty to just test that we roundtrip + }{ + { + name: "AllTypes", + in: StringTag{ + BoolStr: true, + IntStr: 42, + UintptrStr: 44, + StrStr: "xzbit", + NumberStr: "46", + }, + want: `{ + "BoolStr": "true", + "IntStr": "42", + "UintptrStr": "44", + "StrStr": "\"xzbit\"", + "NumberStr": "46" + }`, + }, + { + // See golang.org/issues/38173. + name: "StringDoubleEscapes", + in: StringTag{ + StrStr: "\b\f\n\r\t\"\\", + NumberStr: "0", // just to satisfy the roundtrip + }, + want: `{ + "BoolStr": "false", + "IntStr": "0", + "UintptrStr": "0", + "StrStr": "\"\\u0008\\u000c\\n\\r\\t\\\"\\\\\"", + "NumberStr": "0" + }`, + }, } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Indent with a tab prefix to make the multi-line string + // literals in the table nicer to read. + got, err := MarshalIndent(&test.in, "\t\t\t", "\t") + if err != nil { + t.Fatal(err) + } + if got := string(got); got != test.want { + t.Fatalf(" got: %s\nwant: %s\n", got, test.want) + } - // Verify that it round-trips. - var s2 StringTag - err = NewDecoder(bytes.NewReader(got)).Decode(&s2) - if err != nil { - t.Fatalf("Decode: %v", err) - } - if !reflect.DeepEqual(s, s2) { - t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2) + // Verify that it round-trips. + var s2 StringTag + if err := Unmarshal(got, &s2); err != nil { + t.Fatalf("Decode: %v", err) + } + if !reflect.DeepEqual(test.in, s2) { + t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", test.in, string(got), s2) + } + }) } } diff --git a/libgo/go/encoding/json/stream_test.go b/libgo/go/encoding/json/stream_test.go index ebb4f23..c9e5334 100644 --- a/libgo/go/encoding/json/stream_test.go +++ b/libgo/go/encoding/json/stream_test.go @@ -144,14 +144,15 @@ func TestEncoderSetEscapeHTML(t *testing.T) { }, { "stringOption", stringOption, - `{"bar":"\"\u003chtml\u003efoobar\u003c/html\u003e\""}`, + `{"bar":"\"\\u003chtml\\u003efoobar\\u003c/html\\u003e\""}`, `{"bar":"\"<html>foobar</html>\""}`, }, } { var buf bytes.Buffer enc := NewEncoder(&buf) if err := enc.Encode(tt.v); err != nil { - t.Fatalf("Encode(%s): %s", tt.name, err) + t.Errorf("Encode(%s): %s", tt.name, err) + continue } if got := strings.TrimSpace(buf.String()); got != tt.wantEscape { t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape) @@ -159,7 +160,8 @@ func TestEncoderSetEscapeHTML(t *testing.T) { buf.Reset() enc.SetEscapeHTML(false) if err := enc.Encode(tt.v); err != nil { - t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err) + t.Errorf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err) + continue } if got := strings.TrimSpace(buf.String()); got != tt.want { t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q", diff --git a/libgo/go/go/doc/example.go b/libgo/go/go/doc/example.go index a010d3a..ebf8118 100644 --- a/libgo/go/go/doc/example.go +++ b/libgo/go/go/doc/example.go @@ -62,9 +62,6 @@ func Examples(testFiles ...*ast.File) []*Example { if !ok || f.Recv != nil { continue } - if params := f.Type.Params; len(params.List) != 0 { - continue // function has params; not a valid example - } numDecl++ name := f.Name.Name if isTest(name, "Test") || isTest(name, "Benchmark") { @@ -74,6 +71,9 @@ func Examples(testFiles ...*ast.File) []*Example { if !isTest(name, "Example") { continue } + if params := f.Type.Params; len(params.List) != 0 { + continue // function has params; not a valid example + } if f.Body == nil { // ast.File.Body nil dereference (see issue 28044) continue } diff --git a/libgo/go/go/doc/example_test.go b/libgo/go/go/doc/example_test.go index cd2f469..32db3cd 100644 --- a/libgo/go/go/doc/example_test.go +++ b/libgo/go/go/doc/example_test.go @@ -331,25 +331,65 @@ func main() { } ` +const exampleWholeFileFunction = `package foo_test + +func Foo(x int) { +} + +func Example() { + fmt.Println("Hello, world!") + // Output: Hello, world! +} +` + +const exampleWholeFileFunctionOutput = `package main + +func Foo(x int) { +} + +func main() { + fmt.Println("Hello, world!") +} +` + +var exampleWholeFileTestCases = []struct { + Title, Source, Play, Output string +}{ + { + "Methods", + exampleWholeFile, + exampleWholeFileOutput, + "Hello, world!\n", + }, + { + "Function", + exampleWholeFileFunction, + exampleWholeFileFunctionOutput, + "Hello, world!\n", + }, +} + func TestExamplesWholeFile(t *testing.T) { - fset := token.NewFileSet() - file, err := parser.ParseFile(fset, "test.go", strings.NewReader(exampleWholeFile), parser.ParseComments) - if err != nil { - t.Fatal(err) - } - es := doc.Examples(file) - if len(es) != 1 { - t.Fatalf("wrong number of examples; got %d want 1", len(es)) - } - e := es[0] - if e.Name != "" { - t.Errorf("got Name == %q, want %q", e.Name, "") - } - if g, w := formatFile(t, fset, e.Play), exampleWholeFileOutput; g != w { - t.Errorf("got Play == %q, want %q", g, w) - } - if g, w := e.Output, "Hello, world!\n"; g != w { - t.Errorf("got Output == %q, want %q", g, w) + for _, c := range exampleWholeFileTestCases { + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, "test.go", strings.NewReader(c.Source), parser.ParseComments) + if err != nil { + t.Fatal(err) + } + es := doc.Examples(file) + if len(es) != 1 { + t.Fatalf("%s: wrong number of examples; got %d want 1", c.Title, len(es)) + } + e := es[0] + if e.Name != "" { + t.Errorf("%s: got Name == %q, want %q", c.Title, e.Name, "") + } + if g, w := formatFile(t, fset, e.Play), c.Play; g != w { + t.Errorf("%s: got Play == %q, want %q", c.Title, g, w) + } + if g, w := e.Output, c.Output; g != w { + t.Errorf("%s: got Output == %q, want %q", c.Title, g, w) + } } } diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go index 500c98d..54f9d7b 100644 --- a/libgo/go/go/parser/interface.go +++ b/libgo/go/go/parser/interface.go @@ -133,13 +133,7 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) // first error encountered are returned. // func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) { - fd, err := os.Open(path) - if err != nil { - return nil, err - } - defer fd.Close() - - list, err := fd.Readdir(-1) + list, err := ioutil.ReadDir(path) if err != nil { return nil, err } diff --git a/libgo/go/golang.org/x/sys/cpu/byteorder.go b/libgo/go/golang.org/x/sys/cpu/byteorder.go index da6b9e4..74116e9 100644 --- a/libgo/go/golang.org/x/sys/cpu/byteorder.go +++ b/libgo/go/golang.org/x/sys/cpu/byteorder.go @@ -14,15 +14,20 @@ import ( func hostByteOrder() binary.ByteOrder { switch runtime.GOARCH { case "386", "amd64", "amd64p32", + "alpha", "arm", "arm64", "mipsle", "mips64le", "mips64p32le", + "nios2", "ppc64le", - "riscv", "riscv64": + "riscv", "riscv64", + "sh": return binary.LittleEndian case "armbe", "arm64be", + "m68k", "mips", "mips64", "mips64p32", "ppc", "ppc64", "s390", "s390x", + "shbe", "sparc", "sparc64": return binary.BigEndian } diff --git a/libgo/go/golang.org/x/sys/cpu/cpu_aix_ppc64.go b/libgo/go/golang.org/x/sys/cpu/cpu_aix.go index b0ede11..02d0312 100644 --- a/libgo/go/golang.org/x/sys/cpu/cpu_aix_ppc64.go +++ b/libgo/go/golang.org/x/sys/cpu/cpu_aix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build aix,ppc64 +// +build aix package cpu diff --git a/libgo/go/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/libgo/go/golang.org/x/sys/cpu/syscall_aix_gccgo.go new file mode 100644 index 0000000..2609cc4 --- /dev/null +++ b/libgo/go/golang.org/x/sys/cpu/syscall_aix_gccgo.go @@ -0,0 +1,27 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Recreate a getsystemcfg syscall handler instead of +// using the one provided by x/sys/unix to avoid having +// the dependency between them. (See golang.org/issue/32102) +// Morover, this file will be used during the building of +// gccgo's libgo and thus must not use a CGo method. + +// +build aix +// +build gccgo + +package cpu + +import ( + "syscall" +) + +//extern getsystemcfg +func gccgoGetsystemcfg(label uint32) (r uint64) + +func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { + r1 = uintptr(gccgoGetsystemcfg(uint32(label))) + e1 = syscall.GetErrno() + return +} diff --git a/libgo/go/internal/syscall/unix/getrandom_linux_generic.go b/libgo/go/internal/syscall/unix/getrandom_linux_generic.go index 0c79ae5..007e769 100644 --- a/libgo/go/internal/syscall/unix/getrandom_linux_generic.go +++ b/libgo/go/internal/syscall/unix/getrandom_linux_generic.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build linux -// +build arm64 arm64be nios2 riscv64 +// +build arm64 arm64be nios2 riscv riscv64 package unix diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go index 1b771ca..c31ec51 100644 --- a/libgo/go/math/big/nat.go +++ b/libgo/go/math/big/nat.go @@ -740,7 +740,8 @@ func (z nat) divLarge(u, uIn, vIn nat) (q, r nat) { // The remainder overwrites input u. // // Precondition: -// - len(q) >= len(u)-len(v) +// - q is large enough to hold the quotient u / v +// which has a maximum length of len(u)-len(v)+1. func (q nat) divBasic(u, v nat) { n := len(v) m := len(u) - n @@ -779,6 +780,8 @@ func (q nat) divBasic(u, v nat) { } // D4. + // Compute the remainder u - (q̂*v) << (_W*j). + // The subtraction may overflow if q̂ estimate was off by one. qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0) qhl := len(qhatv) if j+qhl > len(u) && qhatv[n] == 0 { @@ -787,7 +790,11 @@ func (q nat) divBasic(u, v nat) { c := subVV(u[j:j+qhl], u[j:], qhatv) if c != 0 { c := addVV(u[j:j+n], u[j:], v) - u[j+n] += c + // If n == qhl, the carry from subVV and the carry from addVV + // cancel out and don't affect u[j+n]. + if n < qhl { + u[j+n] += c + } qhat-- } @@ -827,6 +834,10 @@ func (z nat) divRecursive(u, v nat) { putNat(tmp) } +// divRecursiveStep computes the division of u by v. +// - z must be large enough to hold the quotient +// - the quotient will overwrite z +// - the remainder will overwrite u func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { u = u.norm() v = v.norm() diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go index 32f29e3..89e913f 100644 --- a/libgo/go/math/big/nat_test.go +++ b/libgo/go/math/big/nat_test.go @@ -786,3 +786,21 @@ func TestNatDiv(t *testing.T) { } } } + +// TestIssue37499 triggers the edge case of divBasic where +// the inaccurate estimate of the first word's quotient +// happens at the very beginning of the loop. +func TestIssue37499(t *testing.T) { + // Choose u and v such that v is slightly larger than u >> N. + // This tricks divBasic into choosing 1 as the first word + // of the quotient. This works in both 32-bit and 64-bit settings. + u := natFromString("0x2b6c385a05be027f5c22005b63c42a1165b79ff510e1706b39f8489c1d28e57bb5ba4ef9fd9387a3e344402c0a453381") + v := natFromString("0x2b6c385a05be027f5c22005b63c42a1165b79ff510e1706c") + + q := nat(nil).make(8) + q.divBasic(u, v) + q = q.norm() + if s := string(q.utoa(16)); s != "fffffffffffffffffffffffffffffffffffffffffffffffb" { + t.Fatalf("incorrect quotient: %s", s) + } +} diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index a19b46d..8ec6de7 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -2450,3 +2450,38 @@ func TestDirSeek(t *testing.T) { } } } + +// Test that opening a file does not change its permissions. Issue 38225. +func TestOpenFileKeepsPermissions(t *testing.T) { + t.Parallel() + dir, err := ioutil.TempDir("", "TestOpenFileKeepsPermissions") + if err != nil { + t.Fatal(err) + } + defer RemoveAll(dir) + name := filepath.Join(dir, "x") + f, err := Create(name) + if err != nil { + t.Fatal(err) + } + if err := f.Close(); err != nil { + t.Error(err) + } + f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0) + if err != nil { + t.Fatal(err) + } + if fi, err := f.Stat(); err != nil { + t.Error(err) + } else if fi.Mode()&0222 == 0 { + t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode()) + } + if err := f.Close(); err != nil { + t.Error(err) + } + if fi, err := Stat(name); err != nil { + t.Error(err) + } else if fi.Mode()&0222 == 0 { + t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode()) + } +} diff --git a/libgo/go/runtime/callers_test.go b/libgo/go/runtime/callers_test.go index 26a6f3a..1fc7f86 100644 --- a/libgo/go/runtime/callers_test.go +++ b/libgo/go/runtime/callers_test.go @@ -67,7 +67,7 @@ func testCallers(t *testing.T, pcs []uintptr, pan bool) { } } -func testCallersEqual(t *testing.T, pcs []uintptr, want []string) { +func testCallersEqual(t *testing.T, pcs []uintptr, want []string, ignore map[string]struct{}) { got := make([]string, 0, len(want)) frames := runtime.CallersFrames(pcs) @@ -76,7 +76,9 @@ func testCallersEqual(t *testing.T, pcs []uintptr, want []string) { if !more || len(got) >= len(want) { break } - got = append(got, frame.Function) + if _, ok := ignore[frame.Function]; !ok { + got = append(got, frame.Function) + } } if !reflect.DeepEqual(want, got) { t.Fatalf("wanted %v, got %v", want, got) @@ -106,7 +108,7 @@ func TestCallersPanic(t *testing.T) { pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] testCallers(t, pcs, true) - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) }() f1(true) } @@ -128,7 +130,7 @@ func TestCallersDoublePanic(t *testing.T) { if recover() == nil { t.Fatal("did not panic") } - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) }() if recover() == nil { t.Fatal("did not panic") @@ -149,7 +151,7 @@ func TestCallersAfterRecovery(t *testing.T) { defer func() { pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) }() defer func() { if recover() == nil { @@ -177,7 +179,7 @@ func TestCallersAbortedPanic(t *testing.T) { // recovered, there is no remaining panic on the stack. pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) }() defer func() { r := recover() @@ -208,7 +210,7 @@ func TestCallersAbortedPanic2(t *testing.T) { defer func() { pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) }() func() { defer func() { @@ -233,10 +235,16 @@ func TestCallersNilPointerPanic(t *testing.T) { want := []string{"runtime.Callers", "runtime_test.TestCallersNilPointerPanic.func1", "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic", "runtime_test.TestCallersNilPointerPanic"} + ign := make(map[string]struct{}) if runtime.Compiler == "gccgo" { + // The expected results of gollvm and gccgo are slightly different, the result + // of gccgo does not contain tRunner, and the result of gollvm does not contain + // sigpanic. Make these two elementes optional to pass both of gollvm and gccgo. want = []string{"runtime.Callers", "runtime_test.TestCallersNilPointerPanic..func1", - "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic", + "runtime.gopanic", "runtime.panicmem", "runtime_test.TestCallersNilPointerPanic"} + ign["runtime.sigpanic"] = struct{}{} + ign["testing.tRunner"] = struct{}{} } defer func() { @@ -245,7 +253,7 @@ func TestCallersNilPointerPanic(t *testing.T) { } pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, ign) }() var p *int if *p == 3 { @@ -271,7 +279,7 @@ func TestCallersDivZeroPanic(t *testing.T) { } pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) }() var n int if 5/n == 1 { @@ -298,7 +306,7 @@ func TestCallersDeferNilFuncPanic(t *testing.T) { } pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) if state == 1 { t.Fatal("nil defer func panicked at defer time rather than function exit time") } @@ -328,7 +336,7 @@ func TestCallersDeferNilFuncPanicWithLoop(t *testing.T) { } pcs := make([]uintptr, 20) pcs = pcs[:runtime.Callers(0, pcs)] - testCallersEqual(t, pcs, want) + testCallersEqual(t, pcs, want, nil) if state == 1 { t.Fatal("nil defer func panicked at defer time rather than function exit time") } diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go index 6268f2e..aa97cf7 100644 --- a/libgo/go/runtime/crash_test.go +++ b/libgo/go/runtime/crash_test.go @@ -55,6 +55,16 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string { t.Fatal(err) } + return runBuiltTestProg(t, exe, name, env...) +} + +func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string { + if *flagQuick { + t.Skip("-quick") + } + + testenv.MustHaveGoBuild(t) + cmd := testenv.CleanCmdEnv(exec.Command(exe, name)) cmd.Env = append(cmd.Env, env...) if testing.Short() { @@ -64,7 +74,7 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string { cmd.Stdout = &b cmd.Stderr = &b if err := cmd.Start(); err != nil { - t.Fatalf("starting %s %s: %v", binary, name, err) + t.Fatalf("starting %s %s: %v", exe, name, err) } // If the process doesn't complete within 1 minute, @@ -92,7 +102,7 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string { }() if err := cmd.Wait(); err != nil { - t.Logf("%s %s exit status: %v", binary, name, err) + t.Logf("%s %s exit status: %v", exe, name, err) } close(done) diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go index 6595faf..ab74e34 100644 --- a/libgo/go/runtime/export_test.go +++ b/libgo/go/runtime/export_test.go @@ -866,7 +866,7 @@ func FreePageAlloc(pp *PageAlloc) { // // This should not be higher than 0x100*pallocChunkBytes to support // mips and mipsle, which only have 31-bit address spaces. -var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + 0x0a00000000000000*sys.GoosAix)) +var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + 0x0a00000000000000*sys.GoosAix*sys.GoarchPpc64)) // PageBase returns an address given a chunk index and a page index // relative to that chunk. diff --git a/libgo/go/runtime/malloc.go b/libgo/go/runtime/malloc.go index 266f5eb..6df7eaa 100644 --- a/libgo/go/runtime/malloc.go +++ b/libgo/go/runtime/malloc.go @@ -312,7 +312,7 @@ const ( // // On other platforms, the user address space is contiguous // and starts at 0, so no offset is necessary. - arenaBaseOffset = sys.GoarchAmd64*(1<<47) + (^0x0a00000000000000+1)&uintptrMask*sys.GoosAix + arenaBaseOffset = sys.GoarchAmd64*(1<<47) + (^0x0a00000000000000+1)&uintptrMask*sys.GoosAix*sys.GoarchPpc64 // Max number of threads to run garbage collection. // 2, 3, and 4 are all plausible maximums depending diff --git a/libgo/go/runtime/mgcscavenge.go b/libgo/go/runtime/mgcscavenge.go index 3b60b3d..d4b527c 100644 --- a/libgo/go/runtime/mgcscavenge.go +++ b/libgo/go/runtime/mgcscavenge.go @@ -288,6 +288,28 @@ func bgscavenge(c chan int) { continue } + if released < physPageSize { + // If this happens, it means that we may have attempted to release part + // of a physical page, but the likely effect of that is that it released + // the whole physical page, some of which may have still been in-use. + // This could lead to memory corruption. Throw. + throw("released less than one physical page of memory") + } + + // On some platforms we may see crit as zero if the time it takes to scavenge + // memory is less than the minimum granularity of its clock (e.g. Windows). + // In this case, just assume scavenging takes 10 µs per regular physical page + // (determined empirically), and conservatively ignore the impact of huge pages + // on timing. + // + // We shouldn't ever see a crit value less than zero unless there's a bug of + // some kind, either on our side or in the platform we're running on, but be + // defensive in that case as well. + const approxCritNSPerPhysicalPage = 10e3 + if crit <= 0 { + crit = approxCritNSPerPhysicalPage * float64(released/physPageSize) + } + // Multiply the critical time by 1 + the ratio of the costs of using // scavenged memory vs. scavenging memory. This forces us to pay down // the cost of reusing this memory eagerly by sleeping for a longer period diff --git a/libgo/go/runtime/mpagecache.go b/libgo/go/runtime/mpagecache.go index 9fc338b..a074961 100644 --- a/libgo/go/runtime/mpagecache.go +++ b/libgo/go/runtime/mpagecache.go @@ -148,9 +148,14 @@ func (s *pageAlloc) allocToCache() pageCache { // Update as an allocation, but note that it's not contiguous. s.update(c.base, pageCachePages, false, true) - // We're always searching for the first free page, and we always know the - // up to pageCache size bits will be allocated, so we can always move the - // searchAddr past the cache. - s.searchAddr = c.base + pageSize*pageCachePages + // Set the search address to the last page represented by the cache. + // Since all of the pages in this block are going to the cache, and we + // searched for the first free page, we can confidently start at the + // next page. + // + // However, s.searchAddr is not allowed to point into unmapped heap memory + // unless it is maxSearchAddr, so make it the last page as opposed to + // the page after. + s.searchAddr = c.base + pageSize*(pageCachePages-1) return c } diff --git a/libgo/go/runtime/mpagecache_test.go b/libgo/go/runtime/mpagecache_test.go index b8cc0bd..2ed0c0a 100644 --- a/libgo/go/runtime/mpagecache_test.go +++ b/libgo/go/runtime/mpagecache_test.go @@ -260,12 +260,13 @@ func TestPageAllocAllocToCache(t *testing.T) { if GOOS == "openbsd" && testing.Short() { t.Skip("skipping because virtual memory is limited; see #36210") } - tests := map[string]struct { + type test struct { before map[ChunkIdx][]BitRange scav map[ChunkIdx][]BitRange hits []PageCache // expected base addresses and patterns after map[ChunkIdx][]BitRange - }{ + } + tests := map[string]test{ "AllFree": { before: map[ChunkIdx][]BitRange{ BaseChunkIdx: {}, @@ -349,6 +350,34 @@ func TestPageAllocAllocToCache(t *testing.T) { }, }, } + if PageAlloc64Bit != 0 { + const chunkIdxBigJump = 0x100000 // chunk index offset which translates to O(TiB) + + // This test is similar to the one with the same name for + // pageAlloc.alloc and serves the same purpose. + // See mpagealloc_test.go for details. + sumsPerPhysPage := ChunkIdx(PhysPageSize / PallocSumBytes) + baseChunkIdx := BaseChunkIdx &^ (sumsPerPhysPage - 1) + tests["DiscontiguousMappedSumBoundary"] = test{ + before: map[ChunkIdx][]BitRange{ + baseChunkIdx + sumsPerPhysPage - 1: {{0, PallocChunkPages - 1}}, + baseChunkIdx + chunkIdxBigJump: {{1, PallocChunkPages - 1}}, + }, + scav: map[ChunkIdx][]BitRange{ + baseChunkIdx + sumsPerPhysPage - 1: {}, + baseChunkIdx + chunkIdxBigJump: {}, + }, + hits: []PageCache{ + NewPageCache(PageBase(baseChunkIdx+sumsPerPhysPage-1, PallocChunkPages-64), 1<<63, 0), + NewPageCache(PageBase(baseChunkIdx+chunkIdxBigJump, 0), 1, 0), + NewPageCache(0, 0, 0), + }, + after: map[ChunkIdx][]BitRange{ + baseChunkIdx + sumsPerPhysPage - 1: {{0, PallocChunkPages}}, + baseChunkIdx + chunkIdxBigJump: {{0, PallocChunkPages}}, + }, + } + } for name, v := range tests { v := v t.Run(name, func(t *testing.T) { diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go index 7c3d41f..69d2c71 100644 --- a/libgo/go/runtime/os_netbsd.go +++ b/libgo/go/runtime/os_netbsd.go @@ -68,9 +68,9 @@ func semasleep(ns int64) int32 { } for { - v := atomic.Load(&_g_.m.mos.waitsemacount) + v := atomic.Load(&_g_.m.waitsemacount) if v > 0 { - if atomic.Cas(&_g_.m.mos.waitsemacount, v, v-1) { + if atomic.Cas(&_g_.m.waitsemacount, v, v-1) { return 0 // semaphore acquired } continue @@ -96,15 +96,15 @@ func semasleep(ns int64) int32 { //go:nosplit func semawakeup(mp *m) { - atomic.Xadd(&mp.mos.waitsemacount, 1) + atomic.Xadd(&mp.waitsemacount, 1) // From NetBSD's _lwp_unpark(2) manual: // "If the target LWP is not currently waiting, it will return // immediately upon the next call to _lwp_park()." - ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.mos.waitsemacount)) + ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount)) if ret != 0 && ret != _ESRCH { // semawakeup can be called on signal stack. systemstack(func() { - print("thrwakeup addr=", &mp.mos.waitsemacount, " sem=", mp.mos.waitsemacount, " ret=", ret, "\n") + print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n") }) } } @@ -115,3 +115,34 @@ func osinit() { physPageSize = getPageSize() } } + +func sysargs(argc int32, argv **byte) { + n := argc + 1 + + // skip over argv, envp to get to auxv + for argv_index(argv, n) != nil { + n++ + } + + // skip NULL separator + n++ + + // now argv+n is auxv + auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) + sysauxv(auxv[:]) +} + +const ( + _AT_NULL = 0 // Terminates the vector + _AT_PAGESZ = 6 // Page size in bytes +) + +func sysauxv(auxv []uintptr) { + for i := 0; auxv[i] != _AT_NULL; i += 2 { + tag, val := auxv[i], auxv[i+1] + switch tag { + case _AT_PAGESZ: + physPageSize = val + } + } +} diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index f75cacf..e098137 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -1704,10 +1704,16 @@ func startTemplateThread() { if GOARCH == "wasm" { // no threads on wasm yet return } + + // Disable preemption to guarantee that the template thread will be + // created before a park once haveTemplateThread is set. + mp := acquirem() if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) { + releasem(mp) return } newm(templateThread, nil) + releasem(mp) } // templateThread is a thread in a known-good state that exists solely diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go index a693937..5f96d64 100644 --- a/libgo/go/runtime/proc_test.go +++ b/libgo/go/runtime/proc_test.go @@ -6,6 +6,7 @@ package runtime_test import ( "fmt" + "internal/testenv" "math" "net" "runtime" @@ -930,6 +931,29 @@ func TestLockOSThreadAvoidsStatePropagation(t *testing.T) { } } +func TestLockOSThreadTemplateThreadRace(t *testing.T) { + testenv.MustHaveGoRun(t) + + exe, err := buildTestProg(t, "testprog") + if err != nil { + t.Fatal(err) + } + + iterations := 100 + if testing.Short() { + // Reduce run time to ~100ms, with much lower probability of + // catching issues. + iterations = 5 + } + for i := 0; i < iterations; i++ { + want := "OK\n" + output := runBuiltTestProg(t, exe, "LockOSThreadTemplateThreadRace") + if output != want { + t.Fatalf("run %d: want %q, got %q", i, want, output) + } + } +} + // fakeSyscall emulates a system call. //go:nosplit func fakeSyscall(duration time.Duration) { diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go index 6f362fc..c555712 100644 --- a/libgo/go/runtime/signal_gccgo.go +++ b/libgo/go/runtime/signal_gccgo.go @@ -60,7 +60,7 @@ type sigctxt struct { } func (c *sigctxt) sigcode() uint64 { - return uint64(c.info.si_code) + return uint64(getSiginfoCode(c.info)) } //go:nosplit diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go index 4a06da5..25b1836 100644 --- a/libgo/go/runtime/stubs.go +++ b/libgo/go/runtime/stubs.go @@ -297,6 +297,10 @@ func getSigactionHandler(*_sigaction) uintptr //go:noescape func setSigactionHandler(*_sigaction, uintptr) +// Get signal code, written in C. +//go:noescape +func getSiginfoCode(*_siginfo_t) uintptr + // Retrieve fields from the siginfo_t and ucontext_t pointers passed // to a signal handler using C, as they are often hidden in a union. // Returns and, if available, PC where signal occurred. diff --git a/libgo/go/runtime/testdata/testprog/lockosthread.go b/libgo/go/runtime/testdata/testprog/lockosthread.go index fd3123e..098cc4d 100644 --- a/libgo/go/runtime/testdata/testprog/lockosthread.go +++ b/libgo/go/runtime/testdata/testprog/lockosthread.go @@ -7,6 +7,7 @@ package main import ( "os" "runtime" + "sync" "time" ) @@ -30,6 +31,7 @@ func init() { runtime.LockOSThread() }) register("LockOSThreadAvoidsStatePropagation", LockOSThreadAvoidsStatePropagation) + register("LockOSThreadTemplateThreadRace", LockOSThreadTemplateThreadRace) } func LockOSThreadMain() { @@ -195,3 +197,50 @@ func LockOSThreadAvoidsStatePropagation() { runtime.UnlockOSThread() println("OK") } + +func LockOSThreadTemplateThreadRace() { + // This test attempts to reproduce the race described in + // golang.org/issue/38931. To do so, we must have a stop-the-world + // (achieved via ReadMemStats) racing with two LockOSThread calls. + // + // While this test attempts to line up the timing, it is only expected + // to fail (and thus hang) around 2% of the time if the race is + // present. + + // Ensure enough Ps to actually run everything in parallel. Though on + // <4 core machines, we are still at the whim of the kernel scheduler. + runtime.GOMAXPROCS(4) + + go func() { + // Stop the world; race with LockOSThread below. + var m runtime.MemStats + for { + runtime.ReadMemStats(&m) + } + }() + + // Try to synchronize both LockOSThreads. + start := time.Now().Add(10*time.Millisecond) + + var wg sync.WaitGroup + wg.Add(2) + + for i := 0; i < 2; i++ { + go func() { + for time.Now().Before(start) { + } + + // Add work to the local runq to trigger early startm + // in handoffp. + go func(){}() + + runtime.LockOSThread() + runtime.Gosched() // add a preemption point. + wg.Done() + }() + } + + wg.Wait() + // If both LockOSThreads completed then we did not hit the race. + println("OK") +} diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go index 97059c8..c12df4c 100644 --- a/libgo/go/syscall/syscall_linux_test.go +++ b/libgo/go/syscall/syscall_linux_test.go @@ -187,7 +187,7 @@ func TestLinuxDeathSignal(t *testing.T) { } cmd := exec.Command(tmpBinary) - cmd.Env = []string{"GO_DEATHSIG_PARENT=1"} + cmd.Env = append(os.Environ(), "GO_DEATHSIG_PARENT=1") chldStdin, err := cmd.StdinPipe() if err != nil { t.Fatalf("failed to create new stdin pipe: %v", err) @@ -225,7 +225,10 @@ func TestLinuxDeathSignal(t *testing.T) { func deathSignalParent() { cmd := exec.Command(os.Args[0]) - cmd.Env = []string{"GO_DEATHSIG_CHILD=1"} + cmd.Env = append(os.Environ(), + "GO_DEATHSIG_PARENT=", + "GO_DEATHSIG_CHILD=1", + ) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout attrs := syscall.SysProcAttr{ @@ -360,7 +363,7 @@ func TestSyscallNoError(t *testing.T) { } cmd := exec.Command(tmpBinary) - cmd.Env = []string{"GO_SYSCALL_NOERROR=1"} + cmd.Env = append(os.Environ(), "GO_SYSCALL_NOERROR=1") out, err := cmd.CombinedOutput() if err != nil { diff --git a/libgo/misc/cgo/test/testx.go b/libgo/misc/cgo/test/testx.go index 42979b5..eb9d7fa 100644 --- a/libgo/misc/cgo/test/testx.go +++ b/libgo/misc/cgo/test/testx.go @@ -124,6 +124,11 @@ typedef struct { } Issue31891B; void callIssue31891(void); + +typedef struct { + int i; +} Issue38408, *PIssue38408; + */ import "C" @@ -552,3 +557,8 @@ func useIssue31891B(c *C.Issue31891B) {} func test31891(t *testing.T) { C.callIssue31891() } + +// issue 38408 +// A typedef pointer can be used as the element type. +// No runtime test; just make sure it compiles. +var _ C.PIssue38408 = &C.Issue38408{i: 1} diff --git a/libgo/runtime/aeshash.c b/libgo/runtime/aeshash.c index 00658d7..93f28fd 100644 --- a/libgo/runtime/aeshash.c +++ b/libgo/runtime/aeshash.c @@ -596,7 +596,7 @@ uintptr aeshashbody(void* p, uintptr seed, uintptr size, Slice aeskeysched) { uintptr aeshashbody(void* p, uintptr seed, uintptr size, Slice aeskeysched) { uint8x16_t *pseed; - uint32x4_t vinit32; + uint64x2_t vinit64; uint8x16_t vinit; uint8x16_t vseed, vseed2, vseed3, vseed4; uint8x16_t vseed5, vseed6, vseed7, vseed8; @@ -610,10 +610,10 @@ uintptr aeshashbody(void* p, uintptr seed, uintptr size, Slice aeskeysched) { pseed = (uint8x16_t*)(aeskeysched.__values); // Combined hash seed and length. - vinit32 = vdupq_n_u32(0); - vinit32[0] = (uint32)seed; - vinit32[1] = (uint32)size; - vinit = vreinterpretq_u8_u32(vinit32); + vinit64 = vdupq_n_u64(0); + vinit64[0] = (uint64)seed; + vinit64[1] = (uint64)size; + vinit = vreinterpretq_u8_u64(vinit64); // Mix in per-process seed. vseed = vaeseq_u8(*pseed, vinit); @@ -626,7 +626,7 @@ uintptr aeshashbody(void* p, uintptr seed, uintptr size, Slice aeskeysched) { // Return 64 bits of scrambled input seed. return vreinterpretq_u64_u8(vseed)[0]; } else if (size < 16) { - vval = vreinterpretq_u8_u32(vdupq_n_u32(0)); + vval = vreinterpretq_u8_u64(vdupq_n_u64(0)); if ((size & 8) != 0) { vval = vreinterpretq_u8_u64(vld1q_lane_u64((uint64_t*)(p), vreinterpretq_u64_u8(vval), 0)); p = (void*)((uint64_t*)(p) + 1); diff --git a/libgo/runtime/go-signal.c b/libgo/runtime/go-signal.c index a07fdea..b429fdb 100644 --- a/libgo/runtime/go-signal.c +++ b/libgo/runtime/go-signal.c @@ -179,6 +179,18 @@ setSigactionHandler(struct sigaction* sa, uintptr handler) // C code to fetch values from the siginfo_t and ucontext_t pointers // passed to a signal handler. +uintptr getSiginfoCode(siginfo_t *) + __attribute__ ((no_split_stack)); + +uintptr getSiginfoCode(siginfo_t *) + __asm__ (GOSYM_PREFIX "runtime.getSiginfoCode"); + +uintptr +getSiginfoCode(siginfo_t *info) +{ + return (uintptr)(info->si_code); +} + struct getSiginfoRet { uintptr sigaddr; uintptr sigpc; diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest index 33f99d7..2bd6b5e 100755 --- a/libgo/testsuite/gotest +++ b/libgo/testsuite/gotest @@ -36,7 +36,7 @@ keep=false pkgpath= prefix= dejagnu=no -timeout=240 +timeout=600 testname="" bench="" trace=false |