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 <base/dbg.h>
7#include <base/mem.h>
8
9#include <cstdlib>
10#include <new>
11
12#ifndef __has_feature
13#define __has_feature(x) 0
14#endif
15#if __has_feature(address_sanitizer)
16#include <sanitizer/asan_interface.h>
17#else
18#define ASAN_POISON_MEMORY_REGION(addr, size) \
19 ((void)(addr), (void)(size))
20#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
21 ((void)(addr), (void)(size))
22#endif
23
24#define MACRO_ALLOC_HEAP() \
25public: \
26 void *operator new(size_t Size) \
27 { \
28 void *pObj = malloc(Size); \
29 mem_zero(pObj, Size); \
30 return pObj; \
31 } \
32 void operator delete(void *pPtr) \
33 { \
34 free(pPtr); \
35 } \
36\
37private:
38
39#define MACRO_ALLOC_POOL_ID() \
40public: \
41 void *operator new(size_t Size, int Id); \
42 void operator delete(void *pObj, int Id); \
43 void operator delete(void *pObj); /* NOLINT(misc-new-delete-overloads) */ \
44\
45private:
46
47#if __has_feature(address_sanitizer)
48#define MACRO_ALLOC_GET_SIZE(POOLTYPE) ((sizeof(POOLTYPE) + 7) & ~7)
49#else
50#define MACRO_ALLOC_GET_SIZE(POOLTYPE) (sizeof(POOLTYPE))
51#endif
52
53#define MACRO_ALLOC_POOL_ID_IMPL(POOLTYPE, PoolSize) \
54 static char gs_PoolData##POOLTYPE[PoolSize][MACRO_ALLOC_GET_SIZE(POOLTYPE)] = {{0}}; \
55 static int gs_PoolUsed##POOLTYPE[PoolSize] = {0}; \
56 [[maybe_unused]] static int gs_PoolDummy##POOLTYPE = (ASAN_POISON_MEMORY_REGION(gs_PoolData##POOLTYPE, sizeof(gs_PoolData##POOLTYPE)), 0); \
57 void *POOLTYPE::operator new(size_t Size, int Id) \
58 { \
59 dbg_assert(sizeof(POOLTYPE) >= Size, "size error"); \
60 dbg_assert(!gs_PoolUsed##POOLTYPE[Id], "already used"); \
61 ASAN_UNPOISON_MEMORY_REGION(gs_PoolData##POOLTYPE[Id], sizeof(gs_PoolData##POOLTYPE[Id])); \
62 gs_PoolUsed##POOLTYPE[Id] = 1; \
63 mem_zero(gs_PoolData##POOLTYPE[Id], sizeof(gs_PoolData##POOLTYPE[Id])); \
64 return gs_PoolData##POOLTYPE[Id]; \
65 } \
66 void POOLTYPE::operator delete(void *pObj, int Id) \
67 { \
68 dbg_assert(gs_PoolUsed##POOLTYPE[Id], "not used"); \
69 dbg_assert(Id == (POOLTYPE *)pObj - (POOLTYPE *)gs_PoolData##POOLTYPE, "invalid id"); /* NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object) */ \
70 gs_PoolUsed##POOLTYPE[Id] = 0; \
71 mem_zero(gs_PoolData##POOLTYPE[Id], sizeof(gs_PoolData##POOLTYPE[Id])); \
72 ASAN_POISON_MEMORY_REGION(gs_PoolData##POOLTYPE[Id], sizeof(gs_PoolData##POOLTYPE[Id])); \
73 } \
74 void POOLTYPE::operator delete(void *pObj) /* NOLINT(misc-new-delete-overloads) */ \
75 { \
76 int Id = (POOLTYPE *)pObj - (POOLTYPE *)gs_PoolData##POOLTYPE; /* NOLINT(bugprone-pointer-arithmetic-on-polymorphic-object) */ \
77 dbg_assert(gs_PoolUsed##POOLTYPE[Id], "not used"); \
78 gs_PoolUsed##POOLTYPE[Id] = 0; \
79 mem_zero(gs_PoolData##POOLTYPE[Id], sizeof(gs_PoolData##POOLTYPE[Id])); \
80 ASAN_POISON_MEMORY_REGION(gs_PoolData##POOLTYPE[Id], sizeof(gs_PoolData##POOLTYPE[Id])); \
81 }
82
83#endif
84