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