SSE: Fix goroutine leak in math operation expression parsing (#102380)
--------- Co-authored-by: Sam Jewell <sam.jewell@grafana.com>
This commit is contained in:
co-authored by
Sam Jewell
parent
216b6e96a9
commit
3f2ef07872
@@ -67,13 +67,14 @@ type stateFn func(*lexer) stateFn
|
||||
|
||||
// lexer holds the state of the scanner.
|
||||
type lexer struct {
|
||||
input string // the string being scanned
|
||||
state stateFn // the next lexing function to enter
|
||||
pos Pos // current position in the input
|
||||
start Pos // start position of this item
|
||||
width Pos // width of last rune read from input
|
||||
lastPos Pos // position of most recent item returned by nextItem
|
||||
items chan item // channel of scanned items
|
||||
input string // the string being scanned
|
||||
state stateFn // the next lexing function to enter
|
||||
pos Pos // current position in the input
|
||||
start Pos // start position of this item
|
||||
width Pos // width of last rune read from input
|
||||
lastPos Pos // position of most recent item returned by nextItem
|
||||
items chan item // channel of scanned items
|
||||
done chan struct{} // channel to signal lexer shutdown
|
||||
}
|
||||
|
||||
// next returns the next rune in the input.
|
||||
@@ -103,7 +104,11 @@ func (l *lexer) backup() {
|
||||
|
||||
// emit passes an item back to the client.
|
||||
func (l *lexer) emit(t itemType) {
|
||||
l.items <- item{t, l.start, l.input[l.start:l.pos]}
|
||||
select {
|
||||
case l.items <- item{t, l.start, l.input[l.start:l.pos]}:
|
||||
case <-l.done:
|
||||
return
|
||||
}
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
@@ -139,7 +144,11 @@ func (l *lexer) lineNumber() int {
|
||||
// errorf returns an error token and terminates the scan by passing
|
||||
// back a nil pointer that will be the next state, terminating l.nextItem.
|
||||
func (l *lexer) errorf(format string, args ...any) stateFn {
|
||||
l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
|
||||
select {
|
||||
case l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}:
|
||||
case <-l.done:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -155,15 +164,32 @@ func lex(input string) *lexer {
|
||||
l := &lexer{
|
||||
input: input,
|
||||
items: make(chan item),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
go l.run()
|
||||
return l
|
||||
}
|
||||
|
||||
// Close terminates the lexer goroutine.
|
||||
func (l *lexer) Close() {
|
||||
select {
|
||||
case <-l.done:
|
||||
// already closed
|
||||
default:
|
||||
close(l.done)
|
||||
}
|
||||
}
|
||||
|
||||
// run runs the state machine for the lexer.
|
||||
func (l *lexer) run() {
|
||||
defer close(l.items)
|
||||
for l.state = lexItem; l.state != nil; {
|
||||
l.state = l.state(l)
|
||||
select {
|
||||
case <-l.done:
|
||||
return
|
||||
default:
|
||||
l.state = l.state(l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user