Derive-C
Loading...
Searching...
No Matches
memory_tracker.h File Reference
#include <derive-c/core/prelude.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
Include dependency graph for memory_tracker.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  memory_tracker_capability { MEMORY_TRACKER_CAP_NONE , MEMORY_TRACKER_CAP_WRITE , MEMORY_TRACKER_CAP_READ_WRITE }
 a wrapper over asan & msan Containers and allocators can use this for custom asan & msan poisoning, provided: More...
enum  memory_tracker_level { MEMORY_TRACKER_LVL_NONE = 0 , MEMORY_TRACKER_LVL_ALLOC = 1 , MEMORY_TRACKER_LVL_CONTAINER = 2 }

Functions

static void memory_tracker_set (memory_tracker_level level, memory_tracker_capability cap, const volatile void *addr, size_t size)
static void memory_tracker_check (memory_tracker_level level, memory_tracker_capability cap, const void *addr, size_t size)
static void memory_tracker_debug (FILE *stream, const void *addr, size_t size)

Variables

static const memory_tracker_level memory_tracker_global_level = MEMORY_TRACKER_LVL_CONTAINER

Enumeration Type Documentation

◆ memory_tracker_capability

a wrapper over asan & msan Containers and allocators can use this for custom asan & msan poisoning, provided:

  • The appropriate level is set (so that container, or allocator poisoning can be disabled)
  • Allocators / containers setting capabilities must set capabilities when providing to the level below. e.g. a container may set CAP to None for user access checks, but set to uninit before passing to allocator free. Capabilities to assign to memory regions
Enumerator
MEMORY_TRACKER_CAP_NONE 
MEMORY_TRACKER_CAP_WRITE 
MEMORY_TRACKER_CAP_READ_WRITE 

Definition at line 45 of file memory_tracker.h.

45 { // NOLINT(performance-enum-size)
memory_tracker_capability
a wrapper over asan & msan Containers and allocators can use this for custom asan & msan poisoning,...
@ MEMORY_TRACKER_CAP_NONE
@ MEMORY_TRACKER_CAP_WRITE
@ MEMORY_TRACKER_CAP_READ_WRITE

◆ memory_tracker_level

The level at which to track memory state:

  • when testing allocators, none
  • when testing containers, at the allocator level
  • when testing users code, at the container and below level
Enumerator
MEMORY_TRACKER_LVL_NONE 
MEMORY_TRACKER_LVL_ALLOC 
MEMORY_TRACKER_LVL_CONTAINER 

Definition at line 58 of file memory_tracker.h.

58 { // NOLINT(performance-enum-size)
memory_tracker_level
@ MEMORY_TRACKER_LVL_NONE
@ MEMORY_TRACKER_LVL_CONTAINER
@ MEMORY_TRACKER_LVL_ALLOC

Function Documentation

◆ memory_tracker_check()

void memory_tracker_check ( memory_tracker_level level,
memory_tracker_capability cap,
const void * addr,
size_t size )
static

Definition at line 112 of file memory_tracker.h.

113 {
114 if (level <= memory_tracker_global_level) {
115#if defined(MSAN_ON)
116 // msan tracks the initialised state, so for none & write we want poisoned / unreadable.
117 switch (cap) {
120 if (__msan_test_shadow((void*)addr, size) != -1) {
121 PANIC("Memory region %p (%zu bytes) is not uninitialised, but should be", addr,
122 size);
123 }
124 return;
125 }
127 if (__msan_test_shadow((void*)addr, size) == -1) {
128 PANIC("Memory region %p (%zu bytes) is not uninitialised, but should be", addr,
129 size);
130 }
131 return;
132 }
133 }
134 UNREACHABLE("Invalid capability");
135#elif defined(ASAN_ON)
136 bool const region_is_poisoned = __asan_region_is_poisoned((void*)addr, size);
137 switch (cap) {
139 if (!region_is_poisoned) {
140 bool const is_at_end_of_granule = is_aligned_pow2_exp((char*)addr - 7, 3);
141 bool const is_next_byte_poisoned =
142 __asan_region_is_poisoned((void*)((char*)addr + 1), 1);
143
144 // JUSTIFY: panic conditionally
145 // - Asan tracks poisoning at the granule/8 byte level, with the number of bytes
146 // poisoned from the end of the granule
147 // - Hence if we have a poisoned byte, in the middle of a granule, with the rest
148 // unpoisoned, asan will mark that byte as unpoisoned
149 // Therefore, we only throw if we are certain the poisoning is wrong (e.g. it would
150 // be continuing contiguous poisoned part of a granule, or its at the start of a
151 // granule)
152 if (is_at_end_of_granule || is_next_byte_poisoned) {
153
154 PANIC("Memory region %p (%zu bytes) is not poisoned, but should be", addr,
155 size);
156 }
157 }
158 return;
159 }
162 if (region_is_poisoned) {
163 PANIC("Memory region %p (%zu bytes) is poisoned, but should be accessible", addr,
164 size);
165 }
166 return;
167 }
168 }
169 UNREACHABLE("Invalid capability");
170#else
171 (void)addr;
172 (void)size;
173 (void)cap;
174#endif
175 }
176}
static INDEX_TYPE size(SELF const *self)
Definition template.h:275
#define UNREACHABLE(...)
Definition macros.h:49
#define PANIC(...)
Definition macros.h:34
static bool INLINE CONST is_aligned_pow2_exp(const void *ptr, unsigned exp)
Definition math.h:31
static const memory_tracker_level memory_tracker_global_level
Here is the call graph for this function:
Here is the caller graph for this function:

◆ memory_tracker_debug()

void memory_tracker_debug ( FILE * stream,
const void * addr,
size_t size )
static

Definition at line 178 of file memory_tracker.h.

178 {
179 fprintf(stream, "memory tracker debug (%zu bytes) at %p ", size, addr);
180#if defined(MSAN_ON)
181 fprintf(stream, "[MSAN]: ")
182 // msan tracks the initialised state, so for none & write we want poisoned / unreadable.
183 for (size_t i = 0; i < size; i++) {
184 fprintf(stream, "\n%p: ", (char*)addr + i);
185 if (__msan_test_shadow((char*)addr + i, 1) == -1) {
186 fprintf(stream, "U [%02x]", *((unsigned char*)addr + i));
187 } else {
188 fprintf(stream, "I [%02x]", *((unsigned char*)addr + i));
189 }
190 }
191#elif defined(ASAN_ON)
192 // Each shadow memory entry covers 8 bytes of memory, aligned to 8 bytes, so we print this.
193 char* addr_start = (char*)addr;
194 char* addr_end = addr_start + size;
195 char* granule_base = (char*)((uintptr_t)addr & ~0x7); // NOLINT(performance-no-int-to-ptr)
196 char* granule_end =
197 (char*)(((uintptr_t)addr + size + 7) & ~0x7); // NOLINT(performance-no-int-to-ptr)
198
199 fprintf(stream, "[ASAN]:");
200 fprintf(stream,
201 "\ndisplaying each 8 byte grandule (asan tracks poisoning as 0-8 bytes from the end)");
202 fprintf(stream, "\n");
203 fprintf(stream, "\n ");
204 for (size_t b = 0; b < 8; b++) {
205 fprintf(stream, " %lu ", b);
206 }
207 fprintf(stream, "\n");
208 for (char* p = granule_base; p < granule_end; p += 8) {
209 fprintf(stream, "%p: ", p);
210 for (char* b = p; b < p + 8; b++) {
211 bool const poisoned = __asan_region_is_poisoned(b, 1);
212 bool const in_selected = (b >= addr_start && b < addr_end);
213 uint8_t value;
214 if (poisoned) {
215 __asan_unpoison_memory_region(b, 1);
216 value = *b;
217 __asan_poison_memory_region(b, 1);
218 } else {
219 value = *b;
220 }
221
222 char const status = poisoned ? 'P' : 'U';
223
224 if (in_selected) {
225 fprintf(stream, "[%c|%02x] ", status, value);
226 } else {
227 fprintf(stream, "|%c|%02x| ", status, value);
228 }
229 }
230 fprintf(stream, "\n");
231 }
232#else
233 fprintf(stream, "[NO TRACKING]");
234 (void)addr;
235 (void)size;
236#endif
237 fprintf(stream, "\n");
238}
static FILE * stream(SELF *self)
Opens a file for.
Definition template.h:112
Here is the call graph for this function:

◆ memory_tracker_set()

void memory_tracker_set ( memory_tracker_level level,
memory_tracker_capability cap,
const volatile void * addr,
size_t size )
static

Definition at line 74 of file memory_tracker.h.

75 {
76 if (level <= memory_tracker_global_level) {
77#if defined(MSAN_ON)
78 // msan tracks the initialised state, so for none & write we want poisoned / unreadable.
79 switch (cap) {
82 __msan_poison(addr, size);
83 return;
84 }
86 __msan_unpoison(addr, size);
87 return;
88 }
89 }
90 UNREACHABLE("Invalid capability");
91#elif defined(ASAN_ON)
92 switch (cap) {
94 __asan_poison_memory_region(addr, size);
95 return;
96 }
99 __asan_unpoison_memory_region(addr, size);
100 return;
101 }
102 }
103 UNREACHABLE("Invalid capability");
104#else
105 (void)addr;
106 (void)size;
107 (void)cap;
108#endif
109 }
110}
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ memory_tracker_global_level

const memory_tracker_level memory_tracker_global_level = MEMORY_TRACKER_LVL_CONTAINER
static

Definition at line 71 of file memory_tracker.h.