|
@@ -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;
|