From 7621c203ae43fe58c0fc4d18e4dcf3caa1985888 Mon Sep 17 00:00:00 2001 From: Maxim Sukharev Date: Tue, 28 Jun 2022 21:40:09 +0800 Subject: [PATCH] Fix segfault in QueryCursor --- bindings.go | 3 +++ bindings_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/bindings.go b/bindings.go index 4d450114..ee712528 100644 --- a/bindings.go +++ b/bindings.go @@ -818,6 +818,8 @@ func (q *Query) StringValueForId(id uint32) string { type QueryCursor struct { c *C.TSQueryCursor t *Tree + // keep a pointer to the query to avoid garbage collection + q *Query isClosed bool } @@ -832,6 +834,7 @@ func NewQueryCursor() *QueryCursor { // Exec executes the query on a given syntax node. func (qc *QueryCursor) Exec(q *Query, n *Node) { + qc.q = q qc.t = n.t C.ts_query_cursor_exec(qc.c, q.c, n.c) } diff --git a/bindings_test.go b/bindings_test.go index 3dc385f5..1b834ca7 100644 --- a/bindings_test.go +++ b/bindings_test.go @@ -596,6 +596,36 @@ func TestLeakParseInput(t *testing.T) { assert.Less(t, m.Alloc, uint64(1024*1024)) } +// see https://github.com/smacker/go-tree-sitter/issues/75 +func TestCursorKeepsQuery(t *testing.T) { + source := bytes.Repeat([]byte("1 + 1"), 10000) + + parser := NewParser() + parser.SetLanguage(getTestGrammar()) + + tree := parser.Parse(nil, source) + root := tree.RootNode() + + for i := 0; i < 100; i++ { + query, _ := NewQuery( + []byte("(number) @match"), + getTestGrammar(), + ) + + qc := NewQueryCursor() + + qc.Exec(query, root) + + for { + // ensure qc.NextMatch() doesn't cause a segfault + match, exists := qc.NextMatch() + if !exists || match == nil { + break + } + } + } +} + func BenchmarkParse(b *testing.B) { ctx := context.Background() parser := NewParser()