Skip to content

text/template/parse: Parse will leak go routines if parsing fails #10574

Closed
@gravis

Description

@gravis

(From https://groups.google.com/forum/#!topic/golang-nuts/6nTWBLbAyKo)

When Parse() is called, a new lexer is created, and it will run in the background:

func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {

[...]

t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim))

[...]

}

(https://github.com/golang/go/blob/master/src/text/template/parse/parse.go#L228)

This will start a go routine :

// lex creates a new scanner for the input string.
func lex(name, input, left, right string) *lexer {
    if left == "" {
        left = leftDelim
    }
    if right == "" {
        right = rightDelim
    }
    l := &lexer{
        name:       name,
        input:      input,
        leftDelim:  left,
        rightDelim: right,
        items:      make(chan item),
    }
    go l.run()
    return l
}

(https://github.com/golang/go/blob/master/src/text/template/parse/lex.go#L191)

Now if the parser fails to parse, it will panic, and the error is recovered :

// recover is the handler that turns panics into returns from the top level of Parse.
func (t *Tree) recover(errp *error) {
    e := recover()
    if e != nil {
        if _, ok := e.(runtime.Error); ok {
            panic(e)
        }
        if t != nil {
            t.stopParse()
        }
        *errp = e.(error)
    }
    return
}

(https://github.com/golang/go/blob/master/src/text/template/parse/parse.go#L191)

which will call t.stopParse():

// stopParse terminates parsing.
func (t *Tree) stopParse() {
    t.lex = nil
    t.vars = nil
    t.funcs = nil
}

The lexer should be GC, except it's still running in the background, because no parser is there to pull on the channel.
I think the lex should have a abort() method to end the routine cleanly, otherwise each time the parser is called and failing, we leave a running lexer behind.

I will create a pull request to fix this, as I have already some code for that.
ps: Minux has confirmed the bug http://play.golang.org/p/qTQXuT3ktV

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions