fix bad free
[oweals/gnunet.git] / src / util / common_allocation.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001, 2002, 2003, 2005, 2006 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file util/common_allocation.c
21  * @brief wrapper around malloc/free
22  * @author Christian Grothoff
23  */
24 #include "platform.h"
25 #include "gnunet_crypto_lib.h"
26 #if HAVE_MALLOC_H
27 #include <malloc.h>
28 #endif
29 #if HAVE_MALLOC_MALLOC_H
30 #include <malloc/malloc.h>
31 #endif
32
33 #define LOG(kind,...) GNUNET_log_from (kind, "util-common-allocation",__VA_ARGS__)
34
35 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-common-allocation", syscall)
36
37 #ifndef INT_MAX
38 #define INT_MAX 0x7FFFFFFF
39 #endif
40
41 #if 0
42 #define W32_MEM_LIMIT 200000000
43 #endif
44
45 #ifdef W32_MEM_LIMIT
46 static LONG mem_used = 0;
47 #endif
48
49 /**
50  * Allocate memory. Checks the return value, aborts if no more
51  * memory is available.
52  *
53  * @param size how many bytes of memory to allocate, do NOT use
54  *  this function (or GNUNET_malloc()) to allocate more than several MB
55  *  of memory, if you are possibly needing a very large chunk use
56  *  #GNUNET_xmalloc_unchecked_() instead.
57  * @param filename where in the code was the call to GNUNET_malloc()
58  * @param linenumber where in the code was the call to GNUNET_malloc()
59  * @return pointer to size bytes of memory
60  */
61 void *
62 GNUNET_xmalloc_ (size_t size,
63                  const char *filename,
64                  int linenumber)
65 {
66   void *ret;
67
68   /* As a security precaution, we generally do not allow very large
69    * allocations using the default 'GNUNET_malloc()' macro */
70   GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED,
71                     filename,
72                     linenumber);
73   ret = GNUNET_xmalloc_unchecked_ (size,
74                                    filename,
75                                    linenumber);
76   if (NULL == ret)
77   {
78     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
79                   "malloc");
80     GNUNET_assert (0);
81   }
82   return ret;
83 }
84
85
86 /**
87  * Allocate memory for a two dimensional array in one block
88  * and set up pointers. Aborts if no more memory is available.
89  * Don't use GNUNET_xnew_array_2d_ directly. Use the
90  * #GNUNET_new_array_2d macro.
91  * The memory of the elements will be zero'ed out.
92  *
93  * @param n size of the first dimension
94  * @param m size of the second dimension
95  * @param elementSize size of a single element in bytes
96  * @param filename where is this call being made (for debugging)
97  * @param linenumber line where this call is being made (for debugging)
98  * @return allocated memory, never NULL
99  */
100 void **
101 GNUNET_xnew_array_2d_ (size_t n,
102                        size_t m,
103                        size_t elementSize,
104                        const char *filename,
105                        int linenumber)
106 {
107         /* use char pointer internally to avoid void pointer arithmetic warnings */
108         char **ret = GNUNET_xmalloc_ (n * sizeof (void *) +  /* 1. dim header */
109                                       n * m * elementSize,   /* element data */
110                                       filename, linenumber);
111
112         for (size_t i = 0; i < n; i++)
113                 ret[i] = (char *)ret +          /* base address */
114                          n * sizeof (void *) +  /* skip 1. dim header */
115                          i * m * elementSize;   /* skip to 2. dim row header */
116         return (void **)ret;
117 }
118
119
120 /**
121  * Allocate memory for a three dimensional array in one block
122  * and set up pointers. Aborts if no more memory is available.
123  * Don't use GNUNET_xnew_array_3d_ directly. Use the
124  * #GNUNET_new_array_3d macro.
125  * The memory of the elements will be zero'ed out.
126  *
127  * @param n size of the first dimension
128  * @param m size of the second dimension
129  * @param o size of the third dimension
130  * @param elementSize size of a single element in bytes
131  * @param filename where is this call being made (for debugging)
132  * @param linenumber line where this call is being made (for debugging)
133  * @return allocated memory, never NULL
134  */
135 void ***
136 GNUNET_xnew_array_3d_ (size_t n, size_t m, size_t o, size_t elementSize,
137                        const char *filename, int linenumber)
138 {
139         /* use char pointer internally to avoid void pointer arithmetic warnings */
140         char ***ret = GNUNET_xmalloc_ (n * sizeof (void **) +    /* 1. dim header */
141                                        n * m * sizeof (void *) + /* 2. dim header */
142                                        n * m * o * elementSize,  /* element data */
143                                        filename, linenumber);
144
145         for (size_t i = 0; i < n; i++)
146         {
147                 /* need to cast to (char *) temporarily for byte level acuracy */
148                 ret[i] = (char **)((char *)ret +             /* base address */
149                                    n * sizeof (void **) +    /* skip 1. dim header */
150                                    i * m * sizeof (void *)); /* skip to 2. dim header */
151                 for (size_t j = 0; j < m; j++)
152                         ret[i][j] = (char *)ret +              /* base address */
153                                     n * sizeof (void **) +     /* skip 1. dim header */
154                                     n * m * sizeof (void *) +  /* skip 2. dim header */
155                                     i * m * o * elementSize +  /* skip to 2. dim part */
156                                         j * o * elementSize;   /* skip to 3. dim row data */
157         }
158         return (void ***)ret;
159 }
160
161
162 /**
163  * Allocate and initialize memory. Checks the return value, aborts if no more
164  * memory is available.  Don't use #GNUNET_xmemdup_() directly. Use the
165  * GNUNET_memdup() macro.
166  *
167  * @param buf buffer to initialize from (must contain size bytes)
168  * @param size number of bytes to allocate
169  * @param filename where is this call being made (for debugging)
170  * @param linenumber line where this call is being made (for debugging)
171  * @return allocated memory, never NULL
172  */
173 void *
174 GNUNET_xmemdup_ (const void *buf,
175                  size_t size,
176                  const char *filename,
177                  int linenumber)
178 {
179   void *ret;
180
181   /* As a security precaution, we generally do not allow very large
182    * allocations here */
183   GNUNET_assert_at (size <= GNUNET_MAX_MALLOC_CHECKED, filename, linenumber);
184 #ifdef W32_MEM_LIMIT
185   size += sizeof (size_t);
186   if (mem_used + size > W32_MEM_LIMIT)
187     return NULL;
188 #endif
189   GNUNET_assert_at (size < INT_MAX, filename, linenumber);
190   ret = malloc (size);
191   if (ret == NULL)
192   {
193     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "malloc");
194     GNUNET_assert (0);
195   }
196 #ifdef W32_MEM_LIMIT
197   *((size_t *) ret) = size;
198   ret = &((size_t *) ret)[1];
199   mem_used += size;
200 #endif
201   GNUNET_memcpy (ret, buf, size);
202   return ret;
203 }
204
205
206 /**
207  * Wrapper around malloc(). Allocates size bytes of memory.
208  * The memory will be zero'ed out.
209  *
210  * @param size the number of bytes to allocate
211  * @param filename where in the code was the call to GNUNET_malloc_unchecked()
212  * @param linenumber where in the code was the call to GNUNET_malloc_unchecked()
213  * @return pointer to size bytes of memory, NULL if we do not have enough memory
214  */
215 void *
216 GNUNET_xmalloc_unchecked_ (size_t size,
217                            const char *filename,
218                            int linenumber)
219 {
220   void *result;
221
222   (void) filename;
223   (void) linenumber;
224 #ifdef W32_MEM_LIMIT
225   size += sizeof (size_t);
226   if (mem_used + size > W32_MEM_LIMIT)
227     return NULL;
228 #endif
229
230   result = malloc (size);
231   if (NULL == result)
232     return NULL;
233   memset (result, 0, size);
234
235 #ifdef W32_MEM_LIMIT
236   *((size_t *) result) = size;
237   result = &((size_t *) result)[1];
238   mem_used += size;
239 #endif
240
241   return result;
242 }
243
244
245 /**
246  * Reallocate memory. Checks the return value, aborts if no more
247  * memory is available.
248  * The content of the intersection of the new and old size will be unchanged.
249  *
250  * @param ptr the pointer to reallocate
251  * @param n how many bytes of memory to allocate
252  * @param filename where in the code was the call to GNUNET_realloc()
253  * @param linenumber where in the code was the call to GNUNET_realloc()
254  * @return pointer to size bytes of memory
255  */
256 void *
257 GNUNET_xrealloc_ (void *ptr,
258                   size_t n,
259                   const char *filename,
260                   int linenumber)
261 {
262   (void) filename;
263   (void) linenumber;
264
265 #ifdef W32_MEM_LIMIT
266   n += sizeof (size_t);
267   ptr = &((size_t *) ptr)[-1];
268   mem_used = mem_used - *((size_t *) ptr) + n;
269 #endif
270   ptr = realloc (ptr, n);
271   if ((NULL == ptr) && (n > 0))
272   {
273     LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
274                   "realloc");
275     GNUNET_assert (0);
276   }
277 #ifdef W32_MEM_LIMIT
278   ptr = &((size_t *) ptr)[1];
279 #endif
280   return ptr;
281 }
282
283
284 # if __BYTE_ORDER == __LITTLE_ENDIAN
285 #define BAADFOOD_STR "\x0D\xF0\xAD\xBA"
286 #endif
287 # if __BYTE_ORDER == __BIG_ENDIAN
288 #define BAADFOOD_STR "\xBA\xAD\xF0\x0D"
289 #endif
290
291 #if WINDOWS
292 #define M_SIZE(p) _msize (p)
293 #endif
294 #if HAVE_MALLOC_NP_H
295 #include <malloc_np.h>
296 #endif
297 #if HAVE_MALLOC_USABLE_SIZE
298 #define M_SIZE(p) malloc_usable_size (p)
299 #elif HAVE_MALLOC_SIZE
300 #define M_SIZE(p) malloc_size (p)
301 #endif
302
303 /**
304  * Free memory. Merely a wrapper for the case that we
305  * want to keep track of allocations.
306  *
307  * @param ptr the pointer to free
308  * @param filename where in the code was the call to GNUNET_free
309  * @param linenumber where in the code was the call to GNUNET_free
310  */
311 void
312 GNUNET_xfree_ (void *ptr,
313                const char *filename,
314                int linenumber)
315 {
316   GNUNET_assert_at (NULL != ptr,
317                     filename,
318                     linenumber);
319 #ifdef W32_MEM_LIMIT
320   ptr = &((size_t *) ptr)[-1];
321   mem_used -= *((size_t *) ptr);
322 #endif
323 #if defined(M_SIZE)
324 #if ENABLE_POISONING
325   {
326     const uint64_t baadfood = GNUNET_ntohll (0xBAADF00DBAADF00DLL);
327     uint64_t *base = ptr;
328     size_t s = M_SIZE (ptr);
329     size_t i;
330
331     for (i=0;i<s/8;i++)
332       base[i] = baadfood;
333     GNUNET_memcpy (&base[s/8], &baadfood, s % 8);
334   }
335 #endif
336 #endif
337   free (ptr);
338 }
339
340
341 /**
342  * Dup a string (same semantics as strdup).
343  *
344  * @param str the string to dup
345  * @param filename where in the code was the call to GNUNET_strdup()
346  * @param linenumber where in the code was the call to GNUNET_strdup()
347  * @return `strdup(@a str)`
348  */
349 char *
350 GNUNET_xstrdup_ (const char *str,
351                  const char *filename,
352                  int linenumber)
353 {
354   char *res;
355   size_t slen;
356
357   GNUNET_assert_at (str != NULL,
358                     filename,
359                     linenumber);
360   slen = strlen (str) + 1;
361   res = GNUNET_xmalloc_ (slen,
362                          filename,
363                          linenumber);
364   GNUNET_memcpy (res,
365           str,
366           slen);
367   return res;
368 }
369
370
371 #if ! HAVE_STRNLEN
372 static size_t
373 strnlen (const char *s,
374          size_t n)
375 {
376   const char *e;
377
378   e = memchr (s, '\0', n);
379   if (NULL == e)
380     return n;
381   return e - s;
382 }
383 #endif
384
385
386 /**
387  * Dup partially a string (same semantics as strndup).
388  *
389  * @param str the string to dup
390  * @param len the length of the string to dup
391  * @param filename where in the code was the call to GNUNET_strndup()
392  * @param linenumber where in the code was the call to GNUNET_strndup()
393  * @return `strndup(@a str,@a len)`
394  */
395 char *
396 GNUNET_xstrndup_ (const char *str,
397                   size_t len,
398                   const char *filename,
399                   int linenumber)
400 {
401   char *res;
402
403   if (0 == len)
404     return GNUNET_strdup ("");
405   GNUNET_assert_at (NULL != str,
406                     filename,
407                     linenumber);
408   len = strnlen (str,
409                  len);
410   res = GNUNET_xmalloc_ (len + 1,
411                          filename,
412                          linenumber);
413   GNUNET_memcpy (res, str, len);
414   /* res[len] = '\0'; 'malloc' zeros out anyway */
415   return res;
416 }
417
418
419 /**
420  * Grow an array.  Grows old by (*oldCount-newCount)*elementSize bytes
421  * and sets *oldCount to newCount.
422  *
423  * @param old address of the pointer to the array
424  *        *old may be NULL
425  * @param elementSize the size of the elements of the array
426  * @param oldCount address of the number of elements in the *old array
427  * @param newCount number of elements in the new array, may be 0
428  * @param filename where in the code was the call to GNUNET_array_grow()
429  * @param linenumber where in the code was the call to GNUNET_array_grow()
430  */
431 void
432 GNUNET_xgrow_ (void **old,
433                size_t elementSize,
434                unsigned int *oldCount,
435          unsigned int newCount,
436                const char *filename,
437                int linenumber)
438 {
439   void *tmp;
440   size_t size;
441
442   GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber);
443   size = newCount * elementSize;
444   if (0 == size)
445   {
446     tmp = NULL;
447   }
448   else
449   {
450     tmp = GNUNET_xmalloc_ (size, filename, linenumber);
451     if (NULL != *old)
452     {
453       GNUNET_memcpy (tmp, *old, elementSize * GNUNET_MIN(*oldCount, newCount));
454     }
455   }
456
457   if (NULL != *old)
458   {
459     GNUNET_xfree_ (*old, filename, linenumber);
460   }
461   *old = tmp;
462   *oldCount = newCount;
463 }
464
465
466 /**
467  * Like asprintf(), just portable.
468  *
469  * @param buf set to a buffer of sufficient size (allocated, caller must free)
470  * @param format format string (see printf(), fprintf(), etc.)
471  * @param ... data for format string
472  * @return number of bytes in `*@a buf`, excluding 0-termination
473  */
474 int
475 GNUNET_asprintf (char **buf,
476                  const char *format,
477                  ...)
478 {
479   int ret;
480   va_list args;
481
482   va_start (args, format);
483   ret = VSNPRINTF (NULL, 0, format, args);
484   va_end (args);
485   GNUNET_assert (ret >= 0);
486   *buf = GNUNET_malloc (ret + 1);
487   va_start (args, format);
488   ret = VSPRINTF (*buf, format, args);
489   va_end (args);
490   return ret;
491 }
492
493
494 /**
495  * Like snprintf(), just aborts if the buffer is of insufficient size.
496  *
497  * @param buf pointer to buffer that is written to
498  * @param size number of bytes in buf
499  * @param format format strings
500  * @param ... data for format string
501  * @return number of bytes written to buf or negative value on error
502  */
503 int
504 GNUNET_snprintf (char *buf,
505                  size_t size,
506                  const char *format, ...)
507 {
508   int ret;
509   va_list args;
510
511   va_start (args, format);
512   ret = VSNPRINTF (buf,
513                    size,
514                    format,
515                    args);
516   va_end (args);
517   GNUNET_assert ( (ret >= 0) &&
518                   (((size_t) ret) < size) );
519   return ret;
520 }
521
522
523 /**
524  * Create a copy of the given message.
525  *
526  * @param msg message to copy
527  * @return duplicate of the message
528  */
529 struct GNUNET_MessageHeader *
530 GNUNET_copy_message (const struct GNUNET_MessageHeader *msg)
531 {
532   struct GNUNET_MessageHeader *ret;
533   uint16_t msize;
534
535   msize = ntohs (msg->size);
536   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
537   ret = GNUNET_malloc (msize);
538   GNUNET_memcpy (ret,
539                  msg,
540                  msize);
541   return ret;
542 }
543
544
545 /* end of common_allocation.c */