// 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 */ } malloc_counter_inc(size); return ptr; } void* nalloc_nofail(size_t count, size_t size) { if (size != 0 && count > SIZE_MAX / size) { log_fatal(EINTERNAL, "Allocation size overflow\n"); os_abort(); } size *= count; 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) { if (size != 0 && count > SIZE_MAX / size) { log_fatal(EINTERNAL, "Allocation size overflow\n"); os_abort(); } void* ptr = calloc(count ? count : 1, size ? size : 1); if (!ptr) { /* LCOV_EXCL_START */ malloc_fail(count * size); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } malloc_counter_inc(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; }