Hello y’all! I’m prototyping something and ended up writing a nif to call tree-sitter, I took the opportunity to learn C and understand how NIFs work.
With a bit of help from copilot and ELisp I ended up writing almost all the APIs from tree-sitter; everything was good until I got a segfault.
After moving pieces around I found that calling ct:pal would “kind of flush” the resources, curiously, not all the resources, but the Node type ones. Here is the repo for the lib GitHub - cfclavijo/erl_ts at develop
I added a test to replicate this problem (initially I thought it was related to the function erl_ts:node_end_byte, thus the name)
node_end_byte_segfault_post_print(_Config) ->
SC = "fun(A)->1+2.",
{ok, Parser} = erl_ts:parser_new(),
{ok, Lang} = erl_ts:tree_sitter_erlang(),
true = erl_ts:parser_set_language(Parser, Lang),
Tree = erl_ts:parser_parse_string(Parser, SC),
RootNode = erl_ts:tree_root_node(Tree),
ct:print(default, ?LOW_IMPORTANCE, "this ends in segfault wtf", [], []),
%% erl_ts:tree_language(Tree), %% this makes the subsequent calls to erl_ts work
%% RootNodeB = erl_ts:tree_root_node(Tree), %% this also makes the subsequent calls to erl_ts work
FunDeclNode = erl_ts:node_child(RootNode, 0), %% here comes the segfault
running rebar3 ct not always throws a segfault, tho
If I remove the ct:print or call the nif passing a different type of reference (Like the Tree), everything works.
Any Idea what could be happening?
(Suggestions on how to improve the C code are welcome as well )
Thanks!