memory.c (4768B)
1 /* 2 * Copyright (c) 2021-2024 lumidify <nobody@lumidify.org> 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <stdarg.h> 20 #include <string.h> 21 #include <stdint.h> 22 #include "util.h" 23 #include "memory.h" 24 25 char * 26 ltk_strdup_impl(const char *s) { 27 char *str = strdup(s); 28 if (!str) 29 ltk_fatal("Out of memory.\n"); 30 return str; 31 } 32 33 char * 34 ltk_strndup_impl(const char *s, size_t n) { 35 char *str = strndup(s, n); 36 if (!str) 37 ltk_fatal("Out of memory.\n"); 38 return str; 39 } 40 41 void * 42 ltk_malloc_impl(size_t size) { 43 void *ptr = malloc(size); 44 if (!ptr) 45 ltk_fatal("Out of memory.\n"); 46 return ptr; 47 } 48 49 void * 50 ltk_calloc_impl(size_t nmemb, size_t size) { 51 void *ptr = calloc(nmemb, size); 52 if (!ptr) 53 ltk_fatal("Out of memory.\n"); 54 return ptr; 55 } 56 57 void * 58 ltk_realloc_impl(void *ptr, size_t size) { 59 void *new_ptr = realloc(ptr, size); 60 if (!new_ptr) 61 ltk_fatal("Out of memory.\n"); 62 return new_ptr; 63 } 64 65 #if MEMDEBUG == 1 66 67 char * 68 ltk_strdup_debug(const char *s, const char *caller, const char *file, int line) { 69 char *str = strdup(s); 70 fprintf(stderr, "DEBUG: strdup %p to %p in %s (%s:%d)\n", 71 (void *)s, (void *)str, caller, file, line); 72 if (!str) 73 ltk_fatal("Out of memory.\n"); 74 return str; 75 } 76 77 char * 78 ltk_strndup_debug(const char *s, size_t n, const char *caller, const char *file, int line) { 79 char *str = strndup(s, n); 80 fprintf(stderr, "DEBUG: strndup %p to %p in %s (%s:%d)\n", 81 (void *)s, (void *)str, caller, file, line); 82 if (!str) 83 ltk_fatal("Out of memory.\n"); 84 return str; 85 } 86 87 void * 88 ltk_malloc_debug(size_t size, const char *caller, const char *file, int line) { 89 void *ptr = malloc(size); 90 fprintf(stderr, "DEBUG: malloc %p, %zu bytes in %s (%s:%d)\n", 91 ptr, size, caller, file, line); 92 if (!ptr) 93 ltk_fatal("Out of memory.\n"); 94 return ptr; 95 } 96 97 void * 98 ltk_calloc_debug(size_t nmemb, size_t size, const char *caller, const char *file, int line) { 99 void *ptr = calloc(nmemb, size); 100 fprintf(stderr, "DEBUG: calloc %p, %zu bytes in %s (%s:%d)\n", 101 ptr, size, caller, file, line); 102 if (!ptr) 103 ltk_fatal("Out of memory.\n"); 104 return ptr; 105 } 106 107 void * 108 ltk_realloc_debug(void *ptr, size_t size, const char *caller, const char *file, int line) { 109 void *new_ptr = realloc(ptr, size); 110 fprintf(stderr, "DEBUG: realloc %p to %p, %zu bytes in %s (%s:%d)\n", 111 ptr, new_ptr, size, caller, file, line); 112 if (!new_ptr) 113 ltk_fatal("Out of memory.\n"); 114 return new_ptr; 115 } 116 117 void 118 ltk_free_debug(void *ptr, const char *caller, const char *file, int line) { 119 fprintf(stderr, "DEBUG: free %p in %s (%s:%d)\n", ptr, caller, file, line); 120 free(ptr); 121 } 122 123 #endif 124 125 /* 126 * This (reallocarray) is from OpenBSD (adapted to exit on error): 127 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 128 */ 129 130 /* 131 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 132 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 133 */ 134 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 135 136 void * 137 ltk_reallocarray(void *optr, size_t nmemb, size_t size) 138 { 139 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 140 nmemb > 0 && SIZE_MAX / nmemb < size) { 141 ltk_fatal("Integer overflow in allocation.\n"); 142 } 143 return ltk_realloc(optr, size * nmemb); 144 } 145 146 /* FIXME: maybe don't double when already very large? */ 147 /* FIXME: better start size when old == 0? */ 148 size_t 149 ideal_array_size(size_t old, size_t needed) { 150 size_t ret = old; 151 /* FIXME: the shrinking here only makes sense if not 152 many elements are removed at once - what would be 153 more sensible here? */ 154 /* FIXME: overflow */ 155 if (old < needed) 156 ret = old * 2 > needed ? old * 2 : needed; 157 else if (needed * 4 < old) 158 ret = old / 2; 159 if (ret == 0) 160 ret = 1; /* not sure if this is necessary */ 161 return ret; 162 } 163 164 char * 165 ltk_print_fmt(char *fmt, ...) { 166 va_list args; 167 va_start(args, fmt); 168 int len = vsnprintf(NULL, 0, fmt, args); 169 /* FIXME: what should be done on error? */ 170 if (len < 0) 171 ltk_fatal("Error in vsnprintf called from print_fmt"); 172 /* FIXME: overflow */ 173 char *str = ltk_malloc(len + 1); 174 va_end(args); 175 va_start(args, fmt); 176 vsnprintf(str, len + 1, fmt, args); 177 va_end(args); 178 return str; 179 }