From 5101de1547ca834edf6aaf2f87f0cf7439bd33d6 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Thu, 26 May 2022 13:02:24 -0400 Subject: [PATCH] Issue #143 - Track recursion depth of equalp This prevents the possibility of segfaulting when traversing arbitrarily complex circular structures. --- CHANGELOG.md | 2 +- include/cyclone/runtime.h | 1 - runtime.c | 19 +++++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e30efb08..94c387c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Bug Fixes -- Enforce a maximum recursion depth when printing an object via `display` and `write`. This prevents segmentation faults when printing circular data structures. +- Enforce a maximum recursion depth when printing an object via `display` and `write`, and when comparing objects via `equal?`. This prevents segmentation faults when working with circular data structures. ## 0.34.0 - January 2, 2022 diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index eb6ae077..b1c0bfc3 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -574,7 +574,6 @@ double MRG32k3a (double seed); //object Cyc_eq(object x, object y); object Cyc_eqv(object x, object y); #define Cyc_eq(x, y) (make_boolean(x == y)) -int equal(object, object); object equalp(object, object); object Cyc_has_cycle(object lst); object Cyc_is_list(object lst); diff --git a/runtime.c b/runtime.c index 7431afc4..6330d026 100644 --- a/runtime.c +++ b/runtime.c @@ -785,7 +785,8 @@ void Cyc_rt_raise_msg(void *data, const char *err) /* END exception handler */ -int equal(object x, object y) +object _equalp(object x, object y, int depth); +static int equal(object x, object y, int depth) { if (x == y) return 1; @@ -818,7 +819,7 @@ int equal(object x, object y) int i; if (x == y) return 1; for (i = 0; i < ((vector) x)->num_elements; i++) { - if (equalp(((vector) x)->elements[i], ((vector) y)->elements[i]) == + if (_equalp(((vector) x)->elements[i], ((vector) y)->elements[i], depth + 1) == boolean_f) return 0; } @@ -1217,7 +1218,8 @@ done: return quote_void; } -object Cyc_display(void *data, object x, FILE * port) { +object Cyc_display(void *data, object x, FILE * port) +{ return _Cyc_display(data, x, port, 0); } @@ -1624,7 +1626,7 @@ object Cyc_heap_alloc_port(void *data, port_type *stack_p) /** * Check two objects for deep equality */ -object equalp(object x, object y) +object _equalp(object x, object y, int depth) { int second_cycle = 0; object slow_lis = x, fast_lis = NULL; @@ -1636,7 +1638,7 @@ object equalp(object x, object y) } for (;; x = cdr(x), y = cdr(y)) { - if (equal(x, y)) + if (depth == MAX_DEPTH || equal(x, y, depth)) return boolean_t; if (is_value_type(x) || is_value_type(y) || (x == NULL) || (y == NULL) || @@ -1648,7 +1650,7 @@ object equalp(object x, object y) pcar_y == car(y)) { // do nothing, already equal } else { - if (boolean_f == equalp(car(x), car(y))) + if (boolean_f == _equalp(car(x), car(y), depth + 1)) return boolean_f; pcar_x = car(x); pcar_y = car(y); @@ -1682,6 +1684,11 @@ object equalp(object x, object y) } } +object equalp(object x, object y) +{ + return _equalp(x, y, 0); +} + object Cyc_num_cmp_va_list(void *data, int argc, int (fn_op(void *, object, object)), object n, va_list ns)