memory.c (4742B)
1 /* 2 * Copyright (c) 2021, 2022 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_strdup_debug(const char *s, const char *caller, const char *file, int line) { 35 char *str = strdup(s); 36 fprintf(stderr, "DEBUG: strdup %p to %p in %s (%s:%d)\n", 37 (void *)s, (void *)str, caller, file, line); 38 if (!str) 39 ltk_fatal("Out of memory.\n"); 40 return str; 41 } 42 43 char * 44 ltk_strndup_impl(const char *s, size_t n) { 45 char *str = strndup(s, n); 46 if (!str) 47 ltk_fatal("Out of memory.\n"); 48 return str; 49 } 50 51 char * 52 ltk_strndup_debug(const char *s, size_t n, const char *caller, const char *file, int line) { 53 char *str = strndup(s, n); 54 fprintf(stderr, "DEBUG: strndup %p to %p in %s (%s:%d)\n", 55 (void *)s, (void *)str, caller, file, line); 56 if (!str) 57 ltk_fatal("Out of memory.\n"); 58 return str; 59 } 60 61 void * 62 ltk_malloc_impl(size_t size) { 63 void *ptr = malloc(size); 64 if (!ptr) 65 ltk_fatal("Out of memory.\n"); 66 return ptr; 67 } 68 69 void * 70 ltk_malloc_debug(size_t size, const char *caller, const char *file, int line) { 71 void *ptr = malloc(size); 72 fprintf(stderr, "DEBUG: malloc %p, %zu bytes in %s (%s:%d)\n", 73 ptr, size, caller, file, line); 74 if (!ptr) 75 ltk_fatal("Out of memory.\n"); 76 return ptr; 77 } 78 79 void * 80 ltk_calloc_impl(size_t nmemb, size_t size) { 81 void *ptr = calloc(nmemb, size); 82 if (!ptr) 83 ltk_fatal("Out of memory.\n"); 84 return ptr; 85 } 86 87 void * 88 ltk_calloc_debug(size_t nmemb, size_t size, const char *caller, const char *file, int line) { 89 void *ptr = calloc(nmemb, size); 90 fprintf(stderr, "DEBUG: calloc %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_realloc_impl(void *ptr, size_t size) { 99 void *new_ptr = realloc(ptr, size); 100 if (!new_ptr) 101 ltk_fatal("Out of memory.\n"); 102 return new_ptr; 103 } 104 105 void * 106 ltk_realloc_debug(void *ptr, size_t size, const char *caller, const char *file, int line) { 107 void *new_ptr = realloc(ptr, size); 108 fprintf(stderr, "DEBUG: realloc %p to %p, %zu bytes in %s (%s:%d)\n", 109 ptr, new_ptr, size, caller, file, line); 110 if (!new_ptr) 111 ltk_fatal("Out of memory.\n"); 112 return new_ptr; 113 } 114 115 void 116 ltk_free_debug(void *ptr, const char *caller, const char *file, int line) { 117 fprintf(stderr, "DEBUG: free %p in %s (%s:%d)\n", ptr, caller, file, line); 118 free(ptr); 119 } 120 121 /* 122 * This (reallocarray) is from OpenBSD (adapted to exit on error): 123 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 124 */ 125 126 /* 127 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX 128 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW 129 */ 130 #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) 131 132 void * 133 ltk_reallocarray(void *optr, size_t nmemb, size_t size) 134 { 135 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 136 nmemb > 0 && SIZE_MAX / nmemb < size) { 137 ltk_fatal("Integer overflow in allocation.\n"); 138 } 139 return ltk_realloc(optr, size * nmemb); 140 } 141 142 /* FIXME: maybe don't double when already very large? */ 143 /* FIXME: better start size when old == 0? */ 144 size_t 145 ideal_array_size(size_t old, size_t needed) { 146 size_t ret = old; 147 /* FIXME: the shrinking here only makes sense if not 148 many elements are removed at once - what would be 149 more sensible here? */ 150 /* FIXME: overflow */ 151 if (old < needed) 152 ret = old * 2 > needed ? old * 2 : needed; 153 else if (needed * 4 < old) 154 ret = old / 2; 155 if (ret == 0) 156 ret = 1; /* not sure if this is necessary */ 157 return ret; 158 } 159 160 char * 161 ltk_print_fmt(char *fmt, ...) { 162 va_list args; 163 va_start(args, fmt); 164 int len = vsnprintf(NULL, 0, fmt, args); 165 /* FIXME: what should be done on error? */ 166 if (len < 0) 167 ltk_fatal("Error in vsnprintf called from print_fmt"); 168 /* FIXME: overflow */ 169 char *str = ltk_malloc(len + 1); 170 va_end(args); 171 va_start(args, fmt); 172 vsnprintf(str, len + 1, fmt, args); 173 va_end(args); 174 return str; 175 }