Move safe memory helper functions to dedicated memory.c and memory.h

This commit is contained in:
Andrea Mazzoleni 2026-07-13 22:54:45 +02:00
parent 07f7247fce
commit 4da1ab072b
5 changed files with 210 additions and 189 deletions

View file

@ -44,6 +44,7 @@ snapraid_SOURCES = \
cmdline/util.c \
cmdline/stream.c \
cmdline/support.c \
cmdline/memory.c \
cmdline/elem.c \
cmdline/state.c \
cmdline/scan.c \
@ -100,6 +101,7 @@ noinst_HEADERS = \
cmdline/util.h \
cmdline/stream.h \
cmdline/support.h \
cmdline/memory.h \
cmdline/elem.h \
cmdline/state.h \
cmdline/parity.h \
@ -130,6 +132,7 @@ mktest_SOURCES = \
os/unix.c \
cmdline/unixapp.c \
cmdline/support.c \
cmdline/memory.c \
tommyds/tommy.c
mkstream_SOURCES = \
@ -139,6 +142,7 @@ mkstream_SOURCES = \
os/unix.c \
cmdline/unixapp.c \
cmdline/support.c \
cmdline/memory.c \
cmdline/util.c \
cmdline/stream.c \
raid/memory.c \

160
cmdline/memory.c Normal file
View file

@ -0,0 +1,160 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "memory.h"
/****************************************************************************/
/* memory */
/**
* Cumulative amount of memory allocated.
*/
static size_t mcounter;
size_t malloc_counter_get(void)
{
size_t ret;
lock_memory();
ret = mcounter;
unlock_memory();
return ret;
}
static void malloc_counter_inc(size_t inc)
{
lock_memory();
mcounter += inc;
unlock_memory();
}
/* LCOV_EXCL_START */
static ssize_t malloc_print(int f, const char* str)
{
ssize_t len = 0;
while (str[len])
++len;
return write(f, str, len);
}
/* LCOV_EXCL_STOP */
/* LCOV_EXCL_START */
static ssize_t malloc_printn(int f, size_t value)
{
char buf[32];
int i;
if (!value)
return write(f, "0", 1);
i = sizeof(buf);
while (value) {
buf[--i] = (value % 10) + '0';
value /= 10;
}
return write(f, buf + i, sizeof(buf) - i);
}
/* LCOV_EXCL_STOP */
/* LCOV_EXCL_START */
void malloc_fail(size_t size)
{
/* don't use printf to avoid any possible extra allocation */
int f = 2; /* stderr */
malloc_print(f, "Failed for Low Memory!\n");
malloc_print(f, "Allocating ");
malloc_printn(f, size);
malloc_print(f, " bytes.\n");
malloc_print(f, "Already allocated ");
malloc_printn(f, malloc_counter_get());
malloc_print(f, " bytes.\n");
if (sizeof(void*) == 4) {
malloc_print(f, "You are currently using a 32 bits executable.\n");
malloc_print(f, "If you have more than 4GB of memory, please upgrade to a 64 bits one.\n");
}
}
/* LCOV_EXCL_STOP */
void* malloc_nofail(size_t size)
{
void* ptr = malloc(size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
#ifndef CHECKER /* Don't preinitialize when running for valgrind */
/*
* Here we preinitialize the memory to ensure that the OS is really allocating it
* and not only reserving the addressable space.
* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process.
* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to
* get a real error from malloc() instead than a process killed.
* Note that calloc() doesn't have the same effect.
*/
memset(ptr, 0xA5, size);
#endif
malloc_counter_inc(size);
return ptr;
}
void* nalloc_nofail(size_t count, size_t size)
{
if (count > SIZE_MAX / size) {
log_fatal(EINTERNAL, "Allocation size overflow\n");
os_abort();
}
size *= count;
/* see the note in malloc_nofail() of why we don't use calloc() */
void* ptr = malloc(size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
malloc_counter_inc(size);
return ptr;
}
void* calloc_nofail(size_t count, size_t size)
{
void* ptr = nalloc_nofail(count, size);
memset(ptr, 0, count * size);
return ptr;
}
char* strdup_nofail(const char* str)
{
size_t size = strlen(str) + 1;
char* ptr = malloc_nofail(size);
memcpy(ptr, str, size);
return ptr;
}

45
cmdline/memory.h Normal file
View file

@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef __MEMORY_H
#define __MEMORY_H
/****************************************************************************/
/* memory */
/**
* Return the size of the cumulative allocated memory.
*/
size_t malloc_counter_get(void);
/**
* Safe malloc.
* If no memory is available, it aborts.
*/
void* malloc_nofail(size_t size);
/**
* Safe malloc with calloc calling arguments.
* If no memory is available, it aborts.
*/
void* nalloc_nofail(size_t count, size_t size);
/**
* Safe calloc.
* If no memory is available, it aborts.
*/
void* calloc_nofail(size_t count, size_t size);
/**
* Safe strdup.
* If no memory is available, it aborts.
*/
char* strdup_nofail(const char* str);
/**
* Helper for printing an error about a failed allocation.
*/
void malloc_fail(size_t size);
#endif

View file

@ -2103,158 +2103,6 @@ void advise_close(struct advise_struct* advise, int f)
advise->dirty_end = 0;
}
/****************************************************************************/
/* memory */
/**
* Cumulative amount of memory allocated.
*/
static size_t mcounter;
size_t malloc_counter_get(void)
{
size_t ret;
lock_memory();
ret = mcounter;
unlock_memory();
return ret;
}
void malloc_counter_inc(size_t inc)
{
lock_memory();
mcounter += inc;
unlock_memory();
}
/* LCOV_EXCL_START */
static ssize_t malloc_print(int f, const char* str)
{
ssize_t len = 0;
while (str[len])
++len;
return write(f, str, len);
}
/* LCOV_EXCL_STOP */
/* LCOV_EXCL_START */
static ssize_t malloc_printn(int f, size_t value)
{
char buf[32];
int i;
if (!value)
return write(f, "0", 1);
i = sizeof(buf);
while (value) {
buf[--i] = (value % 10) + '0';
value /= 10;
}
return write(f, buf + i, sizeof(buf) - i);
}
/* LCOV_EXCL_STOP */
/* LCOV_EXCL_START */
void malloc_fail(size_t size)
{
/* don't use printf to avoid any possible extra allocation */
int f = 2; /* stderr */
malloc_print(f, "Failed for Low Memory!\n");
malloc_print(f, "Allocating ");
malloc_printn(f, size);
malloc_print(f, " bytes.\n");
malloc_print(f, "Already allocated ");
malloc_printn(f, malloc_counter_get());
malloc_print(f, " bytes.\n");
if (sizeof(void*) == 4) {
malloc_print(f, "You are currently using a 32 bits executable.\n");
malloc_print(f, "If you have more than 4GB of memory, please upgrade to a 64 bits one.\n");
}
}
/* LCOV_EXCL_STOP */
void* malloc_nofail(size_t size)
{
void* ptr = malloc(size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
#ifndef CHECKER /* Don't preinitialize when running for valgrind */
/*
* Here we preinitialize the memory to ensure that the OS is really allocating it
* and not only reserving the addressable space.
* Otherwise we are risking that the OOM (Out Of Memory) killer in Linux will kill the process.
* Filling the memory doesn't ensure to disable OOM, but it increase a lot the chances to
* get a real error from malloc() instead than a process killed.
* Note that calloc() doesn't have the same effect.
*/
memset(ptr, 0xA5, size);
#endif
malloc_counter_inc(size);
return ptr;
}
void* nalloc_nofail(size_t count, size_t size)
{
if (count > SIZE_MAX / size) {
log_fatal(EINTERNAL, "Allocation size overflow\n");
os_abort();
}
size *= count;
/* see the note in malloc_nofail() of why we don't use calloc() */
void* ptr = malloc(size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
malloc_counter_inc(size);
return ptr;
}
void* calloc_nofail(size_t count, size_t size)
{
void* ptr = nalloc_nofail(count, size);
memset(ptr, 0, count * size);
return ptr;
}
char* strdup_nofail(const char* str)
{
size_t size = strlen(str) + 1;
char* ptr = malloc_nofail(size);
memcpy(ptr, str, size);
return ptr;
}
/****************************************************************************/
/* smartctl */

View file

@ -5,6 +5,7 @@
#define __SUPPORT_H
#include "app.h"
#include "memory.h"
/****************************************************************************/
/* lock */
@ -519,43 +520,6 @@ int advise_write(struct advise_struct* advise, int f, data_off_t offset, data_of
int advise_read(struct advise_struct* advise, int f, data_off_t offset, data_off_t size);
void advise_close(struct advise_struct* advise, int f);
/****************************************************************************/
/* memory */
/**
* Return the size of the cumulative allocated memory.
*/
size_t malloc_counter_get(void);
/**
* Safe malloc.
* If no memory is available, it aborts.
*/
void* malloc_nofail(size_t size);
/**
* Safe malloc with calloc calling arguments.
* If no memory is available, it aborts.
*/
void* nalloc_nofail(size_t count, size_t size);
/**
* Safe calloc.
* If no memory is available, it aborts.
*/
void* calloc_nofail(size_t count, size_t size);
/**
* Safe strdup.
* If no memory is available, it aborts.
*/
char* strdup_nofail(const char* str);
/**
* Helper for printing an error about a failed allocation.
*/
void malloc_fail(size_t size);
/****************************************************************************/
/* smartctl */