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