errors icon indicating copy to clipboard operation
errors copied to clipboard

if an error somehow wraps itself, Error() recurses forever

Open lunixbochs opened this issue 8 years ago • 2 comments

I know it's totally my bad to cause this in the first place, but I've somehow made err.Error() recurse forever, which means the err itself is the cause. I haven't tracked it down yet, but detecting if the Error() chain loops might be nice, as I had to use delve and print 200k lines of stacktrace to figure out what was wrong.

https://github.com/pkg/errors/blob/master/errors.go#L228

lunixbochs avatar Aug 31 '17 23:08 lunixbochs

ooh, that's bad. If you can make a repro so I can turn it into a test that would be much appreciated.

On Fri, Sep 1, 2017 at 9:39 AM, Ryan Hileman [email protected] wrote:

I know it's totally my bad to cause this in the first place, but I've somehow made err.Error() recurse forever, which means the err itself is the cause. I haven't tracked it down yet, but detecting if the Error() chain loops might be nice, as I had to use delve and print 200k lines of stacktrace to figure out what was wrong.

https://github.com/pkg/errors/blob/master/errors.go#L228

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/pkg/errors/issues/131, or mute the thread https://github.com/notifications/unsubscribe-auth/AAAcAxPeF54EreBUipOKNROlsD9MpcNlks5sd0Q7gaJpZM4PJieV .

davecheney avatar Aug 31 '17 23:08 davecheney

Okay, so this was a different problem than I thought- so not a recursive error- (and totally my fault): a file format parser bug resulted in the next input "frame" being parsed as a recursion of the previous frame. When the very last frame throws io.EOF, it bubbles all the way out (200k stack frames, 200k times errors.Wrap()).

Now withMessage.Error() is quadratic time due to the simple string concat, so deeply nested errors are actually pretty slow as per this gist (which needs to be run locally, not on play.golang.org): https://gist.github.com/lunixbochs/00262cfc53c5096b57274768209f6aa6

I get this output for 20k iterations:

quadratic 511.538ms 100005
linear 2.830926ms 100008

It was taking tens of seconds to print the error message, which is why my stack trace was just miles of withMessage.Error().

Now, I don't think this is real-world case enough to actually fix like this (as a dumb list join is slower for real-world error nesting, like ~20), but if someone in the future ever ends up with this many nested errors.withMessage they will be just as confused as me.

It's also a contrived DoS case.

lunixbochs avatar Sep 01 '17 04:09 lunixbochs