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() \
22public: \
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\
34private:
35
36#define MACRO_ALLOC_POOL_ID() \
37public: \
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\
42private:
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