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