/*++ /* NAME /* mymalloc 3 /* SUMMARY /* memory management wrappers /* SYNOPSIS /* #include /* /* void *mymalloc(len) /* ssize_t len; /* /* void *myrealloc(ptr, len) /* void *ptr; /* ssize_t len; /* /* void myfree(ptr) /* void *ptr; /* /* char *mystrdup(str) /* const char *str; /* /* char *mystrndup(str, len) /* const char *str; /* ssize_t len; /* /* void *mymemdup(ptr, len) /* const void *ptr; /* ssize_t len; /* DESCRIPTION /* This module performs low-level memory management with error /* handling. A call of these functions either succeeds or it does /* not return at all. /* /* To save memory, zero-length strings are shared and read-only. /* The caller must not attempt to modify the null terminator. /* This code is enabled unless NO_SHARED_EMPTY_STRINGS is /* defined at compile time (for example, you have an sscanf() /* routine that pushes characters back into its input). /* /* mymalloc() allocates the requested amount of memory. The memory /* is not set to zero. /* /* myrealloc() resizes memory obtained from mymalloc() or myrealloc() /* to the requested size. The result pointer value may differ from /* that given via the \fIptr\fR argument. /* /* myfree() takes memory obtained from mymalloc() or myrealloc() /* and makes it available for other use. /* /* mystrdup() returns a dynamic-memory copy of its null-terminated /* argument. This routine uses mymalloc(). /* /* mystrndup() returns a dynamic-memory copy of at most \fIlen\fR /* leading characters of its null-terminated /* argument. The result is null-terminated. This routine uses mymalloc(). /* /* mymemdup() makes a copy of the memory pointed to by \fIptr\fR /* with length \fIlen\fR. The result is NOT null-terminated. /* This routine uses mymalloc(). /* SEE ALSO /* msg(3) diagnostics interface /* DIAGNOSTICS /* Problems are reported via the msg(3) diagnostics routines: /* the requested amount of memory is not available; improper use /* is detected; other fatal errors. /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* /* Wietse Venema /* Google, Inc. /* 111 8th Avenue /* New York, NY 10011, USA /*--*/ /* System libraries. */ #include "sys_defs.h" #include #include #include /* Application-specific. */ #include "msg.h" #include "mymalloc.h" /* * Structure of an annotated memory block. In order to detect spurious * free() calls we prepend a signature to memory given to the application. * In order to detect access to free()d blocks, overwrite each block as soon * as it is passed to myfree(). With the code below, the user data has * integer alignment or better. */ typedef struct MBLOCK { int signature; /* set when block is active */ ssize_t length; /* user requested length */ union { ALIGN_TYPE align; char payload[1]; /* actually a bunch of bytes */ } u; } MBLOCK; #define SIGNATURE 0xdead #define FILLER 0xff #define CHECK_IN_PTR(ptr, real_ptr, len, fname) { \ if (ptr == 0) \ msg_panic("%s: null pointer input", fname); \ real_ptr = (MBLOCK *) (ptr - offsetof(MBLOCK, u.payload[0])); \ if (real_ptr->signature != SIGNATURE) \ msg_panic("%s: corrupt or unallocated memory block", fname); \ real_ptr->signature = 0; \ if ((len = real_ptr->length) < 1) \ msg_panic("%s: corrupt memory block length", fname); \ } #define CHECK_OUT_PTR(ptr, real_ptr, len) { \ real_ptr->signature = SIGNATURE; \ real_ptr->length = len; \ ptr = real_ptr->u.payload; \ } #define SPACE_FOR(len) (offsetof(MBLOCK, u.payload[0]) + len) /* * Optimization for short strings. We share one copy with multiple callers. * This differs from normal heap memory in two ways, because the memory is * shared: * * - It must be read-only to avoid horrible bugs. This is OK because there is * no legitimate reason to modify the null terminator. * * - myfree() cannot overwrite the memory with a filler pattern like it can do * with heap memory. Therefore, some dangling pointer bugs will be masked. */ #ifndef NO_SHARED_EMPTY_STRINGS static const char empty_string[] = ""; #endif /* mymalloc - allocate memory or bust */ void *mymalloc(ssize_t len) { void *ptr; MBLOCK *real_ptr; /* * Note: for safety reasons the request length is a signed type. This * allows us to catch integer overflow problems that weren't already * caught up-stream. */ if (len < 1) msg_panic("mymalloc: requested length %ld", (long) len); #ifdef MYMALLOC_FUZZ len += MYMALLOC_FUZZ; #endif if ((real_ptr = (MBLOCK *) malloc(SPACE_FOR(len))) == 0) msg_fatal("mymalloc: insufficient memory for %ld bytes: %m", (long) len); CHECK_OUT_PTR(ptr, real_ptr, len); memset(ptr, FILLER, len); return (ptr); } /* myrealloc - reallocate memory or bust */ void *myrealloc(void *ptr, ssize_t len) { MBLOCK *real_ptr; ssize_t old_len; #ifndef NO_SHARED_EMPTY_STRINGS if (ptr == empty_string) return (mymalloc(len)); #endif /* * Note: for safety reasons the request length is a signed type. This * allows us to catch integer overflow problems that weren't already * caught up-stream. */ if (len < 1) msg_panic("myrealloc: requested length %ld", (long) len); #ifdef MYMALLOC_FUZZ len += MYMALLOC_FUZZ; #endif CHECK_IN_PTR(ptr, real_ptr, old_len, "myrealloc"); if ((real_ptr = (MBLOCK *) realloc((void *) real_ptr, SPACE_FOR(len))) == 0) msg_fatal("myrealloc: insufficient memory for %ld bytes: %m", (long) len); CHECK_OUT_PTR(ptr, real_ptr, len); if (len > old_len) memset(ptr + old_len, FILLER, len - old_len); return (ptr); } /* myfree - release memory */ void myfree(void *ptr) { MBLOCK *real_ptr; ssize_t len; #ifndef NO_SHARED_EMPTY_STRINGS if (ptr != empty_string) { #endif CHECK_IN_PTR(ptr, real_ptr, len, "myfree"); memset((void *) real_ptr, FILLER, SPACE_FOR(len)); free((void *) real_ptr); #ifndef NO_SHARED_EMPTY_STRINGS } #endif } /* mystrdup - save string to heap */ char *mystrdup(const char *str) { size_t len; if (str == 0) msg_panic("mystrdup: null pointer argument"); #ifndef NO_SHARED_EMPTY_STRINGS if (*str == 0) return ((char *) empty_string); #endif if ((len = strlen(str) + 1) > SSIZE_T_MAX) msg_panic("mystrdup: string length >= SSIZE_T_MAX"); return (memcpy(mymalloc(len), str, len)); } /* mystrndup - save substring to heap */ char *mystrndup(const char *str, ssize_t len) { char *result; char *cp; if (str == 0) msg_panic("mystrndup: null pointer argument"); if (len < 0) msg_panic("mystrndup: requested length %ld", (long) len); #ifndef NO_SHARED_EMPTY_STRINGS if (*str == 0) return ((char *) empty_string); #endif if ((cp = memchr(str, 0, len)) != 0) len = cp - str; result = memcpy(mymalloc(len + 1), str, len); result[len] = 0; return (result); } /* mymemdup - copy memory */ void *mymemdup(const void *ptr, ssize_t len) { if (ptr == 0) msg_panic("mymemdup: null pointer argument"); return (memcpy(mymalloc(len), ptr, len)); }