xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/mymalloc.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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