Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Bug That Truncates Stack Traces #477

Merged
merged 1 commit into from
Jul 22, 2017

Conversation

richard-tunein
Copy link
Contributor

@richard-tunein richard-tunein commented Jul 11, 2017

What It Fixes

This PR updates takeStacktrace() to fix some logic errors. The errors would cause that function to improperly truncate a stack trace in many cases.

Details

	programCounters := _stacktracePool.Get().(*programCounters)
	// ...
	for {
		n := runtime.Callers(2, programCounters.pcs)
		if n < cap(programCounters.pcs) {
			programCounters.pcs = programCounters.pcs[:n]
			break
		}
	}

The above code seems to assume that runtime.Callers() writes up to the capacity of the slice, when in fact it will only write up to the length of the slice. This would work the first time that a variable was allocated by the pool, since the slice's capacity and length would be equal. However, the code then re-sizes the slice to reflect the number of items written. When the data structure is put back into the pool, the slice will now have a smaller length.

The next time that data structure is re-used from the pool, runtime.Callers() will only write up to and return that smaller length. If the number of frames is greater than the length, the n < cap(programCounters.pcs) condition will still return true, and the loop will break without obtaining all of the items available.

How I Fixed It

The fix avoids re-slicing programCounters.pcs. Instead, we record the number of total frames in a numFrames variable outside of the for loop, and use it to provide a new (sub-)slice as a parameter to the runtime.CallersFrames() function.

There seemed to be an invalid assumption that runtime.Callers(skip, pcbuf)
would write and return up to cap(pcbuf) entries. This is incorrect--it will
only write and return up to len(pcbuf). This change updates takeStacktrace() to
avoid changing the len of re-used slices.
@CLAassistant
Copy link

CLAassistant commented Jul 11, 2017

CLA assistant check
All committers have signed the CLA.

@codecov
Copy link

codecov bot commented Jul 11, 2017

Codecov Report

Merging #477 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #477   +/-   ##
=======================================
  Coverage   97.12%   97.12%           
=======================================
  Files          36       36           
  Lines        1912     1912           
=======================================
  Hits         1857     1857           
  Misses         45       45           
  Partials       10       10
Impacted Files Coverage Δ
stacktrace.go 86.11% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dadca01...13cef4e. Read the comment docs.

Copy link
Contributor

@akshayjshah akshayjshah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great - thanks for the fix, and for the detailed PR message!

@akshayjshah akshayjshah merged commit 770b97b into uber-go:master Jul 22, 2017
@richard-tunein richard-tunein deleted the stack_trace_buffer_len branch July 23, 2017 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants