@@ -156,6 +156,7 @@ struct dump_arg {
156156 st_table * data ;
157157 st_table * compat_tbl ;
158158 st_table * encodings ;
159+ st_table * userdefs ;
159160 st_index_t num_entries ;
160161};
161162
@@ -204,6 +205,7 @@ mark_dump_arg(void *ptr)
204205 rb_mark_set (p -> symbols );
205206 rb_mark_set (p -> data );
206207 rb_mark_hash (p -> compat_tbl );
208+ rb_mark_set (p -> userdefs );
207209 rb_gc_mark (p -> str );
208210}
209211
@@ -221,6 +223,7 @@ memsize_dump_arg(const void *ptr)
221223 if (p -> symbols ) memsize += rb_st_memsize (p -> symbols );
222224 if (p -> data ) memsize += rb_st_memsize (p -> data );
223225 if (p -> compat_tbl ) memsize += rb_st_memsize (p -> compat_tbl );
226+ if (p -> userdefs ) memsize += rb_st_memsize (p -> userdefs );
224227 if (p -> encodings ) memsize += rb_st_memsize (p -> encodings );
225228 return memsize ;
226229}
@@ -887,6 +890,9 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
887890 st_index_t hasiv2 ;
888891 VALUE encname2 ;
889892
893+ if (arg -> userdefs && st_is_member (arg -> userdefs , (st_data_t )obj )) {
894+ rb_raise (rb_eRuntimeError , "can't dump recursive object using _dump()" );
895+ }
890896 v = INT2NUM (limit );
891897 v = dump_funcall (arg , obj , s_dump , 1 , & v );
892898 if (!RB_TYPE_P (v , T_STRING )) {
@@ -903,7 +909,13 @@ w_object(VALUE obj, struct dump_arg *arg, int limit)
903909 w_class (TYPE_USERDEF , obj , arg , FALSE);
904910 w_bytes (RSTRING_PTR (v ), RSTRING_LEN (v ), arg );
905911 if (hasiv ) {
912+ st_data_t userdefs = (st_data_t )obj ;
913+ if (!arg -> userdefs ) {
914+ arg -> userdefs = rb_init_identtable ();
915+ }
916+ st_add_direct (arg -> userdefs , userdefs , 0 );
906917 w_ivar (hasiv , ivobj , encname , & c_arg );
918+ st_delete (arg -> userdefs , & userdefs , NULL );
907919 }
908920 w_remember (obj , arg );
909921 return ;
@@ -1110,6 +1122,10 @@ clear_dump_arg(struct dump_arg *arg)
11101122 st_free_table (arg -> encodings );
11111123 arg -> encodings = 0 ;
11121124 }
1125+ if (arg -> userdefs ) {
1126+ st_free_table (arg -> userdefs );
1127+ arg -> userdefs = 0 ;
1128+ }
11131129}
11141130
11151131NORETURN (static inline void io_needed (void ));
@@ -1187,6 +1203,7 @@ rb_marshal_dump_limited(VALUE obj, VALUE port, int limit)
11871203 arg -> num_entries = 0 ;
11881204 arg -> compat_tbl = 0 ;
11891205 arg -> encodings = 0 ;
1206+ arg -> userdefs = 0 ;
11901207 arg -> str = rb_str_buf_new (0 );
11911208 if (!NIL_P (port )) {
11921209 if (!rb_respond_to (port , s_write )) {
0 commit comments