malloc_wrappers.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* The wrapper functions in this file work like regular malloc() and free(),
  2. * but store check values before and after the allocation. This helps to catch
  3. * any buffer overrun errors in the test cases.
  4. */
  5. #include "malloc_wrappers.h"
  6. #include <stdint.h>
  7. #include <stdio.h>
  8. #include <assert.h>
  9. #include <string.h>
  10. #define GUARD_SIZE (sizeof(size_t)*3)
  11. #define PREFIX_SIZE (sizeof(size_t)*2)
  12. #define CHECK1 ((size_t)0xDEADBEEF)
  13. #define CHECK2 ((size_t)0x600DCAFE)
  14. #ifndef MAX_ALLOC_BYTES
  15. #define MAX_ALLOC_BYTES 16*1024*1024
  16. #endif
  17. #ifndef DEBUG_MALLOC
  18. #define DEBUG_MALLOC 0
  19. #endif
  20. static size_t g_alloc_count = 0;
  21. static size_t g_alloc_bytes = 0;
  22. static size_t g_max_alloc_bytes = MAX_ALLOC_BYTES;
  23. #ifdef LLVMFUZZER
  24. /* LLVM libsanitizer has a realloc() implementation that always copies
  25. * the whole memory block, even if there would be space to expand it in
  26. * place. This gets pretty slow when fuzzing, so this wrapper limits the
  27. * realloc() calls by rounding allocation size upwards. Real world
  28. * realloc() implementations are hopefully smarter. */
  29. static size_t round_blocksize(size_t size)
  30. {
  31. if (size < 256)
  32. {
  33. return size;
  34. }
  35. else
  36. {
  37. return (size + 1023) / 1024 * 1024;
  38. }
  39. }
  40. #else
  41. static size_t round_blocksize(size_t size)
  42. {
  43. return size;
  44. }
  45. #endif
  46. /* Allocate memory and place check values before and after. */
  47. void* malloc_with_check(size_t size)
  48. {
  49. char *buf = NULL;
  50. if (size <= g_max_alloc_bytes - g_alloc_bytes)
  51. {
  52. buf = malloc(round_blocksize(size + GUARD_SIZE));
  53. }
  54. if (buf)
  55. {
  56. ((size_t*)buf)[0] = size;
  57. ((size_t*)buf)[1] = CHECK1;
  58. ((size_t*)(buf + size))[2] = CHECK2;
  59. g_alloc_count++;
  60. g_alloc_bytes += size;
  61. if (DEBUG_MALLOC) fprintf(stderr, "Alloc 0x%04x/%u\n", (unsigned)(uintptr_t)(buf + PREFIX_SIZE), (unsigned)size);
  62. return buf + PREFIX_SIZE;
  63. }
  64. else
  65. {
  66. if (DEBUG_MALLOC) fprintf(stderr, "malloc(%u) failed\n", (unsigned)size);
  67. return NULL;
  68. }
  69. }
  70. /* Free memory allocated with malloc_with_check() and do the checks. */
  71. void free_with_check(void *mem)
  72. {
  73. if (mem)
  74. {
  75. char *buf = (char*)mem - PREFIX_SIZE;
  76. size_t size = ((size_t*)buf)[0];
  77. if (DEBUG_MALLOC) fprintf(stderr, "Release 0x%04x/%u\n", (unsigned)(uintptr_t)mem, (unsigned)size);
  78. assert(((size_t*)buf)[1] == CHECK1);
  79. assert(((size_t*)(buf + size))[2] == CHECK2);
  80. assert(g_alloc_count > 0);
  81. assert(g_alloc_bytes >= size);
  82. ((size_t*)buf)[1] = 0;
  83. ((size_t*)(buf + size))[2] = 0;
  84. g_alloc_count--;
  85. g_alloc_bytes -= size;
  86. free(buf);
  87. }
  88. }
  89. /* Reallocate block and check / write guard values */
  90. void* realloc_with_check(void *ptr, size_t size)
  91. {
  92. if (!ptr && size)
  93. {
  94. /* Allocate new block and write guard values */
  95. return malloc_with_check(size);
  96. }
  97. else if (ptr && size)
  98. {
  99. /* Change block size */
  100. char *buf = (char*)ptr - PREFIX_SIZE;
  101. size_t oldsize = ((size_t*)buf)[0];
  102. assert(((size_t*)buf)[1] == CHECK1);
  103. assert(((size_t*)(buf + oldsize))[2] == CHECK2);
  104. assert(g_alloc_count > 0);
  105. assert(g_alloc_bytes >= oldsize);
  106. if (size <= g_max_alloc_bytes - (g_alloc_bytes - oldsize))
  107. {
  108. size_t new_rounded = round_blocksize(size + GUARD_SIZE);
  109. size_t old_rounded = round_blocksize(oldsize + GUARD_SIZE);
  110. if (new_rounded != old_rounded)
  111. {
  112. buf = realloc(buf, new_rounded);
  113. }
  114. }
  115. else
  116. {
  117. buf = NULL;
  118. }
  119. if (!buf)
  120. {
  121. if (DEBUG_MALLOC) fprintf(stderr, "Realloc 0x%04x/%u to %u failed\n", (unsigned)(uintptr_t)ptr, (unsigned)oldsize, (unsigned)size);
  122. return NULL;
  123. }
  124. ((size_t*)buf)[0] = size;
  125. ((size_t*)buf)[1] = CHECK1;
  126. ((size_t*)(buf + size))[2] = CHECK2;
  127. g_alloc_bytes -= oldsize;
  128. g_alloc_bytes += size;
  129. if (DEBUG_MALLOC) fprintf(stderr, "Realloc 0x%04x/%u to 0x%04x/%u\n", (unsigned)(uintptr_t)ptr, (unsigned)oldsize, (unsigned)(uintptr_t)(buf + PREFIX_SIZE), (unsigned)size);
  130. return buf + PREFIX_SIZE;
  131. }
  132. else if (ptr && !size)
  133. {
  134. /* Deallocate */
  135. free_with_check(ptr);
  136. return NULL;
  137. }
  138. else
  139. {
  140. /* No action */
  141. return NULL;
  142. }
  143. }
  144. /* Return total number of allocations not yet released */
  145. size_t get_alloc_count()
  146. {
  147. return g_alloc_count;
  148. }
  149. /* Return allocated size for a pointer returned from malloc(). */
  150. size_t get_allocation_size(const void *mem)
  151. {
  152. char *buf = (char*)mem - PREFIX_SIZE;
  153. return ((size_t*)buf)[0];
  154. }
  155. /* Get total number of allocated bytes */
  156. size_t get_alloc_bytes()
  157. {
  158. return g_alloc_bytes;
  159. }
  160. /* Set limit for allocation size */
  161. void set_max_alloc_bytes(size_t max_bytes)
  162. {
  163. g_max_alloc_bytes = max_bytes;
  164. }
  165. size_t get_max_alloc_bytes()
  166. {
  167. return g_max_alloc_bytes;
  168. }