Avoid using recursion for ts_subtree_compare

This can lead to stack overflow crashes.
This commit is contained in:
Max Brunsfeld 2023-11-27 10:43:30 -08:00
parent ac29eab5f9
commit 5e2456c2f2
3 changed files with 26 additions and 16 deletions

View file

@ -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) {