Skip to content

Commit 0033aa8

Browse files
authored
Allow new/delete operators to be called before DllMain (#5454)
Allow new/delete operators to be called before DllMain and allocator initialization in DxcInitThreadMalloc(). The operators can be called before DllMain from CRT libraries when static linking is enabled. If that happens, the new/delete operators will fallback to the standard allocator and use CoTaskMemAlloc/Free directly instead of CoGetMalloc, Alloc/Free & Release for better perf. Enables fixing of [#5163](#5163) and [#5178](#5178).
1 parent 634c2f3 commit 0033aa8

5 files changed

Lines changed: 49 additions & 14 deletions

File tree

include/dxc/Support/Global.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ void DxcClearThreadMalloc() throw();
5454
// Used to retrieve the current invocation's allocator or perform an alloc/free/realloc.
5555
IMalloc *DxcGetThreadMallocNoRef() throw();
5656

57+
// Common implementation of operators new and delete
58+
void *DxcNew(std::size_t size) throw();
59+
void DxcDelete(void* ptr) throw();
60+
5761
class DxcThreadMalloc {
5862
public:
5963
explicit DxcThreadMalloc(IMalloc *pMallocOrNull) throw();

lib/DxcSupport/dxcmem.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,31 @@ DxcThreadMalloc::DxcThreadMalloc(IMalloc *pMallocOrNull) throw() {
9898
DxcThreadMalloc::~DxcThreadMalloc() {
9999
DxcSwapThreadMalloc(pPrior, nullptr);
100100
}
101+
102+
void* DxcNew(std::size_t size) throw() {
103+
void *ptr;
104+
IMalloc* iMalloc = DxcGetThreadMallocNoRef();
105+
if (iMalloc != nullptr) {
106+
ptr = iMalloc->Alloc(size);
107+
} else {
108+
// DxcGetThreadMallocNoRef() returning null means the operator is called before DllMain
109+
// where the g_pDefaultMalloc is initialized, for example from CRT libraries when
110+
// static linking is enabled. In that case fallback to the standard allocator
111+
// and use CoTaskMemAlloc directly instead of CoGetMalloc, Alloc & Release for better perf.
112+
ptr = CoTaskMemAlloc(size);
113+
}
114+
return ptr;
115+
}
116+
117+
void DxcDelete(void *ptr) throw() {
118+
IMalloc* iMalloc = DxcGetThreadMallocNoRef();
119+
if (iMalloc != nullptr) {
120+
iMalloc->Free(ptr);
121+
} else {
122+
// DxcGetThreadMallocNoRef() returning null means the operator is called before DllMain
123+
// where the g_pDefaultMalloc is initialized, for example from CRT libraries when
124+
// static linking is enabled. In that case fallback to the standard allocator
125+
// and use CoTaskMemFree directly instead of CoGetMalloc, Free & Release for better perf.
126+
CoTaskMemFree(ptr);
127+
}
128+
}

tools/clang/tools/dxcompiler/DXCompiler.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,24 @@ HRESULT SetupRegistryPassForPIX();
3131

3232
#if defined(LLVM_ON_WIN32) && !defined(DXC_DISABLE_ALLOCATOR_OVERRIDES)
3333
// operator new and friends.
34-
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
35-
void * ptr = DxcGetThreadMallocNoRef()->Alloc(size);
34+
void* __CRTDECL operator new(std::size_t size) noexcept(false) {
35+
void *ptr = DxcNew(size);
3636
if (ptr == nullptr)
3737
throw std::bad_alloc();
3838
return ptr;
3939
}
40+
4041
void * __CRTDECL operator new(std::size_t size,
4142
const std::nothrow_t &nothrow_value) throw() {
42-
return DxcGetThreadMallocNoRef()->Alloc(size);
43+
return DxcNew(size);
4344
}
45+
4446
void __CRTDECL operator delete (void* ptr) throw() {
45-
DxcGetThreadMallocNoRef()->Free(ptr);
47+
DxcDelete(ptr);
4648
}
49+
4750
void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() {
48-
DxcGetThreadMallocNoRef()->Free(ptr);
51+
DxcDelete(ptr);
4952
}
5053
#endif
5154

tools/clang/tools/dxlib-sample/dxlib_sample.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,20 @@ using namespace hlsl;
2222

2323
// operator new and friends.
2424
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
25-
void * ptr = DxcGetThreadMallocNoRef()->Alloc(size);
25+
void *ptr = DxcNew(size);
2626
if (ptr == nullptr)
2727
throw std::bad_alloc();
2828
return ptr;
2929
}
3030
void * __CRTDECL operator new(std::size_t size,
3131
const std::nothrow_t &nothrow_value) throw() {
32-
return DxcGetThreadMallocNoRef()->Alloc(size);
32+
return DxcNew(size);
3333
}
3434
void __CRTDECL operator delete (void* ptr) throw() {
35-
DxcGetThreadMallocNoRef()->Free(ptr);
35+
DxcDelete(ptr);
3636
}
3737
void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() {
38-
DxcGetThreadMallocNoRef()->Free(ptr);
38+
DxcDelete(ptr);
3939
}
4040
// Finish of new delete.
4141

tools/clang/tools/dxrfallbackcompiler/DXCompiler.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ namespace hlsl { HRESULT SetupRegistryPassForHLSL(); }
2626

2727
#if !defined(DXC_DISABLE_ALLOCATOR_OVERRIDES)
2828
// operator new and friends.
29-
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
30-
void * ptr = DxcGetThreadMallocNoRef()->Alloc(size);
29+
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
30+
void *ptr = DxcNew(size);
3131
if (ptr == nullptr)
3232
throw std::bad_alloc();
3333
return ptr;
3434
}
3535
void * __CRTDECL operator new(std::size_t size,
3636
const std::nothrow_t &nothrow_value) throw() {
37-
return DxcGetThreadMallocNoRef()->Alloc(size);
37+
return DxcNew(size);
3838
}
3939
void __CRTDECL operator delete (void* ptr) throw() {
40-
DxcGetThreadMallocNoRef()->Free(ptr);
40+
DxcDelete(ptr);
4141
}
4242
void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() {
43-
DxcGetThreadMallocNoRef()->Free(ptr);
43+
DxcDelete(ptr);
4444
}
4545
#endif
4646

0 commit comments

Comments
 (0)