txlyre 2 dni temu
rodzic
commit
bfdcb1ea6b
2 zmienionych plików z 27 dodań i 8 usunięć
  1. 26 7
      qirt.c
  2. 1 1
      qirt.h

+ 26 - 7
qirt.c

@@ -2245,10 +2245,13 @@ qi_value_t *qi_call_debug(qi_state_t *state, qi_value_t *value,
   return _qi_call(state, value, pargs, debug_data);
 }
 
-qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
+static qi_bool _qi_guarded_equals(qi_state_t *state, qi_size_t depth, qi_list_t *tempstack, qi_value_t *a, qi_value_t *b) {
+  if (depth >= state->rlimit)
+    qi_throw_format(state, "recursion depth exceeded while comparing nested values");
+
   if (a == b)
     return true;
-
+  
   qi_value_t *meta;
   if ((meta = qi_call_meta(state, NULL, a, "__equals", 2, a, b))) {
     if (meta->type != QI_BOOLEAN)
@@ -2294,6 +2297,12 @@ qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
     return fileno(a->value.file.fd) == fileno(b->value.file.fd);
 
   case QI_LIST:
+    if (qi_list_contains(tempstack, a) || qi_list_contains(tempstack, b))
+      return true;
+
+    qi_list_push(tempstack, a);
+    qi_list_push(tempstack, b);
+
     qi_mutex_lock(a->mutex);
     qi_mutex_lock(b->mutex);
 
@@ -2312,8 +2321,8 @@ qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
     }
 
     for (qi_size_t i = 0; i < qi_list_length(a->value.list); i++)
-      if (!_qi_equals(state, qi_list_index(a->value.list, i),
-                      qi_list_index(b->value.list, i))) {
+      if (!_qi_guarded_equals(state, depth+1, tempstack, qi_list_index(a->value.list, i),
+                              qi_list_index(b->value.list, i))) {
         qi_mutex_unlock(a->mutex);
         qi_mutex_unlock(b->mutex);
 
@@ -2333,13 +2342,19 @@ qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
       return false;
 
     for (qi_size_t i = 0; i < qi_list_length(a->value.list); i++)
-      if (!_qi_equals(state, qi_list_index(a->value.list, i),
-                      qi_list_index(b->value.list, i)))
+      if (!_qi_guarded_equals(state, depth+1, tempstack, qi_list_index(a->value.list, i),
+                              qi_list_index(b->value.list, i)))
         return false;
 
     return true;
 
   case QI_TABLE:
+    if (qi_list_contains(tempstack, a) || qi_list_contains(tempstack, b))
+      return true;
+
+    qi_list_push(tempstack, a);
+    qi_list_push(tempstack, b);
+
     qi_mutex_lock(a->mutex);
     qi_mutex_lock(b->mutex);
 
@@ -2368,7 +2383,7 @@ qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
         return false;
       }
 
-      if (!_qi_equals(state, a_value, b_value)) {
+      if (!_qi_guarded_equals(state, depth+1, tempstack, a_value, b_value)) {
         qi_mutex_unlock(a->mutex);
         qi_mutex_unlock(b->mutex);
 
@@ -2396,6 +2411,10 @@ qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
   return true;
 }
 
+qi_bool _qi_equals(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
+  return _qi_guarded_equals(state, 0, qi_list_make(), a, b);
+}
+
 qi_bool _qi_in(qi_state_t *state, qi_value_t *a, qi_value_t *b) {
   qi_value_t *meta;
   qi_bool fail = false;

+ 1 - 1
qirt.h

@@ -180,7 +180,7 @@ struct _qi_state_t {
   qi_list_t *scopes;
   qi_list_t *calltrace;
 
-  size_t rlimit;
+  qi_size_t rlimit;
 
   const char *_debug_data;
 };