blob: 2b56f362ef8f699a1d231807e8ed824456c331a0 [file] [log] [blame]
/*****************************************************************************\
* xmalloc.c - enhanced malloc routines
* Started with Jim Garlick's xmalloc and tied into slurm log facility.
* Also added ability to print file, line, and function of caller.
*****************************************************************************
* Copyright (C) 2002 The Regents of the University of California.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* Written by Jim Garlick <garlick1@llnl.gov> and
* Mark Grondona <mgrondona@llnl.gov>
* CODE-OCEC-09-009. All rights reserved.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along
* with Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include "config.h"
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "src/common/log.h"
#include "src/common/macros.h"
#include "src/common/xassert.h"
#include "src/common/xmalloc.h"
strong_alias(xfree_ptr, slurm_xfree_ptr);
strong_alias(xsize, slurm_xsize);
#define XMALLOC_MAGIC 0x42
/*
* "Safe" version of malloc().
* size (IN) number of bytes to malloc
* clear (IN) initialize to zero
* RETURN pointer to allocate heap space
*/
void *slurm_xcalloc(size_t count, size_t size, bool clear, bool try,
const char *file, int line, const char *func)
{
size_t total_size;
size_t count_size;
size_t *p;
if (!size || !count)
return NULL;
/*
* Detect overflow of the size calculation and abort().
* Ensure there is sufficient space for the two header words used to
* store the magic value and the allocation length by dividing by two,
* and because on 32-bit systems, if a 2GB allocation request isn't
* sufficient (which would attempt to allocate 2GB + 8Bytes),
* then we're going to run into other problems anyways.
* (And on 64-bit, if a 2EB + 16Bytes request isn't sufficient...)
*/
if ((count != 1) && (count > SIZE_MAX / size / 4)) {
if (try)
return NULL;
log_oom(file, line, func);
abort();
}
count_size = count * size;
total_size = count_size + 2 * sizeof(size_t);
if (clear)
p = calloc(1, total_size);
else
p = malloc(total_size);
if (!p && try) {
return NULL;
} else if (!p) {
/* out of memory */
log_oom(file, line, func);
abort();
}
p[0] = XMALLOC_MAGIC; /* add "secret" magic cookie */
p[1] = count_size; /* store size in buffer */
return &p[2];
}
/*
* "Safe" version of realloc() / reallocarray().
* Args are different: pass in a pointer to the object to be
* realloced instead of the object itself.
* item (IN/OUT) double-pointer to allocated space
* newcount (IN) requested count
* newsize (IN) requested size
* clear (IN) initialize to zero
*/
extern void * slurm_xrecalloc(void **item, size_t count, size_t size,
bool clear, bool try, const char *file,
int line, const char *func)
{
size_t total_size;
size_t count_size;
size_t *p;
if (!size || !count)
return NULL;
/*
* Detect overflow of the size calculation and abort().
* Ensure there is sufficient space for the two header words used to
* store the magic value and the allocation length by dividing by two,
* and because on 32-bit systems, if a 2GB allocation request isn't
* sufficient (which would attempt to allocate 2GB + 8Bytes),
* then we're going to run into other problems anyways.
* (And on 64-bit, if a 2EB + 16Bytes request isn't sufficient...)
*/
if ((count != 1) && (count > SIZE_MAX / size / 4))
goto error;
count_size = count * size;
total_size = count_size + 2 * sizeof(size_t);
if (*item != NULL) {
size_t old_size;
p = (size_t *)*item - 2;
/* magic cookie still there? */
xassert(p[0] == XMALLOC_MAGIC);
old_size = p[1];
p = realloc(p, total_size);
if (p == NULL)
goto error;
if (old_size < count_size) {
char *p_new = (char *)(&p[2]) + old_size;
if (clear)
memset(p_new, 0, (count_size - old_size));
}
xassert(p[0] == XMALLOC_MAGIC);
} else {
/* Initialize new memory */
if (clear)
p = calloc(1, total_size);
else
p = malloc(total_size);
if (p == NULL)
goto error;
p[0] = XMALLOC_MAGIC;
}
p[1] = count_size;
*item = &p[2];
return *item;
error:
if (try)
return NULL;
log_oom(file, line, func);
abort();
}
/*
* Return the size of a buffer.
* item (IN) pointer to allocated space
*/
size_t xsize(void *item)
{
size_t *p = (size_t *)item - 2;
xassert(item != NULL);
xassert(p[0] == XMALLOC_MAGIC); /* CLANG false positive here */
return p[1];
}
/*
* Free which takes a pointer to object to free, which it turns into a null
* object.
* item (IN/OUT) double-pointer to allocated space
*/
void slurm_xfree(void **item)
{
if (*item != NULL) {
size_t *p = (size_t *)*item - 2;
/* magic cookie still there? */
xassert(p[0] == XMALLOC_MAGIC);
p[0] = 0; /* make sure xfree isn't called twice */
free(p);
*item = NULL;
}
}
/*
* Free a NULL-terminated xmalloc()'d array of pointers to further xmalloc()'d
* elements, and NULL the original pointer to prevent accidental reuse.
*/
void slurm_xfree_array(void ***array)
{
if (!*array || !**array)
return;
for (int i = 0; (*array)[i]; i++)
xfree((*array)[i]);
xfree(*array);
}
/*
* Since xfree() is a macro it cannot be used for the ListDelF in list_create()
* and a number of locations where handling it as a function-pointer is
* desired. Use this wrapper to get around that problem.
*/
void xfree_ptr(void *ptr)
{
slurm_xfree(&ptr);
}