@@ -2032,7 +2032,7 @@ mrb_hash_to_s(mrb_state *mrb, mrb_value self)
20322032 mrb -> c -> ci -> mid = MRB_SYM (inspect );
20332033 mrb_value ret = mrb_str_new_lit (mrb , "{" );
20342034 int ai = mrb_gc_arena_save (mrb );
2035- if (mrb_inspect_recursive_p (mrb , self )) {
2035+ if (MRB_RECURSIVE_UNARY_P (mrb , MRB_SYM ( inspect ) , self )) {
20362036 mrb_str_cat_lit (mrb , ret , "...}" );
20372037 return ret ;
20382038 }
@@ -2125,62 +2125,6 @@ mrb_hash_rassoc(mrb_state *mrb, mrb_value hash)
21252125 return mrb_nil_value ();
21262126}
21272127
2128- /*
2129- * Hash recursion detection for equality comparison
2130- *
2131- * This implements a memory-efficient recursion detection mechanism for Hash#== and Hash#eql?
2132- * to prevent SystemStackError when comparing mutually recursive hash structures.
2133- *
2134- * Background:
2135- * - Issue: Hash#eql? caused infinite recursion and stack overflow with recursive hashes
2136- * - Example: a = {}; b = {}; a[:self] = a; a[:other] = b; b[:self] = b; b[:other] = a; a.eql?(b)
2137- *
2138- * Solution:
2139- * - Uses call stack inspection (similar to inspect_recursive_p) to detect recursion
2140- * - Minimal memory overhead - examines existing call frames without additional storage
2141- * - Returns FALSE when recursion detected (conservative approach for mruby's constraints)
2142- * - Preserves all normal equality behavior for non-recursive cases
2143- *
2144- * Design considerations:
2145- * - Memory > Performance > Readability (mruby design priority)
2146- * - Compatible with mruby's embedded/memory-constrained environment
2147- * - Uses established pattern from kernel.c inspect_recursive_p implementation
2148- */
2149-
2150- static mrb_bool
2151- hash_eql_recursive_p (mrb_state * mrb , mrb_value obj )
2152- {
2153- /* Look for recursive eql? calls on the same object in the call stack
2154- * Start from ci[-2] to skip current call frame (ci[-1] is __eql_recursive_p?, ci[0] is eql?)
2155- */
2156- for (mrb_callinfo * ci = & mrb -> c -> ci [-2 ]; ci >=mrb -> c -> cibase ; ci -- ) {
2157- if (ci -> mid == MRB_SYM_Q (eql ) &&
2158- mrb_obj_eq (mrb , obj , ci -> stack [0 ])) {
2159- return TRUE;
2160- }
2161- }
2162- return FALSE;
2163- }
2164-
2165- static mrb_bool
2166- hash_equal_recursive_p (mrb_state * mrb , mrb_value obj )
2167- {
2168- /* Look for recursive == calls on the same object in the call stack */
2169- for (mrb_callinfo * ci = & mrb -> c -> ci [-2 ]; ci >=mrb -> c -> cibase ; ci -- ) {
2170- if (ci -> mid == MRB_OPSYM (eq ) &&
2171- mrb_obj_eq (mrb , obj , ci -> stack [0 ])) {
2172- return TRUE;
2173- }
2174- }
2175- return FALSE;
2176- }
2177-
2178- static mrb_value
2179- mrb_hash_eql_recursive_p (mrb_state * mrb , mrb_value self )
2180- {
2181- return mrb_bool_value (hash_eql_recursive_p (mrb , self ));
2182- }
2183-
21842128/* 15.2.13.4.1 */
21852129static mrb_value
21862130mrb_hash_equal (mrb_state * mrb , mrb_value hash )
@@ -2313,5 +2257,4 @@ mrb_init_hash(mrb_state *mrb)
23132257 mrb_define_method_id (mrb , h , MRB_SYM (rassoc ), mrb_hash_rassoc , MRB_ARGS_REQ (1 ));
23142258 mrb_define_method_id (mrb , h , MRB_SYM (__merge ), mrb_hash_merge_m , MRB_ARGS_REQ (1 ));
23152259 mrb_define_method_id (mrb , h , MRB_SYM (__compact ), mrb_hash_compact , MRB_ARGS_NONE ()); /* implementation of Hash#compact! */
2316- mrb_define_private_method_id (mrb , h , MRB_SYM_Q (__eql_recursive_p ), mrb_hash_eql_recursive_p , MRB_ARGS_NONE ()); /* recursion detection for Hash#eql? */
23172260}
0 commit comments