Avoid using recursion for ts_subtree_compare
This can lead to stack overflow crashes.
This commit is contained in:
parent
ac29eab5f9
commit
5e2456c2f2
3 changed files with 26 additions and 16 deletions
|
|
@ -747,7 +747,7 @@ static bool ts_parser__select_tree(TSParser *self, Subtree left, Subtree right)
|
|||
|
||||
if (ts_subtree_error_cost(left) > 0) return true;
|
||||
|
||||
int comparison = ts_subtree_compare(left, right);
|
||||
int comparison = ts_subtree_compare(left, right, &self->tree_pool);
|
||||
switch (comparison) {
|
||||
case -1:
|
||||
LOG("select_earlier symbol:%s, over_symbol:%s", TREE_NAME(left), TREE_NAME(right));
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "./alloc.h"
|
||||
#include "./array.h"
|
||||
#include "./atomic.h"
|
||||
#include "./subtree.h"
|
||||
#include "./length.h"
|
||||
|
|
@ -618,21 +619,30 @@ void ts_subtree_release(SubtreePool *pool, Subtree self) {
|
|||
}
|
||||
}
|
||||
|
||||
int ts_subtree_compare(Subtree left, Subtree right) {
|
||||
if (ts_subtree_symbol(left) < ts_subtree_symbol(right)) return -1;
|
||||
if (ts_subtree_symbol(right) < ts_subtree_symbol(left)) return 1;
|
||||
if (ts_subtree_child_count(left) < ts_subtree_child_count(right)) return -1;
|
||||
if (ts_subtree_child_count(right) < ts_subtree_child_count(left)) return 1;
|
||||
for (uint32_t i = 0, n = ts_subtree_child_count(left); i < n; i++) {
|
||||
Subtree left_child = ts_subtree_children(left)[i];
|
||||
Subtree right_child = ts_subtree_children(right)[i];
|
||||
switch (ts_subtree_compare(left_child, right_child)) {
|
||||
case -1: return -1;
|
||||
case 1: return 1;
|
||||
default: break;
|
||||
int ts_subtree_compare(Subtree left, Subtree right, SubtreePool *pool) {
|
||||
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(left));
|
||||
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(right));
|
||||
|
||||
int result = 0;
|
||||
while (result == 0 && pool->tree_stack.size > 0) {
|
||||
right = ts_subtree_from_mut(array_pop(&pool->tree_stack));
|
||||
left = ts_subtree_from_mut(array_pop(&pool->tree_stack));
|
||||
|
||||
if (ts_subtree_symbol(left) < ts_subtree_symbol(right)) result = -1;
|
||||
if (ts_subtree_symbol(right) < ts_subtree_symbol(left)) result = 1;
|
||||
if (ts_subtree_child_count(left) < ts_subtree_child_count(right)) result = -1;
|
||||
if (ts_subtree_child_count(right) < ts_subtree_child_count(left)) result = 1;
|
||||
|
||||
for (uint32_t i = ts_subtree_child_count(left); i > 0; i--) {
|
||||
Subtree left_child = ts_subtree_children(left)[i - 1];
|
||||
Subtree right_child = ts_subtree_children(right)[i - 1];
|
||||
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(left_child));
|
||||
array_push(&pool->tree_stack, ts_subtree_to_mut_unsafe(right_child));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
array_clear(&pool->tree_stack);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline void ts_subtree_set_has_changes(MutableSubtree *self) {
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ Subtree ts_subtree_new_missing_leaf(SubtreePool *, TSSymbol, Length, uint32_t, c
|
|||
MutableSubtree ts_subtree_make_mut(SubtreePool *, Subtree);
|
||||
void ts_subtree_retain(Subtree);
|
||||
void ts_subtree_release(SubtreePool *, Subtree);
|
||||
int ts_subtree_compare(Subtree, Subtree);
|
||||
int ts_subtree_compare(Subtree, Subtree, SubtreePool *);
|
||||
void ts_subtree_set_symbol(MutableSubtree *, TSSymbol, const TSLanguage *);
|
||||
void ts_subtree_summarize(MutableSubtree, const Subtree *, uint32_t, const TSLanguage *);
|
||||
void ts_subtree_summarize_children(MutableSubtree, const TSLanguage *);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue