Skip to content

Commit

Permalink
fmt: don't recur if String method (etc.) misbehaves
Browse files Browse the repository at this point in the history
Fixes #2555.

R=golang-dev, dsymonds, r
CC=golang-dev
https://golang.org/cl/5486076
  • Loading branch information
robpike committed Dec 15, 2011
1 parent 85fdd68 commit 24e9683
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/pkg/fmt/fmt_test.go
Expand Up @@ -813,3 +813,37 @@ func TestPanics(t *testing.T) {
}
}
}

// Test that erroneous String routine doesn't cause fatal recursion.
var recurCount = 0

type Recur struct {
i int
failed *bool
}

func (r Recur) String() string {
if recurCount++; recurCount > 10 {
*r.failed = true
return "FAIL"
}
// This will call badVerb. Before the fix, that would cause us to recur into
// this routine to print %!p(value). Now we don't call the user's method
// during an error.
return Sprintf("recur@%p value: %d", r, r.i)
}

func TestBadVerbRecursion(t *testing.T) {
failed := false
r := Recur{3, &failed}
Sprintf("recur@%p value: %d\n", &r, r.i)
if failed {
t.Error("fail with pointer")
}
failed = false
r = Recur{4, &failed}
Sprintf("recur@%p, value: %d\n", r, r.i)
if failed {
t.Error("fail with value")
}
}
7 changes: 7 additions & 0 deletions src/pkg/fmt/print.go
Expand Up @@ -74,6 +74,7 @@ type GoStringer interface {
type pp struct {
n int
panicking bool
erroring bool // printing an error condition
buf bytes.Buffer
// field holds the current item, as an interface{}.
field interface{}
Expand Down Expand Up @@ -124,6 +125,7 @@ var ppFree = newCache(func() interface{} { return new(pp) })
func newPrinter() *pp {
p := ppFree.get().(*pp)
p.panicking = false
p.erroring = false
p.fmt.init(&p.buf)
return p
}
Expand Down Expand Up @@ -299,6 +301,7 @@ func (p *pp) unknownType(v interface{}) {
}

func (p *pp) badVerb(verb rune) {
p.erroring = true
p.add('%')
p.add('!')
p.add(verb)
Expand All @@ -316,6 +319,7 @@ func (p *pp) badVerb(verb rune) {
p.buf.Write(nilAngleBytes)
}
p.add(')')
p.erroring = false
}

func (p *pp) fmtBool(v bool, verb rune) {
Expand Down Expand Up @@ -606,6 +610,9 @@ func (p *pp) catchPanic(field interface{}, verb rune) {
}

func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) {
if p.erroring {
return
}
// Is it a Formatter?
if formatter, ok := p.field.(Formatter); ok {
handled = true
Expand Down

0 comments on commit 24e9683

Please sign in to comment.