1 | /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ |
2 | /* If you are missing that file, acquire a complete release at teeworlds.com. */ |
3 | #ifndef GAME_ALLOC_H |
4 | #define GAME_ALLOC_H |
5 | |
6 | #include <new> |
7 | |
8 | #include <base/system.h> |
9 | #ifndef __has_feature |
10 | #define __has_feature(x) 0 |
11 | #endif |
12 | #if __has_feature(address_sanitizer) |
13 | #include <sanitizer/asan_interface.h> |
14 | #else |
15 | #define ASAN_POISON_MEMORY_REGION(addr, size) \ |
16 | ((void)(addr), (void)(size)) |
17 | #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ |
18 | ((void)(addr), (void)(size)) |
19 | #endif |
20 | |
21 | #define MACRO_ALLOC_HEAP() \ |
22 | public: \ |
23 | void *operator new(size_t Size) \ |
24 | { \ |
25 | void *p = malloc(Size); \ |
26 | mem_zero(p, Size); \ |
27 | return p; \ |
28 | } \ |
29 | void operator delete(void *pPtr) \ |
30 | { \ |
31 | free(pPtr); \ |
32 | } \ |
33 | \ |
34 | private: |
35 | |
36 | #define MACRO_ALLOC_POOL_ID() \ |
37 | public: \ |
38 | void *operator new(size_t Size, int id); \ |
39 | void operator delete(void *p, int id); \ |
40 | void operator delete(void *p); /* NOLINT(misc-new-delete-overloads) */ \ |
41 | \ |
42 | private: |
43 | |
44 | #if __has_feature(address_sanitizer) |
45 | #define MACRO_ALLOC_GET_SIZE(POOLTYPE) ((sizeof(POOLTYPE) + 7) & ~7) |
46 | #else |
47 | #define MACRO_ALLOC_GET_SIZE(POOLTYPE) (sizeof(POOLTYPE)) |
48 | #endif |
49 | |
50 | #define MACRO_ALLOC_POOL_ID_IMPL(POOLTYPE, PoolSize) \ |
51 | static char gs_PoolData##POOLTYPE[PoolSize][MACRO_ALLOC_GET_SIZE(POOLTYPE)] = {{0}}; \ |
52 | static int gs_PoolUsed##POOLTYPE[PoolSize] = {0}; \ |
53 | MAYBE_UNUSED static int gs_PoolDummy##POOLTYPE = (ASAN_POISON_MEMORY_REGION(gs_PoolData##POOLTYPE, sizeof(gs_PoolData##POOLTYPE)), 0); \ |
54 | void *POOLTYPE::operator new(size_t Size, int id) \ |
55 | { \ |
56 | dbg_assert(sizeof(POOLTYPE) >= Size, "size error"); \ |
57 | dbg_assert(!gs_PoolUsed##POOLTYPE[id], "already used"); \ |
58 | ASAN_UNPOISON_MEMORY_REGION(gs_PoolData##POOLTYPE[id], sizeof(gs_PoolData##POOLTYPE[id])); \ |
59 | gs_PoolUsed##POOLTYPE[id] = 1; \ |
60 | mem_zero(gs_PoolData##POOLTYPE[id], sizeof(gs_PoolData##POOLTYPE[id])); \ |
61 | return gs_PoolData##POOLTYPE[id]; \ |
62 | } \ |
63 | void POOLTYPE::operator delete(void *p, int id) \ |
64 | { \ |
65 | dbg_assert(gs_PoolUsed##POOLTYPE[id], "not used"); \ |
66 | dbg_assert(id == (POOLTYPE *)p - (POOLTYPE *)gs_PoolData##POOLTYPE, "invalid id"); \ |
67 | gs_PoolUsed##POOLTYPE[id] = 0; \ |
68 | mem_zero(gs_PoolData##POOLTYPE[id], sizeof(gs_PoolData##POOLTYPE[id])); \ |
69 | ASAN_POISON_MEMORY_REGION(gs_PoolData##POOLTYPE[id], sizeof(gs_PoolData##POOLTYPE[id])); \ |
70 | } \ |
71 | void POOLTYPE::operator delete(void *p) /* NOLINT(misc-new-delete-overloads) */ \ |
72 | { \ |
73 | int id = (POOLTYPE *)p - (POOLTYPE *)gs_PoolData##POOLTYPE; \ |
74 | dbg_assert(gs_PoolUsed##POOLTYPE[id], "not used"); \ |
75 | gs_PoolUsed##POOLTYPE[id] = 0; \ |
76 | mem_zero(gs_PoolData##POOLTYPE[id], sizeof(gs_PoolData##POOLTYPE[id])); \ |
77 | ASAN_POISON_MEMORY_REGION(gs_PoolData##POOLTYPE[id], sizeof(gs_PoolData##POOLTYPE[id])); \ |
78 | } |
79 | |
80 | #endif |
81 | |