Skip to content

Commit

Permalink
Allow new/delete operators to be called before DllMain (#5454)
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
hekota authored Jul 28, 2023
1 parent 634c2f3 commit 0033aa8
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 14 deletions.
4 changes: 4 additions & 0 deletions include/dxc/Support/Global.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ void DxcClearThreadMalloc() throw();
// Used to retrieve the current invocation's allocator or perform an alloc/free/realloc.
IMalloc *DxcGetThreadMallocNoRef() throw();

// Common implementation of operators new and delete
void *DxcNew(std::size_t size) throw();
void DxcDelete(void* ptr) throw();

class DxcThreadMalloc {
public:
explicit DxcThreadMalloc(IMalloc *pMallocOrNull) throw();
Expand Down
28 changes: 28 additions & 0 deletions lib/DxcSupport/dxcmem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,31 @@ DxcThreadMalloc::DxcThreadMalloc(IMalloc *pMallocOrNull) throw() {
DxcThreadMalloc::~DxcThreadMalloc() {
DxcSwapThreadMalloc(pPrior, nullptr);
}

void* DxcNew(std::size_t size) throw() {
void *ptr;
IMalloc* iMalloc = DxcGetThreadMallocNoRef();
if (iMalloc != nullptr) {
ptr = iMalloc->Alloc(size);
} else {
// DxcGetThreadMallocNoRef() returning null means the operator is called before DllMain
// where the g_pDefaultMalloc is initialized, for example from CRT libraries when
// static linking is enabled. In that case fallback to the standard allocator
// and use CoTaskMemAlloc directly instead of CoGetMalloc, Alloc & Release for better perf.
ptr = CoTaskMemAlloc(size);
}
return ptr;
}

void DxcDelete(void *ptr) throw() {
IMalloc* iMalloc = DxcGetThreadMallocNoRef();
if (iMalloc != nullptr) {
iMalloc->Free(ptr);
} else {
// DxcGetThreadMallocNoRef() returning null means the operator is called before DllMain
// where the g_pDefaultMalloc is initialized, for example from CRT libraries when
// static linking is enabled. In that case fallback to the standard allocator
// and use CoTaskMemFree directly instead of CoGetMalloc, Free & Release for better perf.
CoTaskMemFree(ptr);
}
}
13 changes: 8 additions & 5 deletions tools/clang/tools/dxcompiler/DXCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,24 @@ HRESULT SetupRegistryPassForPIX();

#if defined(LLVM_ON_WIN32) && !defined(DXC_DISABLE_ALLOCATOR_OVERRIDES)
// operator new and friends.
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
void * ptr = DxcGetThreadMallocNoRef()->Alloc(size);
void* __CRTDECL operator new(std::size_t size) noexcept(false) {
void *ptr = DxcNew(size);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}

void * __CRTDECL operator new(std::size_t size,
const std::nothrow_t &nothrow_value) throw() {
return DxcGetThreadMallocNoRef()->Alloc(size);
return DxcNew(size);
}

void __CRTDECL operator delete (void* ptr) throw() {
DxcGetThreadMallocNoRef()->Free(ptr);
DxcDelete(ptr);
}

void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() {
DxcGetThreadMallocNoRef()->Free(ptr);
DxcDelete(ptr);
}
#endif

Expand Down
8 changes: 4 additions & 4 deletions tools/clang/tools/dxlib-sample/dxlib_sample.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ using namespace hlsl;

// operator new and friends.
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
void * ptr = DxcGetThreadMallocNoRef()->Alloc(size);
void *ptr = DxcNew(size);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
void * __CRTDECL operator new(std::size_t size,
const std::nothrow_t &nothrow_value) throw() {
return DxcGetThreadMallocNoRef()->Alloc(size);
return DxcNew(size);
}
void __CRTDECL operator delete (void* ptr) throw() {
DxcGetThreadMallocNoRef()->Free(ptr);
DxcDelete(ptr);
}
void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() {
DxcGetThreadMallocNoRef()->Free(ptr);
DxcDelete(ptr);
}
// Finish of new delete.

Expand Down
10 changes: 5 additions & 5 deletions tools/clang/tools/dxrfallbackcompiler/DXCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ namespace hlsl { HRESULT SetupRegistryPassForHLSL(); }

#if !defined(DXC_DISABLE_ALLOCATOR_OVERRIDES)
// operator new and friends.
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
void * ptr = DxcGetThreadMallocNoRef()->Alloc(size);
void * __CRTDECL operator new(std::size_t size) noexcept(false) {
void *ptr = DxcNew(size);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
void * __CRTDECL operator new(std::size_t size,
const std::nothrow_t &nothrow_value) throw() {
return DxcGetThreadMallocNoRef()->Alloc(size);
return DxcNew(size);
}
void __CRTDECL operator delete (void* ptr) throw() {
DxcGetThreadMallocNoRef()->Free(ptr);
DxcDelete(ptr);
}
void __CRTDECL operator delete (void* ptr, const std::nothrow_t& nothrow_constant) throw() {
DxcGetThreadMallocNoRef()->Free(ptr);
DxcDelete(ptr);
}
#endif

Expand Down

0 comments on commit 0033aa8

Please sign in to comment.