custom_memory_manager.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2018 (c) Stefan Profanter, fortiss GmbH
  6. */
  7. /**
  8. * This memory manager allows to manually reduce the available RAM.
  9. *
  10. * It keeps track of malloc and free calls and counts the available RAM.
  11. * If the requested memory allocation results in hitting the limit,
  12. * it will return NULL and prevent the new allocation.
  13. */
  14. #include "custom_memory_manager.h"
  15. #include <stdlib.h>
  16. #include <stdio.h>
  17. #include <stdint.h>
  18. #include <limits.h>
  19. #include <pthread.h>
  20. pthread_mutex_t mutex;
  21. struct UA_mm_entry {
  22. size_t size;
  23. void* address;
  24. struct UA_mm_entry *next;
  25. struct UA_mm_entry *prev;
  26. };
  27. unsigned long long totalMemorySize = 0;
  28. unsigned long long memoryLimit = ULONG_MAX;
  29. /*
  30. * Head and Tail of the double linked list
  31. */
  32. struct UA_mm_entry *address_map_first = NULL;
  33. struct UA_mm_entry *address_map_last = NULL;
  34. void UA_memoryManager_setLimit(unsigned long long newLimit) {
  35. memoryLimit = newLimit;
  36. //printf("MemoryManager: Setting memory limit to %lld\n", newLimit);
  37. }
  38. int UA_memoryManager_setLimitFromLast4Bytes(const uint8_t *data, size_t size) {
  39. if (size <4)
  40. return 0;
  41. // just cast the last 4 bytes to uint32
  42. const uint32_t *newLimit = (const uint32_t*)(uintptr_t)&(data[size-4]);
  43. uint32_t limit;
  44. // use memcopy to avoid asan complaining on misaligned memory
  45. memcpy(&limit, newLimit, sizeof(uint32_t));
  46. UA_memoryManager_setLimit(limit);
  47. return 1;
  48. }
  49. /**
  50. * Add address entry to the linked list after it was allocated.
  51. *
  52. * @param size Size of the allocated memory block
  53. * @param addr Address of the allocated memory block
  54. * @return 1 on success, 0 if it failed
  55. */
  56. static int addToMap(size_t size, void *addr) {
  57. struct UA_mm_entry *newEntry = (struct UA_mm_entry*)malloc(sizeof(struct UA_mm_entry));
  58. if (!newEntry) {
  59. //printf("MemoryManager: Could not allocate memory");
  60. return 0;
  61. }
  62. newEntry->size = size;
  63. newEntry->address = addr;
  64. newEntry->next = NULL;
  65. pthread_mutex_lock(&mutex);
  66. newEntry->prev = address_map_last;
  67. if (address_map_last)
  68. address_map_last->next = newEntry;
  69. address_map_last = newEntry;
  70. totalMemorySize += size;
  71. if (address_map_first == NULL) {
  72. address_map_first = newEntry;
  73. }
  74. pthread_mutex_unlock(&mutex);
  75. //printf("Total size (malloc): %lld And new address: %p Entry %p\n", totalMemorySize, addr, (void*)newEntry);
  76. return 1;
  77. }
  78. /**
  79. * Remove entry from the list before the memory block is freed.
  80. *
  81. * @param addr Address of the memory block which is freed.
  82. *
  83. * @return 1 on success, 0 if the memory block was not found in the list.
  84. */
  85. static int removeFromMap(void *addr) {
  86. if (addr == NULL)
  87. return 1;
  88. pthread_mutex_lock(&mutex);
  89. struct UA_mm_entry *e = address_map_last;
  90. while (e) {
  91. if (e->address == addr) {
  92. if (e == address_map_first)
  93. address_map_first = e->next;
  94. if (e == address_map_last)
  95. address_map_last = e->prev;
  96. if (e->prev) {
  97. e->prev->next = e->next;
  98. }
  99. if (e->next) {
  100. e->next->prev = e->prev;
  101. }
  102. totalMemorySize -= e->size;
  103. //printf("Total size (free): %lld after addr %p and deleting %p\n", totalMemorySize, addr, (void*)e);
  104. free(e);
  105. pthread_mutex_unlock(&mutex);
  106. return 1;
  107. }
  108. e = e->prev;
  109. }
  110. pthread_mutex_unlock(&mutex);
  111. //printf("MemoryManager: Entry with address %p not found", addr);
  112. return 0;
  113. }
  114. void* UA_memoryManager_malloc(size_t size) {
  115. if (totalMemorySize + size > memoryLimit)
  116. return NULL;
  117. void *addr = malloc(size);
  118. if (!addr)
  119. return NULL;
  120. addToMap(size, addr);
  121. return addr;
  122. }
  123. void* UA_memoryManager_calloc(size_t num, size_t size) {
  124. if (totalMemorySize + (size * num) > memoryLimit)
  125. return NULL;
  126. void *addr = calloc(num, size);
  127. if (!addr)
  128. return NULL;
  129. addToMap(size*num, addr);
  130. return addr;
  131. }
  132. void* UA_memoryManager_realloc(void *ptr, size_t new_size) {
  133. removeFromMap(ptr);
  134. if (totalMemorySize + new_size > memoryLimit)
  135. return NULL;
  136. void *addr = realloc(ptr, new_size);
  137. if (!addr)
  138. return NULL;
  139. addToMap(new_size, addr);
  140. return addr;
  141. }
  142. void UA_memoryManager_free(void* ptr) {
  143. removeFromMap(ptr);
  144. free(ptr);
  145. }