|
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
|