| /*****************************************************************************\ |
| * 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); |
| } |