1+ /*
2+ * This file provides a Windows-specific overriding of the malloc,
3+ * free, calloc, realloc, and msize functions using the Detours library.
4+ */
5+ #ifdef _DEBUG
6+ # include < crtdbg.h>
7+ #endif
8+
9+ #include " detours.h"
10+
11+ #include < new>
12+ #include < stdlib.h>
13+
14+ #pragma warning(push)
15+ #pragma warning(disable : 4075)
16+ // Needs to be the same segment as used in the pal as this is a single compilation unit
17+ #pragma init_seg(".CRT$XCB")
18+ #pragma warning(pop)
19+
20+ // Symbols for the original malloc, free, calloc, realloc, and msize functions
21+ auto * original_malloc = malloc;
22+ auto * original_calloc = calloc;
23+ auto * original_realloc = realloc;
24+ auto * original_free = free;
25+ auto * original_msize = _msize;
26+
27+ void * (*original_new)(size_t ) = operator new ;
28+ void * (*original_new2)(size_t , const std::nothrow_t &) = operator new ;
29+
30+ void * (*original_new_array)(size_t ) = operator new [];
31+ void * (*original_new_array2)(size_t , const std::nothrow_t &) = operator new [];
32+
33+ void (*original_delete)(void *) = operator delete ;
34+ void (*original_delete2)(void *, size_t ) = operator delete ;
35+ void (*original_delete3)(void *, const std::nothrow_t &) = operator delete ;
36+
37+ void (*original_delete_array)(void *) = operator delete[] ;
38+ void (*original_delete_array2)(void *, size_t ) = operator delete[] ;
39+
40+ #include < snmalloc/snmalloc_core.h>
41+ // Provides the global configuration for the snmalloc implementation.
42+ #include < snmalloc/backend/globalconfig.h>
43+
44+ #define SNMALLOC_PROVIDE_OWN_CONFIG
45+
46+ namespace snmalloc
47+ {
48+ class WindowsHeapAsSecondaryAllocator
49+ {
50+ public:
51+ // This flag is used to turn off checks on fast paths if the secondary
52+ // allocator does not own the memory at all.
53+ static constexpr inline bool pass_through = false ;
54+
55+ SNMALLOC_FAST_PATH
56+ static void initialize () {}
57+
58+ // We always use snmalloc for allocation.
59+ template <class SizeAlign >
60+ SNMALLOC_FAST_PATH static void * allocate (SizeAlign&&)
61+ {
62+ return nullptr ;
63+ }
64+
65+ // If the memory was not deallocated by snmalloc, then try the
66+ // original free.
67+ SNMALLOC_FAST_PATH
68+ static void deallocate (void * pointer)
69+ {
70+ if (pointer == nullptr )
71+ return ;
72+
73+ original_free (pointer);
74+ }
75+
76+ SNMALLOC_FAST_PATH
77+ static size_t alloc_size (const void * p)
78+ {
79+ return original_msize (const_cast <void *>(p));
80+ }
81+ };
82+
83+ // Root failed deallocations and msize requests to the Windows heap.
84+ using Config = snmalloc::StandardConfigClientMeta<
85+ NoClientMetaDataProvider,
86+ WindowsHeapAsSecondaryAllocator>;
87+ using Alloc = snmalloc::Allocator<Config>;
88+ } // namespace snmalloc
89+
90+ #define SNMALLOC_STATIC_LIBRARY_PREFIX snmalloc_
91+ #include " detours/detours.h"
92+
93+ #include < snmalloc/override/malloc.cc>
94+ #include < stdio.h>
95+ #include < windows.h>
96+
97+ // This name is not provided by malloc.cc above, so we define it here.
98+ size_t snmalloc_msize (void * ptr)
99+ {
100+ // Call the snmalloc function to get the allocation size.
101+ // This is not accurate as it rounds up, whereas the original msize
102+ // function returns the exact size of the allocation.
103+ return snmalloc::alloc_size (ptr);
104+ }
105+
106+ SnmallocDetour::SnmallocDetour ()
107+ {
108+ // Initilialize snmalloc.
109+ snmalloc_free (snmalloc_malloc (1 ));
110+
111+ DetourTransactionBegin ();
112+ DetourAttach (&(PVOID&)original_free, snmalloc_free);
113+ DetourAttach (&(PVOID&)original_delete, snmalloc_free);
114+ DetourAttach (&(PVOID&)original_delete2, snmalloc_free);
115+ DetourAttach (&(PVOID&)original_delete3, snmalloc_free);
116+ DetourAttach (&(PVOID&)original_delete_array, snmalloc_free);
117+ DetourAttach (&(PVOID&)original_delete_array2, snmalloc_free);
118+ DetourAttach (&(PVOID&)original_malloc, snmalloc_malloc);
119+ DetourAttach (&(PVOID&)original_calloc, snmalloc_calloc);
120+ DetourAttach (&(PVOID&)original_realloc, snmalloc_realloc);
121+ DetourAttach (&(PVOID&)original_msize, snmalloc_msize);
122+ DetourAttach (&(PVOID&)original_new, snmalloc_malloc);
123+ DetourAttach (&(PVOID&)original_new2, snmalloc_malloc);
124+ DetourAttach (&(PVOID&)original_new_array, snmalloc_malloc);
125+ DetourAttach (&(PVOID&)original_new_array2, snmalloc_malloc);
126+
127+ DetourTransactionCommit ();
128+ }
129+
130+ SnmallocDetour::~SnmallocDetour ()
131+ {
132+ // Detours performs allocation so during this some data structures will
133+ // be allocated with snmalloc. These cannot be handled by the Windows heap
134+ // so leave snmalloc::free in place to handle these allocations.
135+
136+ DetourTransactionBegin ();
137+ DetourDetach (&(PVOID&)original_calloc, snmalloc_calloc);
138+ DetourDetach (&(PVOID&)original_realloc, snmalloc_realloc);
139+ DetourDetach (&(PVOID&)original_malloc, snmalloc_malloc);
140+ DetourDetach (&(PVOID&)original_msize, snmalloc_msize);
141+ DetourDetach (&(PVOID&)original_new, snmalloc_malloc);
142+ DetourDetach (&(PVOID&)original_new2, snmalloc_malloc);
143+ DetourDetach (&(PVOID&)original_new_array, snmalloc_malloc);
144+ DetourDetach (&(PVOID&)original_new_array2, snmalloc_malloc);
145+ DetourTransactionCommit ();
146+
147+ // This transaction's allocation will come from the Windows heap, so it is
148+ // safe to use the Windows heap's free during teardown.
149+ DetourTransactionBegin ();
150+ DetourDetach (&(PVOID&)original_free, snmalloc_free);
151+ DetourDetach (&(PVOID&)original_delete, snmalloc_free);
152+ DetourAttach (&(PVOID&)original_delete2, snmalloc_free);
153+ DetourDetach (&(PVOID&)original_delete3, snmalloc_free);
154+ DetourDetach (&(PVOID&)original_delete_array, snmalloc_free);
155+ DetourDetach (&(PVOID&)original_delete_array2, snmalloc_free);
156+ DetourTransactionCommit ();
157+ }
158+
159+ extern " C" bool is_snmalloc_detour (void * ptr)
160+ {
161+ return snmalloc::is_owned (ptr);
162+ }
0 commit comments