1 /* $NetBSD: mymalloc.c,v 1.1.1.3 2013/01/02 18:59:13 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* mymalloc 3 6 /* SUMMARY 7 /* memory management wrappers 8 /* SYNOPSIS 9 /* #include <mymalloc.h> 10 /* 11 /* char *mymalloc(len) 12 /* ssize_t len; 13 /* 14 /* char *myrealloc(ptr, len) 15 /* char *ptr; 16 /* ssize_t len; 17 /* 18 /* void myfree(ptr) 19 /* char *ptr; 20 /* 21 /* char *mystrdup(str) 22 /* const char *str; 23 /* 24 /* char *mystrndup(str, len) 25 /* const char *str; 26 /* ssize_t len; 27 /* 28 /* char *mymemdup(ptr, len) 29 /* const char *ptr; 30 /* ssize_t len; 31 /* DESCRIPTION 32 /* This module performs low-level memory management with error 33 /* handling. A call of these functions either succeeds or it does 34 /* not return at all. 35 /* 36 /* To save memory, zero-length strings are shared and read-only. 37 /* The caller must not attempt to modify the null terminator. 38 /* This code is enabled unless NO_SHARED_EMPTY_STRINGS is 39 /* defined at compile time (for example, you have an sscanf() 40 /* routine that pushes characters back into its input). 41 /* 42 /* mymalloc() allocates the requested amount of memory. The memory 43 /* is not set to zero. 44 /* 45 /* myrealloc() resizes memory obtained from mymalloc() or myrealloc() 46 /* to the requested size. The result pointer value may differ from 47 /* that given via the \fIptr\fR argument. 48 /* 49 /* myfree() takes memory obtained from mymalloc() or myrealloc() 50 /* and makes it available for other use. 51 /* 52 /* mystrdup() returns a dynamic-memory copy of its null-terminated 53 /* argument. This routine uses mymalloc(). 54 /* 55 /* mystrndup() returns a dynamic-memory copy of at most \fIlen\fR 56 /* leading characters of its null-terminated 57 /* argument. The result is null-terminated. This routine uses mymalloc(). 58 /* 59 /* mymemdup() makes a copy of the memory pointed to by \fIptr\fR 60 /* with length \fIlen\fR. The result is NOT null-terminated. 61 /* This routine uses mymalloc(). 62 /* SEE ALSO 63 /* msg(3) diagnostics interface 64 /* DIAGNOSTICS 65 /* Problems are reported via the msg(3) diagnostics routines: 66 /* the requested amount of memory is not available; improper use 67 /* is detected; other fatal errors. 68 /* LICENSE 69 /* .ad 70 /* .fi 71 /* The Secure Mailer license must be distributed with this software. 72 /* AUTHOR(S) 73 /* Wietse Venema 74 /* IBM T.J. Watson Research 75 /* P.O. Box 704 76 /* Yorktown Heights, NY 10598, USA 77 /*--*/ 78 79 /* System libraries. */ 80 81 #include "sys_defs.h" 82 #include <stdlib.h> 83 #include <stddef.h> 84 #include <string.h> 85 86 /* Application-specific. */ 87 88 #include "msg.h" 89 #include "mymalloc.h" 90 91 /* 92 * Structure of an annotated memory block. In order to detect spurious 93 * free() calls we prepend a signature to memory given to the application. 94 * In order to detect access to free()d blocks, overwrite each block as soon 95 * as it is passed to myfree(). With the code below, the user data has 96 * integer alignment or better. 97 */ 98 typedef struct MBLOCK { 99 int signature; /* set when block is active */ 100 ssize_t length; /* user requested length */ 101 union { 102 ALIGN_TYPE align; 103 char payload[1]; /* actually a bunch of bytes */ 104 } u; 105 } MBLOCK; 106 107 #define SIGNATURE 0xdead 108 #define FILLER 0xff 109 110 #define CHECK_IN_PTR(ptr, real_ptr, len, fname) { \ 111 if (ptr == 0) \ 112 msg_panic("%s: null pointer input", fname); \ 113 real_ptr = (MBLOCK *) (ptr - offsetof(MBLOCK, u.payload[0])); \ 114 if (real_ptr->signature != SIGNATURE) \ 115 msg_panic("%s: corrupt or unallocated memory block", fname); \ 116 real_ptr->signature = 0; \ 117 if ((len = real_ptr->length) < 1) \ 118 msg_panic("%s: corrupt memory block length", fname); \ 119 } 120 121 #define CHECK_OUT_PTR(ptr, real_ptr, len) { \ 122 real_ptr->signature = SIGNATURE; \ 123 real_ptr->length = len; \ 124 ptr = real_ptr->u.payload; \ 125 } 126 127 #define SPACE_FOR(len) (offsetof(MBLOCK, u.payload[0]) + len) 128 129 /* 130 * Optimization for short strings. We share one copy with multiple callers. 131 * This differs from normal heap memory in two ways, because the memory is 132 * shared: 133 * 134 * - It must be read-only to avoid horrible bugs. This is OK because there is 135 * no legitimate reason to modify the null terminator. 136 * 137 * - myfree() cannot overwrite the memory with a filler pattern like it can do 138 * with heap memory. Therefore, some dangling pointer bugs will be masked. 139 */ 140 #ifndef NO_SHARED_EMPTY_STRINGS 141 static const char empty_string[] = ""; 142 143 #endif 144 145 /* mymalloc - allocate memory or bust */ 146 147 char *mymalloc(ssize_t len) 148 { 149 char *ptr; 150 MBLOCK *real_ptr; 151 152 /* 153 * Note: for safety reasons the request length is a signed type. This 154 * allows us to catch integer overflow problems that weren't already 155 * caught up-stream. 156 */ 157 if (len < 1) 158 msg_panic("mymalloc: requested length %ld", (long) len); 159 #ifdef MYMALLOC_FUZZ 160 len += MYMALLOC_FUZZ; 161 #endif 162 if ((real_ptr = (MBLOCK *) malloc(SPACE_FOR(len))) == 0) 163 msg_fatal("mymalloc: insufficient memory for %ld bytes: %m", 164 (long) len); 165 CHECK_OUT_PTR(ptr, real_ptr, len); 166 memset(ptr, FILLER, len); 167 return (ptr); 168 } 169 170 /* myrealloc - reallocate memory or bust */ 171 172 char *myrealloc(char *ptr, ssize_t len) 173 { 174 MBLOCK *real_ptr; 175 ssize_t old_len; 176 177 #ifndef NO_SHARED_EMPTY_STRINGS 178 if (ptr == empty_string) 179 return (mymalloc(len)); 180 #endif 181 182 /* 183 * Note: for safety reasons the request length is a signed type. This 184 * allows us to catch integer overflow problems that weren't already 185 * caught up-stream. 186 */ 187 if (len < 1) 188 msg_panic("myrealloc: requested length %ld", (long) len); 189 #ifdef MYMALLOC_FUZZ 190 len += MYMALLOC_FUZZ; 191 #endif 192 CHECK_IN_PTR(ptr, real_ptr, old_len, "myrealloc"); 193 if ((real_ptr = (MBLOCK *) realloc((char *) real_ptr, SPACE_FOR(len))) == 0) 194 msg_fatal("myrealloc: insufficient memory for %ld bytes: %m", 195 (long) len); 196 CHECK_OUT_PTR(ptr, real_ptr, len); 197 if (len > old_len) 198 memset(ptr + old_len, FILLER, len - old_len); 199 return (ptr); 200 } 201 202 /* myfree - release memory */ 203 204 void myfree(char *ptr) 205 { 206 MBLOCK *real_ptr; 207 ssize_t len; 208 209 #ifndef NO_SHARED_EMPTY_STRINGS 210 if (ptr != empty_string) { 211 #endif 212 CHECK_IN_PTR(ptr, real_ptr, len, "myfree"); 213 memset((char *) real_ptr, FILLER, SPACE_FOR(len)); 214 free((char *) real_ptr); 215 #ifndef NO_SHARED_EMPTY_STRINGS 216 } 217 #endif 218 } 219 220 /* mystrdup - save string to heap */ 221 222 char *mystrdup(const char *str) 223 { 224 if (str == 0) 225 msg_panic("mystrdup: null pointer argument"); 226 #ifndef NO_SHARED_EMPTY_STRINGS 227 if (*str == 0) 228 return ((char *) empty_string); 229 #endif 230 return (strcpy(mymalloc(strlen(str) + 1), str)); 231 } 232 233 /* mystrndup - save substring to heap */ 234 235 char *mystrndup(const char *str, ssize_t len) 236 { 237 char *result; 238 char *cp; 239 240 if (str == 0) 241 msg_panic("mystrndup: null pointer argument"); 242 if (len < 0) 243 msg_panic("mystrndup: requested length %ld", (long) len); 244 #ifndef NO_SHARED_EMPTY_STRINGS 245 if (*str == 0) 246 return ((char *) empty_string); 247 #endif 248 if ((cp = memchr(str, 0, len)) != 0) 249 len = cp - str; 250 result = memcpy(mymalloc(len + 1), str, len); 251 result[len] = 0; 252 return (result); 253 } 254 255 /* mymemdup - copy memory */ 256 257 char *mymemdup(const char *ptr, ssize_t len) 258 { 259 if (ptr == 0) 260 msg_panic("mymemdup: null pointer argument"); 261 return (memcpy(mymalloc(len), ptr, len)); 262 } 263