Skip to content

text/template: does not recover from panics where it should #2663

@remyoudompheng

Description

@remyoudompheng
What steps will reproduce the problem?
1. Compile and run the following program:

package main

import (
  "errors"
  "fmt"
  "os"
  "text/template"
)

const tpl = `
An error has occurred in {{ .Context }}! Message: {{ .Error.Error }}
`

type Message struct {
  Context string
  Error error
}

func main() {
  t := template.New("T")
  t = template.Must(t.Parse(tpl))

  err := Message{"context", errors.New("some error")}
  errT := t.Execute(os.Stderr, err)
  if errT != nil {
      fmt.Fprintf(os.Stderr, "\ninternal template error: %s", errT)
  }

  err.Error = nil
  errT = t.Execute(os.Stderr, err)
  if errT != nil {
      fmt.Fprintf(os.Stderr, "\ninternal template error: %s", errT)
  }
}


What is the expected output?

An error has occurred in context! Message: some error

An error has occurred in context! Message: 
internal template error: Call of method on nil interface value

What do you see instead?

An error has occurred in context! Message: some error

An error has occurred in context! Message: panic: Call of method on nil interface value
[recovered]
    panic: interface conversion: string is not error: missing method Error

goroutine 1 [running]:
----- stack segment boundary -----
text/template.errRecover(0x7ff5ec9bbee0, 0x7ff5ec9bb100)
    /opt/remy/go/src/pkg/text/template/exec.go:84 +0xaf
----- stack segment boundary -----
reflect.Value.call(0x490650, 0xf84000d450, 0x13a, 0x4b7f54, 0x6c6c614300000004, ...)
    /opt/remy/go/src/pkg/reflect/value.go:367 +0x1f8
reflect.Value.Call(0x490650, 0xf84000d450, 0x13a, 0x52f1a8, 0x0, ...)
    /opt/remy/go/src/pkg/reflect/value.go:330 +0x85
text/template.(*state).evalCall(0xf840019480, 0x4a0130, 0xf84000d440, 0x192, 0x490650,
...)
    /opt/remy/go/src/pkg/text/template/exec.go:489 +0x677
text/template.(*state).evalField(0xf840019480, 0x4a0130, 0xf84000d440, 0x192, 0x4d92d9,
...)
    /opt/remy/go/src/pkg/text/template/exec.go:408 +0x232
text/template.(*state).evalFieldChain(0xf840019480, 0x4a0130, 0xf84000d440, 0x192,
0x490650, ...)
    /opt/remy/go/src/pkg/text/template/exec.go:381 +0x194
text/template.(*state).evalFieldNode(0xf840019480, 0x4a0130, 0xf84000d440, 0x192,
0xf84000d0c0, ...)
    /opt/remy/go/src/pkg/text/template/exec.go:360 +0xa7
text/template.(*state).evalCommand(0xf840019480, 0x4a0130, 0xf84000d440, 0x192,
0xf84000d0e0, ...)
    /opt/remy/go/src/pkg/text/template/exec.go:312 +0x284
text/template.(*state).evalPipeline(0xf840019480, 0x4a0130, 0xf84000d440, 0x192,
0xf8400192d0, ...)
    /opt/remy/go/src/pkg/text/template/exec.go:290 +0xfd
text/template.(*state).walk(0xf840019480, 0x4a0130, 0xf84000d440, 0x192, 0xf8400192a0,
...)
    /opt/remy/go/src/pkg/text/template/exec.go:124 +0xde
text/template.(*state).walk(0xf840019480, 0x4a0130, 0xf84000d440, 0x192, 0xf8400193c0,
...)
    /opt/remy/go/src/pkg/text/template/exec.go:133 +0x5f9
text/template.(*Template).Execute(0xf84001e080, 0xf840019300, 0xf84001a010, 0x4a0120,
0xf84000d440, ...)
    /opt/remy/go/src/pkg/text/template/exec.go:112 +0x1d3
main.main()
    /tmp/main.go:30 +0x2fa

Which compiler are you using (5g, 6g, 8g, gccgo)?

6g

Which operating system are you using?

linux

Which revision are you using?  (hg identify)

52ae6fbcc97a+ tip

Please provide any additional information below.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions