common_allocation.c 15 KB

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