Blame lib/memory.c

Packit Service 5956c7
/*
Packit Service 5956c7
 * Soft:        Keepalived is a failover program for the LVS project
Packit Service 5956c7
 *              <www.linuxvirtualserver.org>. It monitor & manipulate
Packit Service 5956c7
 *              a loadbalanced server pool using multi-layer checks.
Packit Service 5956c7
 *
Packit Service 5956c7
 * Part:        Memory management framework. This framework is used to
Packit Service 5956c7
 *              find any memory leak.
Packit Service 5956c7
 *
Packit Service 5956c7
 * Authors:     Alexandre Cassen, <acassen@linux-vs.org>
Packit Service 5956c7
 *              Jan Holmberg, <jan@artech.net>
Packit Service 5956c7
 *
Packit Service 5956c7
 *              This program is distributed in the hope that it will be useful,
Packit Service 5956c7
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 5956c7
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit Service 5956c7
 *              See the GNU General Public License for more details.
Packit Service 5956c7
 *
Packit Service 5956c7
 *              This program is free software; you can redistribute it and/or
Packit Service 5956c7
 *              modify it under the terms of the GNU General Public License
Packit Service 5956c7
 *              as published by the Free Software Foundation; either version
Packit Service 5956c7
 *              2 of the License, or (at your option) any later version.
Packit Service 5956c7
 *
Packit Service 5956c7
 * Copyright (C) 2001-2017 Alexandre Cassen, <acassen@gmail.com>
Packit Service 5956c7
 */
Packit Service 5956c7
Packit Service 5956c7
#include "config.h"
Packit Service 5956c7
Packit Service 5956c7
#ifdef _MEM_CHECK_
Packit Service 5956c7
#include <assert.h>
Packit Service 5956c7
#include <unistd.h>
Packit Service 5956c7
#include <fcntl.h>
Packit Service 5956c7
#include <stdlib.h>
Packit Service 5956c7
#include <time.h>
Packit Service 5956c7
#include <limits.h>
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
#include <errno.h>
Packit Service 5956c7
#include <string.h>
Packit Service 5956c7
Packit Service 5956c7
#include "memory.h"
Packit Service 5956c7
#include "utils.h"
Packit Service 5956c7
#include "bitops.h"
Packit Service 5956c7
#include "logger.h"
Packit Service 5956c7
#include "scheduler.h"
Packit Service 5956c7
Packit Service 5956c7
#ifdef _MEM_CHECK_
Packit Service 5956c7
#include "timer.h"
Packit Service 5956c7
#include "rbtree.h"
Packit Service 5956c7
#include "list_head.h"
Packit Service 5956c7
Packit Service 5956c7
/* Global var */
Packit Service 5956c7
size_t mem_allocated;			/* Total memory used in Bytes */
Packit Service 5956c7
static size_t max_mem_allocated;	/* Maximum memory used in Bytes */
Packit Service 5956c7
Packit Service 5956c7
static const char *terminate_banner;	/* banner string for report file */
Packit Service 5956c7
Packit Service 5956c7
static bool skip_mem_check_final;
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
static void *
Packit Service 5956c7
xalloc(unsigned long size)
Packit Service 5956c7
{
Packit Service 5956c7
	void *mem = malloc(size);
Packit Service 5956c7
Packit Service 5956c7
	if (mem == NULL) {
Packit Service 5956c7
		if (__test_bit(DONT_FORK_BIT, &debug))
Packit Service 5956c7
			perror("Keepalived");
Packit Service 5956c7
		else
Packit Service 5956c7
			log_message(LOG_INFO, "Keepalived xalloc() error - %s", strerror(errno));
Packit Service 5956c7
		exit(KEEPALIVED_EXIT_NO_MEMORY);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
#ifdef _MEM_CHECK_
Packit Service 5956c7
	mem_allocated += size - sizeof(long);
Packit Service 5956c7
	if (mem_allocated > max_mem_allocated)
Packit Service 5956c7
		max_mem_allocated = mem_allocated;
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
	return mem;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void *
Packit Service 5956c7
zalloc(unsigned long size)
Packit Service 5956c7
{
Packit Service 5956c7
	void *mem = xalloc(size);
Packit Service 5956c7
Packit Service 5956c7
	if (mem)
Packit Service 5956c7
		memset(mem, 0, size);
Packit Service 5956c7
Packit Service 5956c7
	return mem;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* KeepAlived memory management. in debug mode,
Packit Service 5956c7
 * help finding eventual memory leak.
Packit Service 5956c7
 * Allocation memory types manipulated are :
Packit Service 5956c7
 *
Packit Service 5956c7
 * +-type------------------+-meaning------------------+
Packit Service 5956c7
 * ! FREE_SLOT             ! Free slot                !
Packit Service 5956c7
 * ! OVERRUN               ! Overrun                  !
Packit Service 5956c7
 * ! FREE_NULL             ! free null                !
Packit Service 5956c7
 * ! REALLOC_NULL          ! realloc null             !
Packit Service 5956c7
 * ! DOUBLE_FREE           ! double free              !
Packit Service 5956c7
 * ! REALLOC_DOUBLE_FREE   ! realloc freed block      !
Packit Service 5956c7
 * ! FREE_NOT_ALLOC        ! Not previously allocated !
Packit Service 5956c7
 * ! REALLOC_NOT_ALLOC     ! Not previously allocated !
Packit Service 5956c7
 * ! MALLOC_ZERO_SIZE      ! malloc with size 0       !
Packit Service 5956c7
 * ! REALLOC_ZERO_SIZE     ! realloc with size 0      !
Packit Service 5956c7
 * ! LAST_FREE             ! Last free list           !
Packit Service 5956c7
 * ! ALLOCATED             ! Allocated                !
Packit Service 5956c7
 * +-----------------------+--------------------------+
Packit Service 5956c7
 *
Packit Service 5956c7
 * global variable debug bit MEM_ERR_DETECT_BIT used to
Packit Service 5956c7
 * flag some memory error.
Packit Service 5956c7
 *
Packit Service 5956c7
 */
Packit Service 5956c7
Packit Service 5956c7
#ifdef _MEM_CHECK_
Packit Service 5956c7
Packit Service 5956c7
enum slot_type {
Packit Service 5956c7
	FREE_SLOT = 0,
Packit Service 5956c7
	OVERRUN,
Packit Service 5956c7
	FREE_NULL,
Packit Service 5956c7
	REALLOC_NULL,
Packit Service 5956c7
	DOUBLE_FREE,
Packit Service 5956c7
	REALLOC_DOUBLE_FREE,
Packit Service 5956c7
	FREE_NOT_ALLOC,
Packit Service 5956c7
	REALLOC_NOT_ALLOC,
Packit Service 5956c7
	MALLOC_ZERO_SIZE,
Packit Service 5956c7
	REALLOC_ZERO_SIZE,
Packit Service 5956c7
	LAST_FREE,
Packit Service 5956c7
	ALLOCATED,
Packit Service 5956c7
} ;
Packit Service 5956c7
Packit Service 5956c7
#define TIME_STR_LEN	9
Packit Service 5956c7
Packit Service 5956c7
#if ULONG_MAX == 0xffffffffffffffffUL
Packit Service 5956c7
#define CHECK_VAL	0xa5a55a5aa5a55a5aUL
Packit Service 5956c7
#elif ULONG_MAX == 0xffffffffUL
Packit Service 5956c7
#define CHECK_VAL	0xa5a55a5aUL
Packit Service 5956c7
#else
Packit Service 5956c7
#define CHECK_VAL	0xa5a5
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
#define FREE_LIST_SIZE	256
Packit Service 5956c7
Packit Service 5956c7
typedef struct {
Packit Service 5956c7
	enum slot_type type;
Packit Service 5956c7
	int line;
Packit Service 5956c7
	const char *func;
Packit Service 5956c7
	const char *file;
Packit Service 5956c7
	void *ptr;
Packit Service 5956c7
	size_t size;
Packit Service 5956c7
	union {
Packit Service 5956c7
		list_head_t l;	/* When on free list */
Packit Service 5956c7
		rb_node_t t;
Packit Service 5956c7
	};
Packit Service 5956c7
	unsigned seq_num;
Packit Service 5956c7
} MEMCHECK;
Packit Service 5956c7
Packit Service 5956c7
/* Last free pointers */
Packit Service 5956c7
static LH_LIST_HEAD(free_list);
Packit Service 5956c7
static unsigned free_list_size;
Packit Service 5956c7
Packit Service 5956c7
/* alloc_list entries used for 1000 VRRP instance each with VMAC interfaces is 33589 */
Packit Service 5956c7
static rb_root_t alloc_list = RB_ROOT;
Packit Service 5956c7
static LH_LIST_HEAD(bad_list);
Packit Service 5956c7
Packit Service 5956c7
static unsigned number_alloc_list;	/* number of alloc_list allocation entries */
Packit Service 5956c7
static unsigned max_alloc_list;
Packit Service 5956c7
static unsigned num_mallocs;
Packit Service 5956c7
static unsigned num_reallocs;
Packit Service 5956c7
static unsigned seq_num;
Packit Service 5956c7
Packit Service 5956c7
static FILE *log_op = NULL;
Packit Service 5956c7
Packit Service 5956c7
static inline int
Packit Service 5956c7
memcheck_ptr_cmp(MEMCHECK *m1, MEMCHECK *m2)
Packit Service 5956c7
{
Packit Service 5956c7
	return m1->ptr - m2->ptr;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static inline int
Packit Service 5956c7
memcheck_seq_cmp(MEMCHECK *m1, MEMCHECK *m2)
Packit Service 5956c7
{
Packit Service 5956c7
	return m1->seq_num - m2->seq_num;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static const char *
Packit Service 5956c7
format_time(void)
Packit Service 5956c7
{
Packit Service 5956c7
	static char time_buf[TIME_STR_LEN+1];
Packit Service 5956c7
Packit Service 5956c7
	strftime(time_buf, sizeof time_buf, "%T ", localtime(&time_now.tv_sec));
Packit Service 5956c7
Packit Service 5956c7
	return time_buf;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
memcheck_log(const char *called_func, const char *param, const char *file, const char *function, int line)
Packit Service 5956c7
{
Packit Service 5956c7
	int len = strlen(called_func) + (param ? strlen(param) : 0);
Packit Service 5956c7
Packit Service 5956c7
	if ((len = 36 - len) < 0)
Packit Service 5956c7
		len = 0;
Packit Service 5956c7
Packit Service 5956c7
	fprintf(log_op, "%s%*s%s(%s) at %s, %d, %s\n",
Packit Service 5956c7
	       format_time(), len, "", called_func, param ? param : "", file, line, function);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static MEMCHECK *
Packit Service 5956c7
get_free_alloc_entry(void)
Packit Service 5956c7
{
Packit Service 5956c7
	MEMCHECK *entry;
Packit Service 5956c7
Packit Service 5956c7
	/* If number on free list < 256, allocate new entry, otherwise take head */
Packit Service 5956c7
	if (free_list_size < 256)
Packit Service 5956c7
		entry = malloc(sizeof *entry);
Packit Service 5956c7
	else {
Packit Service 5956c7
		entry = list_first_entry(&free_list, MEMCHECK, l);
Packit Service 5956c7
		list_head_del(&entry->l);
Packit Service 5956c7
		free_list_size--;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	entry->seq_num = seq_num++;
Packit Service 5956c7
Packit Service 5956c7
	return entry;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void *
Packit Service 5956c7
keepalived_malloc(size_t size, const char *file, const char *function, int line)
Packit Service 5956c7
{
Packit Service 5956c7
	void *buf;
Packit Service 5956c7
	MEMCHECK *entry, *entry2;
Packit Service 5956c7
Packit Service 5956c7
	buf = zalloc(size + sizeof (unsigned long));
Packit Service 5956c7
Packit Service 5956c7
	*(unsigned long *) ((char *) buf + size) = size + CHECK_VAL;
Packit Service 5956c7
Packit Service 5956c7
	entry = get_free_alloc_entry();
Packit Service 5956c7
Packit Service 5956c7
	entry->ptr = buf;
Packit Service 5956c7
	entry->size = size;
Packit Service 5956c7
	entry->file = file;
Packit Service 5956c7
	entry->func = function;
Packit Service 5956c7
	entry->line = line;
Packit Service 5956c7
	entry->type = ALLOCATED;
Packit Service 5956c7
Packit Service 5956c7
	rb_insert_sort(&alloc_list, entry, t, memcheck_ptr_cmp);
Packit Service 5956c7
	if (++number_alloc_list > max_alloc_list)
Packit Service 5956c7
		max_alloc_list = number_alloc_list;
Packit Service 5956c7
Packit Service 5956c7
	fprintf(log_op, "%szalloc [%3d:%3d], %9p, %4zu at %s, %3d, %s%s\n",
Packit Service 5956c7
	       format_time(), entry->seq_num, number_alloc_list, buf, size, file, line, function, !size ? " - size is 0" : "");
Packit Service 5956c7
#ifdef _MEM_CHECK_LOG_
Packit Service 5956c7
	if (__test_bit(MEM_CHECK_LOG_BIT, &debug))
Packit Service 5956c7
		log_message(LOG_INFO, "zalloc[%3d:%3d], %9p, %4zu at %s, %3d, %s",
Packit Service 5956c7
		       entry->seq_num, number_alloc_list, buf, size, file, line, function);
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
	num_mallocs++;
Packit Service 5956c7
Packit Service 5956c7
	if (!size) {
Packit Service 5956c7
		/* Record malloc with 0 size */
Packit Service 5956c7
		entry2 = get_free_alloc_entry();
Packit Service 5956c7
		*entry2 = *entry;
Packit Service 5956c7
		entry2->type = MALLOC_ZERO_SIZE;
Packit Service 5956c7
		list_add_tail(&entry2->l, &bad_list);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	return buf;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static void *
Packit Service 5956c7
keepalived_free_realloc_common(void *buffer, size_t size, const char *file, const char *function, int line, bool is_realloc)
Packit Service 5956c7
{
Packit Service 5956c7
	unsigned long check;
Packit Service 5956c7
	MEMCHECK *entry, *entry2, *le;
Packit Service 5956c7
	MEMCHECK search = {.ptr = buffer};
Packit Service 5956c7
Packit Service 5956c7
	/* If nullpointer remember */
Packit Service 5956c7
	if (buffer == NULL) {
Packit Service 5956c7
		entry = get_free_alloc_entry();
Packit Service 5956c7
Packit Service 5956c7
		entry->ptr = NULL;
Packit Service 5956c7
		entry->size = size;
Packit Service 5956c7
		entry->file = file;
Packit Service 5956c7
		entry->func = function;
Packit Service 5956c7
		entry->line = line;
Packit Service 5956c7
		entry->type = !size ? FREE_NULL : REALLOC_NULL;
Packit Service 5956c7
Packit Service 5956c7
		if (!is_realloc)
Packit Service 5956c7
			fprintf(log_op, "%s%-7s%9s, %9s, %4s at %s, %3d, %s\n", format_time(),
Packit Service 5956c7
				"free", "ERROR", "NULL", "",
Packit Service 5956c7
				file, line, function);
Packit Service 5956c7
		else
Packit Service 5956c7
			fprintf(log_op, "%s%-7s%9s, %9s, %4zu at %s, %3d, %s%s\n", format_time(),
Packit Service 5956c7
				"realloc", "ERROR", "NULL",
Packit Service 5956c7
				size, file, line, function, size ? " *** converted to malloc" : "");
Packit Service 5956c7
Packit Service 5956c7
		__set_bit(MEM_ERR_DETECT_BIT, &debug);
Packit Service 5956c7
Packit Service 5956c7
		list_add_tail(&entry->l, &bad_list);
Packit Service 5956c7
Packit Service 5956c7
		return !size ? NULL : keepalived_malloc(size, file, function, line);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	entry = rb_search(&alloc_list, &search, t, memcheck_ptr_cmp);
Packit Service 5956c7
Packit Service 5956c7
	/* Not found */
Packit Service 5956c7
	if (!entry) {
Packit Service 5956c7
		entry = get_free_alloc_entry();
Packit Service 5956c7
Packit Service 5956c7
		entry->ptr = buffer;
Packit Service 5956c7
		entry->size = size;
Packit Service 5956c7
		entry->file = file;
Packit Service 5956c7
		entry->func = function;
Packit Service 5956c7
		entry->line = line;
Packit Service 5956c7
		entry->type = !size ? FREE_NOT_ALLOC : REALLOC_NOT_ALLOC;
Packit Service 5956c7
		entry->seq_num = seq_num++;
Packit Service 5956c7
Packit Service 5956c7
		if (!is_realloc)
Packit Service 5956c7
			fprintf(log_op, "%s%-7s%9s, %9p,      at %s, %3d, %s - not found\n", format_time(),
Packit Service 5956c7
				"free", "ERROR",
Packit Service 5956c7
				buffer, file, line, function);
Packit Service 5956c7
		else
Packit Service 5956c7
			fprintf(log_op, "%s%-7s%9s, %9p, %4zu at %s, %3d, %s - not found\n", format_time(),
Packit Service 5956c7
				"realloc", "ERROR",
Packit Service 5956c7
				buffer, size, file, line, function);
Packit Service 5956c7
Packit Service 5956c7
		__set_bit(MEM_ERR_DETECT_BIT, &debug);
Packit Service 5956c7
Packit Service 5956c7
		list_for_each_entry_reverse(le, &free_list, l) {
Packit Service 5956c7
			if (le->ptr == buffer &&
Packit Service 5956c7
			    le->type == LAST_FREE) {
Packit Service 5956c7
				fprintf
Packit Service 5956c7
				    (log_op, "%11s-> pointer last released at [%3d:%3d], at %s, %3d, %s\n",
Packit Service 5956c7
				     "", le->seq_num, number_alloc_list,
Packit Service 5956c7
				     le->file, le->line,
Packit Service 5956c7
				     le->func);
Packit Service 5956c7
Packit Service 5956c7
				entry->type = !size ? DOUBLE_FREE : REALLOC_DOUBLE_FREE;
Packit Service 5956c7
				break;
Packit Service 5956c7
			}
Packit Service 5956c7
		};
Packit Service 5956c7
Packit Service 5956c7
		list_add_tail(&entry->l, &bad_list);
Packit Service 5956c7
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	check = entry->size + CHECK_VAL;
Packit Service 5956c7
	if (*(unsigned long *)((char *)buffer + entry->size) != check) {
Packit Service 5956c7
		entry2 = get_free_alloc_entry();
Packit Service 5956c7
Packit Service 5956c7
		*entry2 = *entry;
Packit Service 5956c7
		entry2->type = OVERRUN;
Packit Service 5956c7
		list_add_tail(&entry2->l, &bad_list);
Packit Service 5956c7
Packit Service 5956c7
		fprintf(log_op, "%s%s corrupt, buffer overrun [%3d:%3d], %9p, %4zu at %s, %3d, %s\n",
Packit Service 5956c7
		       format_time(), !is_realloc ? "free" : "realloc",
Packit Service 5956c7
		       entry->seq_num, number_alloc_list, buffer,
Packit Service 5956c7
		       entry->size, file,
Packit Service 5956c7
		       line, function);
Packit Service 5956c7
		dump_buffer(entry->ptr,
Packit Service 5956c7
			    entry->size + sizeof (check), log_op, TIME_STR_LEN);
Packit Service 5956c7
		fprintf(log_op, "%*sCheck_sum\n", TIME_STR_LEN, "");
Packit Service 5956c7
		dump_buffer((char *) &check,
Packit Service 5956c7
			    sizeof(check), log_op, TIME_STR_LEN);
Packit Service 5956c7
Packit Service 5956c7
		__set_bit(MEM_ERR_DETECT_BIT, &debug);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	mem_allocated -= entry->size;
Packit Service 5956c7
Packit Service 5956c7
	if (!size) {
Packit Service 5956c7
		free(buffer);
Packit Service 5956c7
Packit Service 5956c7
		if (is_realloc) {
Packit Service 5956c7
			fprintf(log_op, "%s%-7s[%3d:%3d], %9p, %4zu at %s, %3d, %s -> %9s, %4s at %s, %3d, %s\n",
Packit Service 5956c7
			       format_time(), "realloc", entry->seq_num,
Packit Service 5956c7
			       number_alloc_list, entry->ptr,
Packit Service 5956c7
			       entry->size, entry->file,
Packit Service 5956c7
			       entry->line, entry->func,
Packit Service 5956c7
			       "made free", "", file, line, function);
Packit Service 5956c7
Packit Service 5956c7
			/* Record bad realloc */
Packit Service 5956c7
			entry2 = get_free_alloc_entry();
Packit Service 5956c7
			*entry2 = *entry;
Packit Service 5956c7
			entry2->type = REALLOC_ZERO_SIZE;
Packit Service 5956c7
			entry2->file = file;
Packit Service 5956c7
			entry2->line = line;
Packit Service 5956c7
			entry2->func = function;
Packit Service 5956c7
			list_add_tail(&entry2->l, &bad_list);
Packit Service 5956c7
		}
Packit Service 5956c7
		else
Packit Service 5956c7
			fprintf(log_op, "%s%-7s[%3d:%3d], %9p, %4zu at %s, %3d, %s -> %9s, %4s at %s, %3d, %s\n",
Packit Service 5956c7
			       format_time(), "free", entry->seq_num,
Packit Service 5956c7
			       number_alloc_list, entry->ptr,
Packit Service 5956c7
			       entry->size, entry->file,
Packit Service 5956c7
			       entry->line, entry->func,
Packit Service 5956c7
			       "NULL", "", file, line, function);
Packit Service 5956c7
#ifdef _MEM_CHECK_LOG_
Packit Service 5956c7
		if (__test_bit(MEM_CHECK_LOG_BIT, &debug))
Packit Service 5956c7
			log_message(LOG_INFO, "%-7s[%3d:%3d], %9p, %4zu at %s, %3d, %s",
Packit Service 5956c7
			       is_realloc ? "realloc" : "free",
Packit Service 5956c7
			       entry->seq_num, number_alloc_list, buffer,
Packit Service 5956c7
			       entry->size, file, line, function);
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
		entry->file = file;
Packit Service 5956c7
		entry->line = line;
Packit Service 5956c7
		entry->func = function;
Packit Service 5956c7
		entry->type = LAST_FREE;
Packit Service 5956c7
Packit Service 5956c7
		rb_erase(&entry->t, &alloc_list);
Packit Service 5956c7
		list_add_tail(&entry->l, &free_list);
Packit Service 5956c7
		free_list_size++;
Packit Service 5956c7
Packit Service 5956c7
		number_alloc_list--;
Packit Service 5956c7
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	buffer = realloc(buffer, size + sizeof (unsigned long));
Packit Service 5956c7
	mem_allocated += size;
Packit Service 5956c7
Packit Service 5956c7
	if (mem_allocated > max_mem_allocated)
Packit Service 5956c7
		max_mem_allocated = mem_allocated;
Packit Service 5956c7
Packit Service 5956c7
	fprintf(log_op, "%srealloc[%3d:%3d], %9p, %4zu at %s, %3d, %s -> %9p, %4zu at %s, %3d, %s\n",
Packit Service 5956c7
	       format_time(), entry->seq_num,
Packit Service 5956c7
	       number_alloc_list, entry->ptr,
Packit Service 5956c7
	       entry->size, entry->file,
Packit Service 5956c7
	       entry->line, entry->func,
Packit Service 5956c7
	       buffer, size, file, line, function);
Packit Service 5956c7
#ifdef _MEM_CHECK_LOG_
Packit Service 5956c7
	if (__test_bit(MEM_CHECK_LOG_BIT, &debug))
Packit Service 5956c7
		log_message(LOG_INFO, "realloc[%3d:%3d], %9p, %4zu at %s, %3d, %s -> %9p, %4zu at %s, %3d, %s",
Packit Service 5956c7
		       entry->seq_num, number_alloc_list, entry->ptr,
Packit Service 5956c7
		       entry->size, entry->file,
Packit Service 5956c7
		       entry->line, entry->func,
Packit Service 5956c7
		       buffer, size, file, line, function);
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
	*(unsigned long *) ((char *) buffer + size) = size + CHECK_VAL;
Packit Service 5956c7
Packit Service 5956c7
	if (entry->ptr != buffer) {
Packit Service 5956c7
		rb_erase(&entry->t, &alloc_list);
Packit Service 5956c7
		entry->ptr = buffer;
Packit Service 5956c7
		rb_insert_sort(&alloc_list, entry, t, memcheck_ptr_cmp);
Packit Service 5956c7
	} else
Packit Service 5956c7
		entry->ptr = buffer;
Packit Service 5956c7
	entry->size = size;
Packit Service 5956c7
	entry->file = file;
Packit Service 5956c7
	entry->line = line;
Packit Service 5956c7
	entry->func = function;
Packit Service 5956c7
Packit Service 5956c7
	num_reallocs++;
Packit Service 5956c7
Packit Service 5956c7
	return buffer;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
keepalived_free(void *buffer, const char *file, const char *function, int line)
Packit Service 5956c7
{
Packit Service 5956c7
	keepalived_free_realloc_common(buffer, 0, file, function, line, false);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void *
Packit Service 5956c7
keepalived_realloc(void *buffer, size_t size, const char *file,
Packit Service 5956c7
		   const char *function, int line)
Packit Service 5956c7
{
Packit Service 5956c7
	return keepalived_free_realloc_common(buffer, size, file, function, line, true);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static void
Packit Service 5956c7
keepalived_alloc_log(bool final)
Packit Service 5956c7
{
Packit Service 5956c7
	unsigned int overrun = 0, badptr = 0, zero_size = 0;
Packit Service 5956c7
	size_t sum = 0;
Packit Service 5956c7
	MEMCHECK *entry;
Packit Service 5956c7
Packit Service 5956c7
	if (final) {
Packit Service 5956c7
		/* If this is a forked child, we don't want the dump */
Packit Service 5956c7
		if (skip_mem_check_final)
Packit Service 5956c7
			return;
Packit Service 5956c7
Packit Service 5956c7
		fprintf(log_op, "\n---[ Keepalived memory dump for (%s) ]---\n\n", terminate_banner);
Packit Service 5956c7
	}
Packit Service 5956c7
	else
Packit Service 5956c7
		fprintf(log_op, "\n---[ Keepalived memory dump for (%s) at %s ]---\n\n", terminate_banner, format_time());
Packit Service 5956c7
Packit Service 5956c7
	/* List the blocks currently allocated */
Packit Service 5956c7
	if (!RB_EMPTY_ROOT(&alloc_list)) {
Packit Service 5956c7
		fprintf(log_op, "Entries %s\n\n", final ? "not released" : "currently allocated");
Packit Service 5956c7
		rb_for_each_entry(entry, &alloc_list, t) {
Packit Service 5956c7
			sum += entry->size;
Packit Service 5956c7
			fprintf(log_op, "%9p [%3d:%3d], %4zu at %s, %3d, %s",
Packit Service 5956c7
			       entry->ptr, entry->seq_num, number_alloc_list,
Packit Service 5956c7
			       entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
			if (entry->type != ALLOCATED)
Packit Service 5956c7
				fprintf(log_op, " type = %d", entry->type);
Packit Service 5956c7
			fprintf(log_op, "\n");
Packit Service 5956c7
		}
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	if (!list_empty(&bad_list)) {
Packit Service 5956c7
		if (!RB_EMPTY_ROOT(&alloc_list))
Packit Service 5956c7
			fprintf(log_op, "\n");
Packit Service 5956c7
		fprintf(log_op, "Bad entry list\n\n");
Packit Service 5956c7
Packit Service 5956c7
		list_for_each_entry(entry, &bad_list, l) {
Packit Service 5956c7
			switch (entry->type) {
Packit Service 5956c7
			case FREE_NULL:
Packit Service 5956c7
				badptr++;
Packit Service 5956c7
				fprintf(log_op, "%9s %9s, %4s at %s, %3d, %s - null pointer to free\n",
Packit Service 5956c7
				       "NULL", "", "", entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case REALLOC_NULL:
Packit Service 5956c7
				badptr++;
Packit Service 5956c7
				fprintf(log_op, "%9s %9s, %4zu at %s, %3d, %s - null pointer to realloc (converted to malloc)\n",
Packit Service 5956c7
				     "NULL", "", entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case FREE_NOT_ALLOC:
Packit Service 5956c7
				badptr++;
Packit Service 5956c7
				fprintf(log_op, "%9p %9s, %4s at %s, %3d, %s - pointer not found for free\n",
Packit Service 5956c7
				     entry->ptr, "", "", entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case REALLOC_NOT_ALLOC:
Packit Service 5956c7
				badptr++;
Packit Service 5956c7
				fprintf(log_op, "%9p %9s, %4zu at %s, %3d, %s - pointer not found for realloc\n",
Packit Service 5956c7
				     entry->ptr, "", entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case DOUBLE_FREE:
Packit Service 5956c7
				badptr++;
Packit Service 5956c7
				fprintf(log_op, "%9p %9s, %4s at %s, %3d, %s - double free of pointer\n",
Packit Service 5956c7
				     entry->ptr, "", "", entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case REALLOC_DOUBLE_FREE:
Packit Service 5956c7
				badptr++;
Packit Service 5956c7
				fprintf(log_op, "%9p %9s, %4zu at %s, %3d, %s - realloc 0 size already freed\n",
Packit Service 5956c7
				     entry->ptr, "", entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case OVERRUN:
Packit Service 5956c7
				overrun++;
Packit Service 5956c7
				fprintf(log_op, "%9p [%3d:%3d], %4zu at %s, %3d, %s - buffer overrun\n",
Packit Service 5956c7
				       entry->ptr, entry->seq_num, number_alloc_list,
Packit Service 5956c7
				       entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case MALLOC_ZERO_SIZE:
Packit Service 5956c7
				zero_size++;
Packit Service 5956c7
				fprintf(log_op, "%9p [%3d:%3d], %4zu at %s, %3d, %s - malloc zero size\n",
Packit Service 5956c7
				       entry->ptr, entry->seq_num, number_alloc_list,
Packit Service 5956c7
				       entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case REALLOC_ZERO_SIZE:
Packit Service 5956c7
				zero_size++;
Packit Service 5956c7
				fprintf(log_op, "%9p [%3d:%3d], %4zu at %s, %3d, %s - realloc zero size (handled as free)\n",
Packit Service 5956c7
				       entry->ptr, entry->seq_num, number_alloc_list,
Packit Service 5956c7
				       entry->size, entry->file, entry->line, entry->func);
Packit Service 5956c7
				break;
Packit Service 5956c7
			case ALLOCATED:	/* not used - avoid compiler warning */
Packit Service 5956c7
			case FREE_SLOT:
Packit Service 5956c7
			case LAST_FREE:
Packit Service 5956c7
				break;
Packit Service 5956c7
			}
Packit Service 5956c7
		}
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	fprintf(log_op, "\n\n---[ Keepalived memory dump summary for (%s) ]---\n", terminate_banner);
Packit Service 5956c7
	fprintf(log_op, "Total number of bytes %s...: %zu\n", final ? "not freed" : "allocated", sum);
Packit Service 5956c7
	fprintf(log_op, "Number of entries %s.......: %d\n", final ? "not freed" : "allocated", number_alloc_list);
Packit Service 5956c7
	fprintf(log_op, "Maximum allocated entries.........: %d\n", max_alloc_list);
Packit Service 5956c7
	fprintf(log_op, "Maximum memory allocated..........: %zu\n", max_mem_allocated);
Packit Service 5956c7
	fprintf(log_op, "Number of mallocs.................: %d\n", num_mallocs);
Packit Service 5956c7
	fprintf(log_op, "Number of reallocs................: %d\n", num_reallocs);
Packit Service 5956c7
	fprintf(log_op, "Number of bad entries.............: %d\n", badptr);
Packit Service 5956c7
	fprintf(log_op, "Number of buffer overrun..........: %d\n", overrun);
Packit Service 5956c7
	fprintf(log_op, "Number of 0 size allocations......: %d\n\n", zero_size);
Packit Service 5956c7
	if (sum != mem_allocated)
Packit Service 5956c7
		fprintf(log_op, "ERROR - sum of allocated %zu != mem_allocated %zu\n", sum, mem_allocated);
Packit Service 5956c7
Packit Service 5956c7
	if (final) {
Packit Service 5956c7
		if (sum || number_alloc_list || badptr || overrun)
Packit Service 5956c7
			fprintf(log_op, "=> Program seems to have some memory problem !!!\n\n");
Packit Service 5956c7
		else
Packit Service 5956c7
			fprintf(log_op, "=> Program seems to be memory allocation safe...\n\n");
Packit Service 5956c7
	}
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static void
Packit Service 5956c7
keepalived_free_final(void)
Packit Service 5956c7
{
Packit Service 5956c7
	keepalived_alloc_log(true);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
keepalived_alloc_dump(void)
Packit Service 5956c7
{
Packit Service 5956c7
	keepalived_alloc_log(false);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
mem_log_init(const char* prog_name, const char *banner)
Packit Service 5956c7
{
Packit Service 5956c7
	size_t log_name_len;
Packit Service 5956c7
	char *log_name;
Packit Service 5956c7
Packit Service 5956c7
	if (__test_bit(LOG_CONSOLE_BIT, &debug)) {
Packit Service 5956c7
		log_op = stderr;
Packit Service 5956c7
		return;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	if (log_op)
Packit Service 5956c7
		fclose(log_op);
Packit Service 5956c7
Packit Service 5956c7
	log_name_len = 5 + strlen(prog_name) + 5 + 7 + 4 + 1;	/* "/tmp/" + prog_name + "_mem." + PID + ".log" + '\0" */
Packit Service 5956c7
	log_name = malloc(log_name_len);
Packit Service 5956c7
	if (!log_name) {
Packit Service 5956c7
		log_message(LOG_INFO, "Unable to malloc log file name");
Packit Service 5956c7
		log_op = stderr;
Packit Service 5956c7
		return;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	snprintf(log_name, log_name_len, "/tmp/%s_mem.%d.log", prog_name, getpid());
Packit Service 5956c7
	log_op = fopen_safe(log_name, "w");
Packit Service 5956c7
	if (log_op == NULL) {
Packit Service 5956c7
		log_message(LOG_INFO, "Unable to open %s for appending", log_name);
Packit Service 5956c7
		log_op = stderr;
Packit Service 5956c7
	}
Packit Service 5956c7
	else {
Packit Service 5956c7
		int fd = fileno(log_op);
Packit Service 5956c7
Packit Service 5956c7
		/* We don't want any children to inherit the log file */
Packit Service 5956c7
		fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
Packit Service 5956c7
Packit Service 5956c7
		/* Make the log output line buffered. This was to ensure that
Packit Service 5956c7
		 * children didn't inherit the buffer, but the CLOEXEC above
Packit Service 5956c7
		 * should resolve that. */
Packit Service 5956c7
		setlinebuf(log_op);
Packit Service 5956c7
Packit Service 5956c7
		fprintf(log_op, "\n");
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	free(log_name);
Packit Service 5956c7
Packit Service 5956c7
	terminate_banner = banner;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void skip_mem_dump(void)
Packit Service 5956c7
{
Packit Service 5956c7
	skip_mem_check_final = true;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void enable_mem_log_termination(void)
Packit Service 5956c7
{
Packit Service 5956c7
	atexit(keepalived_free_final);
Packit Service 5956c7
}
Packit Service 5956c7
#endif