diff -Nru golang-github-go-stack-stack-1.5.2/debian/changelog golang-github-go-stack-stack-1.8.0/debian/changelog --- golang-github-go-stack-stack-1.5.2/debian/changelog 2016-10-27 10:07:03.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/changelog 2020-04-12 09:25:42.000000000 +0000 @@ -1,3 +1,22 @@ +golang-github-go-stack-stack (1.8.0-1) unstable; urgency=medium + + * Team upload. + * New upstream version 1.8.0 (Closes: #952164) + * Replace extra Priority to optional + * Update maintainer address to team+pkg-go@tracker.debian.org + * Bump debhelper compat to 12 + * Bump Standards-Version to 4.5.0 + * Add Rules-Requires-Root and Testsuite + * Remove golang-godebiancontrol-dev from Build-Depends + + -- Shengjing Zhu Sun, 12 Apr 2020 17:25:42 +0800 + +golang-github-go-stack-stack (1.5.2-3) UNRELEASED; urgency=medium + + * Point Vcs-* urls to salsa.debian.org. + + -- Alexandre Viau Mon, 02 Apr 2018 17:23:51 -0400 + golang-github-go-stack-stack (1.5.2-2) unstable; urgency=medium * Replace golang-go with golang-any in Build-Depends. diff -Nru golang-github-go-stack-stack-1.5.2/debian/compat golang-github-go-stack-stack-1.8.0/debian/compat --- golang-github-go-stack-stack-1.5.2/debian/compat 2016-09-19 21:41:32.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -9 diff -Nru golang-github-go-stack-stack-1.5.2/debian/control golang-github-go-stack-stack-1.8.0/debian/control --- golang-github-go-stack-stack-1.5.2/debian/control 2016-10-27 10:06:49.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/control 2020-04-12 09:25:42.000000000 +0000 @@ -1,24 +1,23 @@ Source: golang-github-go-stack-stack Section: devel -Priority: extra -Maintainer: Debian Go Packaging Team -Uploaders: Alessio Treglia -Build-Depends: - debhelper (>= 9~), - dh-golang, - golang-any, - golang-godebiancontrol-dev -Standards-Version: 3.9.8 -Homepage: http://github.com/go-stack/stack +Priority: optional +Maintainer: Debian Go Packaging Team +Uploaders: Alessio Treglia , +Build-Depends: debhelper-compat (= 12), + dh-golang, + golang-any, +Standards-Version: 4.5.0 +Homepage: https://github.com/go-stack/stack +Vcs-Browser: https://salsa.debian.org/go-team/packages/golang-github-go-stack-stack +Vcs-Git: https://salsa.debian.org/go-team/packages/golang-github-go-stack-stack.git XS-Go-Import-Path: github.com/go-stack/stack -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-go/packages/golang-github-go-stack-stack.git/ -Vcs-Git: https://anonscm.debian.org/git/pkg-go/packages/golang-github-go-stack-stack.git/ +Rules-Requires-Root: no +Testsuite: autopkgtest-pkg-go Package: golang-github-go-stack-stack-dev Architecture: all -Depends: - ${misc:Depends}, - ${shlibs:Depends} +Depends: ${misc:Depends}, + ${shlibs:Depends}, Description: capture, manipulate, and format call stacks Package stack implements utilities to capture, manipulate, and format call stacks. It provides a simpler API than diff -Nru golang-github-go-stack-stack-1.5.2/debian/copyright golang-github-go-stack-stack-1.8.0/debian/copyright --- golang-github-go-stack-stack-1.5.2/debian/copyright 2016-09-19 21:41:32.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/copyright 2020-04-12 09:25:42.000000000 +0000 @@ -1,6 +1,6 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Tendermint -Source: https://github.com/tendermint/go-common +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: stack +Source: https://github.com/go-stack/stack Files: * Copyright: 2014 Chris Hines diff -Nru golang-github-go-stack-stack-1.5.2/debian/gbp.conf golang-github-go-stack-stack-1.8.0/debian/gbp.conf --- golang-github-go-stack-stack-1.5.2/debian/gbp.conf 2016-09-19 21:41:32.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/gbp.conf 2020-04-12 09:25:42.000000000 +0000 @@ -1,3 +1,2 @@ [DEFAULT] pristine-tar = True -#compression = xz diff -Nru golang-github-go-stack-stack-1.5.2/debian/gitlab-ci.yml golang-github-go-stack-stack-1.8.0/debian/gitlab-ci.yml --- golang-github-go-stack-stack-1.5.2/debian/gitlab-ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/gitlab-ci.yml 2020-04-12 09:25:42.000000000 +0000 @@ -0,0 +1,28 @@ + +# auto-generated, DO NOT MODIFY. +# The authoritative copy of this file lives at: +# https://salsa.debian.org/go-team/ci/blob/master/cmd/ci/gitlabciyml.go + +# TODO: publish under debian-go-team/ci +image: stapelberg/ci2 + +test_the_archive: + artifacts: + paths: + - before-applying-commit.json + - after-applying-commit.json + script: + # Create an overlay to discard writes to /srv/gopath/src after the build: + - "rm -rf /cache/overlay/{upper,work}" + - "mkdir -p /cache/overlay/{upper,work}" + - "mount -t overlay overlay -o lowerdir=/srv/gopath/src,upperdir=/cache/overlay/upper,workdir=/cache/overlay/work /srv/gopath/src" + - "export GOPATH=/srv/gopath" + - "export GOCACHE=/cache/go" + # Build the world as-is: + - "ci-build -exemptions=/var/lib/ci-build/exemptions.json > before-applying-commit.json" + # Copy this package into the overlay: + - "GBP_CONF_FILES=:debian/gbp.conf gbp buildpackage --git-no-pristine-tar --git-ignore-branch --git-ignore-new --git-export-dir=/tmp/export --git-no-overlay --git-tarball-dir=/nonexistant --git-cleaner=/bin/true --git-builder='dpkg-buildpackage -S -d --no-sign'" + - "pgt-gopath -dsc /tmp/export/*.dsc" + # Rebuild the world: + - "ci-build -exemptions=/var/lib/ci-build/exemptions.json > after-applying-commit.json" + - "ci-diff before-applying-commit.json after-applying-commit.json" diff -Nru golang-github-go-stack-stack-1.5.2/debian/rules golang-github-go-stack-stack-1.8.0/debian/rules --- golang-github-go-stack-stack-1.5.2/debian/rules 2016-09-19 21:41:32.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/debian/rules 2020-04-12 09:25:42.000000000 +0000 @@ -1,11 +1,4 @@ #!/usr/bin/make -f -export DH_OPTIONS - -export DH_GOPKG := github.com/go-stack/stack - %: dh $@ --buildsystem=golang --with=golang - -get-orig-source: - debian/get-git-source.sh diff -Nru golang-github-go-stack-stack-1.5.2/go.mod golang-github-go-stack-stack-1.8.0/go.mod --- golang-github-go-stack-stack-1.5.2/go.mod 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/go.mod 2018-08-26 13:48:48.000000000 +0000 @@ -0,0 +1 @@ +module github.com/go-stack/stack diff -Nru golang-github-go-stack-stack-1.5.2/LICENSE.md golang-github-go-stack-stack-1.8.0/LICENSE.md --- golang-github-go-stack-stack-1.5.2/LICENSE.md 2016-05-14 03:44:11.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/LICENSE.md 2018-08-26 13:48:48.000000000 +0000 @@ -1,13 +1,21 @@ -Copyright 2014 Chris Hines +The MIT License (MIT) -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at +Copyright (c) 2014 Chris Hines - http://www.apache.org/licenses/LICENSE-2.0 +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff -Nru golang-github-go-stack-stack-1.5.2/stack.go golang-github-go-stack-stack-1.8.0/stack.go --- golang-github-go-stack-stack-1.5.2/stack.go 2016-05-14 03:44:11.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/stack.go 2018-08-26 13:48:48.000000000 +0000 @@ -1,3 +1,5 @@ +// +build go1.7 + // Package stack implements utilities to capture, manipulate, and format call // stacks. It provides a simpler API than package runtime. // @@ -21,29 +23,31 @@ // Call records a single function invocation from a goroutine stack. type Call struct { - fn *runtime.Func - pc uintptr + frame runtime.Frame } // Caller returns a Call from the stack of the current goroutine. The argument // skip is the number of stack frames to ascend, with 0 identifying the // calling function. func Caller(skip int) Call { - var pcs [2]uintptr + // As of Go 1.9 we need room for up to three PC entries. + // + // 0. An entry for the stack frame prior to the target to check for + // special handling needed if that prior entry is runtime.sigpanic. + // 1. A possible second entry to hold metadata about skipped inlined + // functions. If inline functions were not skipped the target frame + // PC will be here. + // 2. A third entry for the target frame PC when the second entry + // is used for skipped inline functions. + var pcs [3]uintptr n := runtime.Callers(skip+1, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + frame, _ := frames.Next() + frame, _ = frames.Next() - var c Call - - if n < 2 { - return c - } - - c.pc = pcs[1] - if runtime.FuncForPC(pcs[0]) != sigpanic { - c.pc-- + return Call{ + frame: frame, } - c.fn = runtime.FuncForPC(c.pc) - return c } // String implements fmt.Stinger. It is equivalent to fmt.Sprintf("%v", c). @@ -54,9 +58,10 @@ // MarshalText implements encoding.TextMarshaler. It formats the Call the same // as fmt.Sprintf("%v", c). func (c Call) MarshalText() ([]byte, error) { - if c.fn == nil { + if c.frame == (runtime.Frame{}) { return nil, ErrNoFunc } + buf := bytes.Buffer{} fmt.Fprint(&buf, c) return buf.Bytes(), nil @@ -71,29 +76,33 @@ // %s source file // %d line number // %n function name +// %k last segment of the package path // %v equivalent to %s:%d // // It accepts the '+' and '#' flags for most of the verbs as follows. // -// %+s path of source file relative to the compile time GOPATH +// %+s path of source file relative to the compile time GOPATH, +// or the module path joined to the path of source file relative +// to module root // %#s full path of source file // %+n import path qualified function name +// %+k full package path // %+v equivalent to %+s:%d // %#v equivalent to %#s:%d func (c Call) Format(s fmt.State, verb rune) { - if c.fn == nil { + if c.frame == (runtime.Frame{}) { fmt.Fprintf(s, "%%!%c(NOFUNC)", verb) return } switch verb { case 's', 'v': - file, line := c.fn.FileLine(c.pc) + file := c.frame.File switch { case s.Flag('#'): // done case s.Flag('+'): - file = file[pkgIndex(file, c.fn.Name()):] + file = pkgFilePath(&c.frame) default: const sep = "/" if i := strings.LastIndex(file, sep); i != -1 { @@ -103,16 +112,31 @@ io.WriteString(s, file) if verb == 'v' { buf := [7]byte{':'} - s.Write(strconv.AppendInt(buf[:1], int64(line), 10)) + s.Write(strconv.AppendInt(buf[:1], int64(c.frame.Line), 10)) } case 'd': - _, line := c.fn.FileLine(c.pc) buf := [6]byte{} - s.Write(strconv.AppendInt(buf[:0], int64(line), 10)) + s.Write(strconv.AppendInt(buf[:0], int64(c.frame.Line), 10)) + + case 'k': + name := c.frame.Function + const pathSep = "/" + start, end := 0, len(name) + if i := strings.LastIndex(name, pathSep); i != -1 { + start = i + len(pathSep) + } + const pkgSep = "." + if i := strings.Index(name[start:], pkgSep); i != -1 { + end = start + i + } + if s.Flag('+') { + start = 0 + } + io.WriteString(s, name[start:end]) case 'n': - name := c.fn.Name() + name := c.frame.Function if !s.Flag('+') { const pathSep = "/" if i := strings.LastIndex(name, pathSep); i != -1 { @@ -127,35 +151,17 @@ } } +// Frame returns the call frame infomation for the Call. +func (c Call) Frame() runtime.Frame { + return c.frame +} + // PC returns the program counter for this call frame; multiple frames may // have the same PC value. +// +// Deprecated: Use Call.Frame instead. func (c Call) PC() uintptr { - return c.pc -} - -// name returns the import path qualified name of the function containing the -// call. -func (c Call) name() string { - if c.fn == nil { - return "???" - } - return c.fn.Name() -} - -func (c Call) file() string { - if c.fn == nil { - return "???" - } - file, _ := c.fn.FileLine(c.pc) - return file -} - -func (c Call) line() int { - if c.fn == nil { - return 0 - } - _, line := c.fn.FileLine(c.pc) - return line + return c.frame.PC } // CallStack records a sequence of function invocations from a goroutine @@ -179,9 +185,6 @@ buf := bytes.Buffer{} buf.Write(openBracketBytes) for i, pc := range cs { - if pc.fn == nil { - return nil, ErrNoFunc - } if i > 0 { buf.Write(spaceBytes) } @@ -205,49 +208,22 @@ s.Write(closeBracketBytes) } -// findSigpanic intentionally executes faulting code to generate a stack trace -// containing an entry for runtime.sigpanic. -func findSigpanic() *runtime.Func { - var fn *runtime.Func - var p *int - func() int { - defer func() { - if p := recover(); p != nil { - var pcs [512]uintptr - n := runtime.Callers(2, pcs[:]) - for _, pc := range pcs[:n] { - f := runtime.FuncForPC(pc) - if f.Name() == "runtime.sigpanic" { - fn = f - break - } - } - } - }() - // intentional nil pointer dereference to trigger sigpanic - return *p - }() - return fn -} - -var sigpanic = findSigpanic() - // Trace returns a CallStack for the current goroutine with element 0 // identifying the calling function. func Trace() CallStack { var pcs [512]uintptr - n := runtime.Callers(2, pcs[:]) - cs := make([]Call, n) + n := runtime.Callers(1, pcs[:]) - for i, pc := range pcs[:n] { - pcFix := pc - if i > 0 && cs[i-1].fn != sigpanic { - pcFix-- - } - cs[i] = Call{ - fn: runtime.FuncForPC(pcFix), - pc: pcFix, - } + frames := runtime.CallersFrames(pcs[:n]) + cs := make(CallStack, 0, n) + + // Skip extra frame retrieved just to make sure the runtime.sigpanic + // special case is handled. + frame, more := frames.Next() + + for more { + frame, more = frames.Next() + cs = append(cs, Call{frame: frame}) } return cs @@ -256,7 +232,7 @@ // TrimBelow returns a slice of the CallStack with all entries below c // removed. func (cs CallStack) TrimBelow(c Call) CallStack { - for len(cs) > 0 && cs[0].pc != c.pc { + for len(cs) > 0 && cs[0] != c { cs = cs[1:] } return cs @@ -265,7 +241,7 @@ // TrimAbove returns a slice of the CallStack with all entries above c // removed. func (cs CallStack) TrimAbove(c Call) CallStack { - for len(cs) > 0 && cs[len(cs)-1].pc != c.pc { + for len(cs) > 0 && cs[len(cs)-1] != c { cs = cs[:len(cs)-1] } return cs @@ -311,15 +287,90 @@ return i + len(sep) } +// pkgFilePath returns the frame's filepath relative to the compile-time GOPATH, +// or its module path joined to its path relative to the module root. +// +// As of Go 1.11 there is no direct way to know the compile time GOPATH or +// module paths at runtime, but we can piece together the desired information +// from available information. We note that runtime.Frame.Function contains the +// function name qualified by the package path, which includes the module path +// but not the GOPATH. We can extract the package path from that and append the +// last segments of the file path to arrive at the desired package qualified +// file path. For example, given: +// +// GOPATH /home/user +// import path pkg/sub +// frame.File /home/user/src/pkg/sub/file.go +// frame.Function pkg/sub.Type.Method +// Desired return pkg/sub/file.go +// +// It appears that we simply need to trim ".Type.Method" from frame.Function and +// append "/" + path.Base(file). +// +// But there are other wrinkles. Although it is idiomatic to do so, the internal +// name of a package is not required to match the last segment of its import +// path. In addition, the introduction of modules in Go 1.11 allows working +// without a GOPATH. So we also must make these work right: +// +// GOPATH /home/user +// import path pkg/go-sub +// package name sub +// frame.File /home/user/src/pkg/go-sub/file.go +// frame.Function pkg/sub.Type.Method +// Desired return pkg/go-sub/file.go +// +// Module path pkg/v2 +// import path pkg/v2/go-sub +// package name sub +// frame.File /home/user/cloned-pkg/go-sub/file.go +// frame.Function pkg/v2/sub.Type.Method +// Desired return pkg/v2/go-sub/file.go +// +// We can handle all of these situations by using the package path extracted +// from frame.Function up to, but not including, the last segment as the prefix +// and the last two segments of frame.File as the suffix of the returned path. +// This preserves the existing behavior when working in a GOPATH without modules +// and a semantically equivalent behavior when used in module aware project. +func pkgFilePath(frame *runtime.Frame) string { + pre := pkgPrefix(frame.Function) + post := pathSuffix(frame.File) + if pre == "" { + return post + } + return pre + "/" + post +} + +// pkgPrefix returns the import path of the function's package with the final +// segment removed. +func pkgPrefix(funcName string) string { + const pathSep = "/" + end := strings.LastIndex(funcName, pathSep) + if end == -1 { + return "" + } + return funcName[:end] +} + +// pathSuffix returns the last two segments of path. +func pathSuffix(path string) string { + const pathSep = "/" + lastSep := strings.LastIndex(path, pathSep) + if lastSep == -1 { + return path + } + return path[strings.LastIndex(path[:lastSep], pathSep)+1:] +} + var runtimePath string func init() { - var pcs [1]uintptr + var pcs [3]uintptr runtime.Callers(0, pcs[:]) - fn := runtime.FuncForPC(pcs[0]) - file, _ := fn.FileLine(pcs[0]) + frames := runtime.CallersFrames(pcs[:]) + frame, _ := frames.Next() + file := frame.File - idx := pkgIndex(file, fn.Name()) + idx := pkgIndex(frame.File, frame.Function) runtimePath = file[:idx] if runtime.GOOS == "windows" { @@ -328,7 +379,7 @@ } func inGoroot(c Call) bool { - file := c.file() + file := c.frame.File if len(file) == 0 || file[0] == '?' { return true } diff -Nru golang-github-go-stack-stack-1.5.2/stack-go19_test.go golang-github-go-stack-stack-1.8.0/stack-go19_test.go --- golang-github-go-stack-stack-1.5.2/stack-go19_test.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/stack-go19_test.go 2018-08-26 13:48:48.000000000 +0000 @@ -0,0 +1,67 @@ +// +build go1.9 + +package stack_test + +import ( + "runtime" + "testing" + + "github.com/go-stack/stack" +) + +func TestCallerInlinedPanic(t *testing.T) { + t.Parallel() + + var line int + + defer func() { + if recover() != nil { + var pcs [32]uintptr + n := runtime.Callers(1, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + // count frames to runtime.sigpanic + panicIdx := 0 + for { + f, more := frames.Next() + if f.Function == "runtime.sigpanic" { + break + } + panicIdx++ + if !more { + t.Fatal("no runtime.sigpanic entry on the stack") + } + } + + c := stack.Caller(panicIdx) + if got, want := c.Frame().Function, "runtime.sigpanic"; got != want { + t.Errorf("sigpanic frame: got name == %v, want name == %v", got, want) + } + + c1 := stack.Caller(panicIdx + 1) + if got, want := c1.Frame().Function, "github.com/go-stack/stack_test.inlinablePanic"; got != want { + t.Errorf("TestCallerInlinedPanic frame: got name == %v, want name == %v", got, want) + } + if got, want := c1.Frame().Line, line; got != want { + t.Errorf("TestCallerInlinedPanic frame: got line == %v, want line == %v", got, want) + } + } + }() + + doPanic(t, &line) + t.Fatal("failed to panic") +} + +func doPanic(t *testing.T, panicLine *int) { + _, _, line, ok := runtime.Caller(0) + *panicLine = line + 11 // adjust to match line of panic below + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + inlinablePanic() +} + +func inlinablePanic() { + // Initiate a sigpanic. + var x *uintptr + _ = *x +} diff -Nru golang-github-go-stack-stack-1.5.2/stackinternal_test.go golang-github-go-stack-stack-1.8.0/stackinternal_test.go --- golang-github-go-stack-stack-1.5.2/stackinternal_test.go 2016-05-14 03:44:11.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/stackinternal_test.go 1970-01-01 00:00:00.000000000 +0000 @@ -1,65 +0,0 @@ -package stack - -import ( - "runtime" - "testing" -) - -func TestFindSigpanic(t *testing.T) { - t.Parallel() - sp := findSigpanic() - if got, want := sp.Name(), "runtime.sigpanic"; got != want { - t.Errorf("got == %v, want == %v", got, want) - } -} - -func TestCaller(t *testing.T) { - t.Parallel() - - c := Caller(0) - _, file, line, ok := runtime.Caller(0) - line-- - if !ok { - t.Fatal("runtime.Caller(0) failed") - } - - if got, want := c.file(), file; got != want { - t.Errorf("got file == %v, want file == %v", got, want) - } - - if got, want := c.line(), line; got != want { - t.Errorf("got line == %v, want line == %v", got, want) - } -} - -type fholder struct { - f func() CallStack -} - -func (fh *fholder) labyrinth() CallStack { - for { - return fh.f() - } - panic("this line only needed for go 1.0") -} - -func TestTrace(t *testing.T) { - t.Parallel() - - fh := fholder{ - f: func() CallStack { - cs := Trace() - return cs - }, - } - - cs := fh.labyrinth() - - lines := []int{51, 41, 56} - - for i, line := range lines { - if got, want := cs[i].line(), line; got != want { - t.Errorf("got line[%d] == %v, want line[%d] == %v", i, got, i, want) - } - } -} diff -Nru golang-github-go-stack-stack-1.5.2/stack_test.go golang-github-go-stack-stack-1.8.0/stack_test.go --- golang-github-go-stack-stack-1.5.2/stack_test.go 2016-05-14 03:44:11.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/stack_test.go 2018-08-26 13:48:48.000000000 +0000 @@ -13,13 +13,192 @@ "github.com/go-stack/stack" ) +func TestCaller(t *testing.T) { + t.Parallel() + + c := stack.Caller(0) + _, file, line, ok := runtime.Caller(0) + line-- + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + if got, want := c.Frame().File, file; got != want { + t.Errorf("got file == %v, want file == %v", got, want) + } + + if got, want := c.Frame().Line, line; got != want { + t.Errorf("got line == %v, want line == %v", got, want) + } +} + +func f3(f1 func() stack.Call) stack.Call { + return f2(f1) +} + +func f2(f1 func() stack.Call) stack.Call { + return f1() +} + +func TestCallerMidstackInlined(t *testing.T) { + t.Parallel() + + _, _, line, ok := runtime.Caller(0) + line -= 10 // adjust to return f1() line inside f2() + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + c := f3(func() stack.Call { + return stack.Caller(2) + }) + + if got, want := c.Frame().Line, line; got != want { + t.Errorf("got line == %v, want line == %v", got, want) + } + if got, want := c.Frame().Function, "github.com/go-stack/stack_test.f3"; got != want { + t.Errorf("got func name == %v, want func name == %v", got, want) + } +} + +func TestCallerPanic(t *testing.T) { + t.Parallel() + + var ( + line int + ok bool + ) + + defer func() { + if recover() != nil { + var pcs [32]uintptr + n := runtime.Callers(1, pcs[:]) + frames := runtime.CallersFrames(pcs[:n]) + // count frames to runtime.sigpanic + panicIdx := 0 + for { + f, more := frames.Next() + if f.Function == "runtime.sigpanic" { + break + } + panicIdx++ + if !more { + t.Fatal("no runtime.sigpanic entry on the stack") + } + } + c := stack.Caller(panicIdx) + if got, want := c.Frame().Function, "runtime.sigpanic"; got != want { + t.Errorf("sigpanic frame: got name == %v, want name == %v", got, want) + } + c1 := stack.Caller(panicIdx + 1) + if got, want := c1.Frame().Function, "github.com/go-stack/stack_test.TestCallerPanic"; got != want { + t.Errorf("TestCallerPanic frame: got name == %v, want name == %v", got, want) + } + if got, want := c1.Frame().Line, line; got != want { + t.Errorf("TestCallerPanic frame: got line == %v, want line == %v", got, want) + } + } + }() + + _, _, line, ok = runtime.Caller(0) + line += 7 // adjust to match line of panic below + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + // Initiate a sigpanic. + var x *uintptr + _ = *x +} + +type tholder struct { + trace func() stack.CallStack +} + +func (th *tholder) traceLabyrinth() stack.CallStack { + for { + return th.trace() + } +} + +func TestTrace(t *testing.T) { + t.Parallel() + + _, _, line, ok := runtime.Caller(0) + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + + fh := tholder{ + trace: func() stack.CallStack { + cs := stack.Trace() + return cs + }, + } + + cs := fh.traceLabyrinth() + + lines := []int{line + 7, line - 7, line + 12} + + for i, line := range lines { + if got, want := cs[i].Frame().Line, line; got != want { + t.Errorf("got line[%d] == %v, want line[%d] == %v", i, got, i, want) + } + } +} + +// Test stack handling originating from a sigpanic. +func TestTracePanic(t *testing.T) { + t.Parallel() + + var ( + line int + ok bool + ) + + defer func() { + if recover() != nil { + trace := stack.Trace() + + // find runtime.sigpanic + panicIdx := -1 + for i, c := range trace { + if c.Frame().Function == "runtime.sigpanic" { + panicIdx = i + break + } + } + if panicIdx == -1 { + t.Fatal("no runtime.sigpanic entry on the stack") + } + if got, want := trace[panicIdx].Frame().Function, "runtime.sigpanic"; got != want { + t.Errorf("sigpanic frame: got name == %v, want name == %v", got, want) + } + if got, want := trace[panicIdx+1].Frame().Function, "github.com/go-stack/stack_test.TestTracePanic"; got != want { + t.Errorf("TestTracePanic frame: got name == %v, want name == %v", got, want) + } + if got, want := trace[panicIdx+1].Frame().Line, line; got != want { + t.Errorf("TestTracePanic frame: got line == %v, want line == %v", got, want) + } + } + }() + + _, _, line, ok = runtime.Caller(0) + line += 7 // adjust to match line of panic below + if !ok { + t.Fatal("runtime.Caller(0) failed") + } + // Initiate a sigpanic. + var x *uintptr + _ = *x +} + const importPath = "github.com/go-stack/stack" type testType struct{} -func (tt testType) testMethod() (c stack.Call, pc uintptr, file string, line int, ok bool) { +func (tt testType) testMethod() (c stack.Call, file string, line int, ok bool) { c = stack.Caller(0) - pc, file, line, ok = runtime.Caller(0) + _, file, line, ok = runtime.Caller(0) line-- return } @@ -28,14 +207,14 @@ t.Parallel() c := stack.Caller(0) - pc, file, line, ok := runtime.Caller(0) + _, file, line, ok := runtime.Caller(0) line-- if !ok { t.Fatal("runtime.Caller(0) failed") } relFile := path.Join(importPath, filepath.Base(file)) - c2, pc2, file2, line2, ok2 := testType{}.testMethod() + c2, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } @@ -54,7 +233,9 @@ {c, "func", "%#s", file}, {c, "func", "%d", fmt.Sprint(line)}, {c, "func", "%n", "TestCallFormat"}, - {c, "func", "%+n", runtime.FuncForPC(pc - 1).Name()}, + {c, "func", "%+n", "github.com/go-stack/stack_test.TestCallFormat"}, + {c, "func", "%k", "stack_test"}, + {c, "func", "%+k", "github.com/go-stack/stack_test"}, {c, "func", "%v", fmt.Sprint(path.Base(file), ":", line)}, {c, "func", "%+v", fmt.Sprint(relFile, ":", line)}, {c, "func", "%#v", fmt.Sprint(file, ":", line)}, @@ -64,7 +245,9 @@ {c2, "meth", "%#s", file2}, {c2, "meth", "%d", fmt.Sprint(line2)}, {c2, "meth", "%n", "testType.testMethod"}, - {c2, "meth", "%+n", runtime.FuncForPC(pc2).Name()}, + {c2, "meth", "%+n", "github.com/go-stack/stack_test.testType.testMethod"}, + {c2, "meth", "%k", "stack_test"}, + {c2, "meth", "%+k", "github.com/go-stack/stack_test"}, {c2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)}, {c2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)}, {c2, "meth", "%#v", fmt.Sprint(file2, ":", line2)}, @@ -88,7 +271,7 @@ t.Fatal("runtime.Caller(0) failed") } - c2, _, file2, line2, ok2 := testType{}.testMethod() + c2, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } @@ -121,7 +304,7 @@ t.Fatal("runtime.Caller(0) failed") } - c2, _, file2, line2, ok2 := testType{}.testMethod() + c2, file2, line2, ok2 := testType{}.testMethod() if !ok2 { t.Fatal("runtime.Caller(0) failed") } @@ -174,6 +357,7 @@ t.Errorf("\n got %v\nwant %v", got, want) } } + func getTrace(t *testing.T) (stack.CallStack, int) { cs := stack.Trace().TrimRuntime() _, _, line, ok := runtime.Caller(0) @@ -187,7 +371,7 @@ func TestTrimAbove(t *testing.T) { trace := trimAbove() if got, want := len(trace), 2; got != want { - t.Errorf("got len(trace) == %v, want %v, trace: %n", got, want, trace) + t.Fatalf("got len(trace) == %v, want %v, trace: %n", got, want, trace) } if got, want := fmt.Sprintf("%n", trace[1]), "TestTrimAbove"; got != want { t.Errorf("got %q, want %q", got, want) diff -Nru golang-github-go-stack-stack-1.5.2/.travis.yml golang-github-go-stack-stack-1.8.0/.travis.yml --- golang-github-go-stack-stack-1.5.2/.travis.yml 2016-05-14 03:44:11.000000000 +0000 +++ golang-github-go-stack-stack-1.8.0/.travis.yml 2018-08-26 13:48:48.000000000 +0000 @@ -1,16 +1,15 @@ language: go sudo: false go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 + - 1.7.x + - 1.8.x + - 1.9.x + - 1.10.x + - 1.11.x - tip before_install: - go get github.com/mattn/goveralls - - go get golang.org/x/tools/cmd/cover script: - goveralls -service=travis-ci