Fix memory leak in autoload_data

If the autoload_data has autoload_const and the autoload_data is freed
before the autoload_const, then the autoload_data will leak.

This commit changes it so that when the autoload_data is freed, it will
clear the whole linked list of autoload_const so that the autoload_data
can be safely freed.

    1000.times do |i|
      str = "foo#{i}".freeze

      autoload(:"B#{i}", str)
      autoload(:"C#{i}", str)
    end

Reports leaked memory with the macOS leaks tool:

    12  ruby                                  0x1006398a4 rb_f_autoload + 96  load.c:1524
    11  ruby                                  0x100639710 rb_mod_autoload + 112  load.c:1460
    10  ruby                                  0x10080a914 rb_autoload_str + 224  variable.c:2666
    9   ruby                                  0x1007c3308 rb_mutex_synchronize + 56  thread_sync.c:637
    8   ruby                                  0x1005acb24 rb_ensure + 312  eval.c:1009
    7   ruby                                  0x10080aac8 autoload_synchronized + 204  variable.c:2630
    6   ruby                                  0x10080f8bc autoload_feature_lookup_or_create + 76  variable.c:2578
    5   ruby                                  0x1005c29a4 rb_data_typed_object_zalloc + 232  gc.c:3186
    4   ruby                                  0x1005c2774 ruby_xcalloc + 32  gc.c:14440
    3   ruby                                  0x1005cddf4 ruby_xcalloc_body + 56  gc.c:12878
    2   ruby                                  0x1005cde7c objspace_xcalloc + 124  gc.c:12871
    1   ruby                                  0x1005c1990 calloc1 + 28  gc.c:1906
    0   libsystem_malloc.dylib                0x18b2ebb78 _malloc_zone_calloc_instrumented_or_legacy + 100
This commit is contained in:
Peter Zhu 2024-01-05 17:14:16 -05:00
parent 8b86d6f0c1
commit 11286ac479

View File

@ -2460,10 +2460,12 @@ autoload_data_free(void *ptr)
{
struct autoload_data *p = ptr;
// We may leak some memory at VM shutdown time, no big deal...?
if (ccan_list_empty(&p->constants)) {
ruby_xfree(p);
struct autoload_const *autoload_const, *next;
ccan_list_for_each_safe(&p->constants, autoload_const, next, cnode) {
ccan_list_del_init(&autoload_const->cnode);
}
ruby_xfree(p);
}
static size_t