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