void qd_alloc_finalize()

in src/alloc_pool.c [526:669]


void qd_alloc_finalize(void)
{
    //
    // Note that the logging facility is already finalized by the time this is called.
    // We will dump debugging information into debug_dump if specified.
    //
    // The assumption coming into this finalizer is that all allocations have been
    // released.  Any non-released objects shall be flagged.
    //

    //
    // Note: By the time we get here, the server threads have been joined and there is
    //       only the main thread remaining.  There is therefore no reason to be
    //       concerned about locking.
    //

    qd_alloc_item_t *item;
    qd_alloc_type_t *type_item = DEQ_HEAD(type_list);
#ifdef QD_MEMORY_DEBUG
    const char *last_leak = 0;
#endif

    FILE *dump_file = 0;
    if (debug_dump) {
        dump_file = fopen(debug_dump, "w");
    }
#if QD_MEMORY_DEBUG
    // For memory debug builds make it very hard to ignore leaks
    else {
        dump_file = stderr;
    }
#endif

    while (type_item) {
        qd_entity_cache_remove(QD_ALLOCATOR_TYPE, type_item);
        qd_alloc_type_desc_t *desc = type_item->desc;

        //
        // Reclaim the items on the global free pool
        //
        item = pop_stack(&desc->global_pool->free_list);
        while (item) {
            FREE_CACHE_ALIGNED(item);
            desc->stats->total_free_to_heap++;
            item = pop_stack(&desc->global_pool->free_list);
        }
        free_stack_chunks(&desc->global_pool->free_list);
        free(desc->global_pool);
        desc->global_pool = 0;
        desc->header = 0;  // reset header, so we can initialize again later in qd_alloc (in subsequent test)

        //
        // Reclaim the items on thread pools
        //
        qd_alloc_pool_t *tpool = DEQ_HEAD(desc->tpool_list);
        while (tpool) {
            item = pop_stack(&tpool->free_list);
            while (item) {
                FREE_CACHE_ALIGNED(item);
                desc->stats->total_free_to_heap++;
                item = pop_stack(&tpool->free_list);
            }
            DEQ_REMOVE_HEAD(desc->tpool_list);
            free_stack_chunks(&tpool->free_list);
            FREE_CACHE_ALIGNED(tpool);
            tpool = DEQ_HEAD(desc->tpool_list);
        }

        //
        // Check the stats for lost items
        //
        if (dump_file && desc->stats->total_free_to_heap < desc->stats->total_alloc_from_heap) {
            bool suppressed = false;
            for (int i = 0; leaking_types[i]; ++i) {
                if (strcmp(desc->type_name, leaking_types[i]) == 0) {
                    suppressed = true;
                    break;
                }
            }
            fprintf(dump_file,
                    "alloc.c: Items of type '%s' remain allocated at shutdown: %"PRId64"%s\n",
                    desc->type_name,
                    desc->stats->total_alloc_from_heap - desc->stats->total_free_to_heap,
                    suppressed ? " (SUPPRESSED)" : "");

#ifdef QD_MEMORY_DEBUG
            qd_alloc_type_t *qtype = (qd_alloc_type_t*) desc->debug;
            qd_alloc_item_t *item = DEQ_HEAD(qtype->allocated);
            char buf[100];
            while (item) {
                DEQ_REMOVE_HEAD(qtype->allocated);
                char **strings = backtrace_symbols(item->backtrace, item->backtrace_size);

                if (!suppressed) {
                    // DISPATCH-1795: avoid output noise by only printing
                    // backtraces for leaks that are not suppressed
                    qd_log_formatted_time(&item->timestamp, buf, 100);
                    fprintf(dump_file, "Leak: %s type: %s address: %p\n",
                            buf, desc->type_name, (void *)(&item[1]));
                    for (size_t i = 0; i < item->backtrace_size; i++)
                        fprintf(dump_file, "%s\n", strings[i]);
                    fprintf(dump_file, "\n");
                    last_leak = desc->type_name;
                }
                free(strings);

                // free the item to prevent ASAN from also reporting this leak.
                // Since this is a custom heap ASAN will dump the first
                // malloc() of the object - not the last time it was allocated
                // from the pool.
                FREE_CACHE_ALIGNED(item);
                item = DEQ_HEAD(qtype->allocated);
            }
#endif
        }

        //
        // Reclaim the descriptor components
        //
        free(desc->stats);
        sys_mutex_free(desc->lock);
        desc->lock = 0;
        desc->trailer = 0;

        DEQ_REMOVE_HEAD(type_list);
        free(type_item);
        type_item = DEQ_HEAD(type_list);
    }

    sys_mutex_free(init_lock);
    if (debug_dump) {
        fclose(dump_file);
        free(debug_dump);
        debug_dump = 0;
    }

#ifdef QD_MEMORY_DEBUG
    if (last_leak) {
        fprintf(stderr, "ERROR: Aborted due to unexpected alloc pool leak of type '%s'\n", last_leak);
        fflush(0);
        abort();
    }
#endif
}