Skip to content

Create new class to handle external validation, and rename existing dll loading class. #7514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 56 commits into from
Aug 18, 2025
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
d7d1936
implement stage 2
bob80905 Jun 6, 2025
c527502
add crucial headers
bob80905 Jun 6, 2025
7f7dc30
chore: autopublish 2025-06-06T00:27:21Z
github-actions[bot] Jun 6, 2025
e7ec854
address Tex non-header changes
bob80905 Jun 6, 2025
39f913c
handle includes
bob80905 Jun 6, 2025
3700bfd
swap include order
bob80905 Jun 6, 2025
33c88f9
address Tex, and make a flawed attempt at writing a unit test
bob80905 Jun 18, 2025
544a9c7
chore: autopublish 2025-06-18T04:25:45Z
github-actions[bot] Jun 18, 2025
eeb1516
validated that local test passes
bob80905 Jun 18, 2025
9800c91
address tex, update unit test
bob80905 Jun 25, 2025
a4c9629
ifdef for windows vs unix env var addition
bob80905 Jun 25, 2025
a9282fd
add wstring conversion stuff and env var resets
bob80905 Jun 25, 2025
e781627
address tex
bob80905 Jun 25, 2025
2915a8d
special casing for unix systems
bob80905 Jun 25, 2025
57dd853
address tex, make wstrings more universal too
bob80905 Jun 30, 2025
98b25af
add includes for _wgetenv
bob80905 Jun 30, 2025
c274e5b
remove wstring for simplicity
bob80905 Jun 30, 2025
b46def4
fix undeclared variables in non windows case, and pointer lifetime bug
bob80905 Jun 30, 2025
b76fab2
adjust for build errors
bob80905 Jul 1, 2025
89dcc4a
address final forgotten comments
bob80905 Jul 1, 2025
acbf68a
try removing unicode from cmakelists
bob80905 Jul 2, 2025
f2890f5
update comment Justin pointed out was outdated
bob80905 Jul 3, 2025
eb1e96f
remove Linux definitions from windows only testing, address ambiguity…
bob80905 Jul 7, 2025
36c33a2
do not inherit from DxcDllSupport
bob80905 Jul 7, 2025
6577046
add win32 preprocessor gate to allow non windows envs to build
bob80905 Jul 7, 2025
80b50a6
remove test from non-windows since it depends on wide strings
bob80905 Jul 7, 2025
bfc508f
remove friend, remove protected:
bob80905 Jul 8, 2025
a144ca1
address Damyan final concerns
bob80905 Jul 11, 2025
bd01fa5
try another way to emit an hresult
bob80905 Jul 12, 2025
647c946
try E_INVALIDARG
bob80905 Jul 14, 2025
a29f6ee
use an interface
bob80905 Jul 18, 2025
fffb407
fix nix error
bob80905 Jul 18, 2025
5411894
remove comment on header that is likely to become stale
bob80905 Jul 24, 2025
45f74fa
perform rename
bob80905 Jul 28, 2025
64f61a8
resolve merge conflicts
bob80905 Jul 28, 2025
ed23ada
update old class name
bob80905 Jul 28, 2025
2383541
rename to IDllLoader, rename to OverrideDll, remove defaulted functio…
bob80905 Aug 6, 2025
209582f
address all of Justin + Damyan 2c
bob80905 Aug 7, 2025
daf6f0a
add override
bob80905 Aug 7, 2025
c8d867e
add more overrides
bob80905 Aug 7, 2025
0aa3c8d
add virtual to destructor for HlslIntellisense
bob80905 Aug 7, 2025
15fceac
address Damyan: specify constructors in interface, remove cleanup fro…
bob80905 Aug 7, 2025
09be489
address Damyan
bob80905 Aug 8, 2025
be99192
Merge branch 'main' into create_DxcDllExtValidationSupport
bob80905 Aug 8, 2025
cba829b
we keep trying, this should be it
bob80905 Aug 8, 2025
17f26c6
clang format
bob80905 Aug 8, 2025
c0ee094
remove move ctor and copy ctor
bob80905 Aug 8, 2025
cdf321e
address all but justins last comment
bob80905 Aug 11, 2025
c8b704a
do a function rename
bob80905 Aug 11, 2025
965f78c
try undoing spirv change
bob80905 Aug 12, 2025
48fb6fa
remove unneeded forward decl
bob80905 Aug 12, 2025
b100acd
add DxCompilerDllLoader class, and use it
bob80905 Aug 13, 2025
f66408c
address Justin
bob80905 Aug 13, 2025
c8bebee
fix build err
bob80905 Aug 13, 2025
4633dcc
remove specificdllloader from ensureenabled, use new LibraryDllLoader…
bob80905 Aug 14, 2025
005ea83
rename to DXCLibraryDllSupport, address Justin
bob80905 Aug 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions include/dxc/Support/dxcapi.extval.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "dxc/Support/dxcapi.use.h"
#include <string>

namespace dxc {
class DxcDllExtValidationSupport : public IDllSupport {
// DxCompilerSupport manages the
// lifetime of dxcompiler.dll, while DxilExtValSupport
// manages the lifetime of dxil.dll
dxc::DxcDllSupport DxCompilerSupport;
dxc::DxcDllSupport DxilExtValSupport;

DxcCreateInstanceProc m_createFn;
DxcCreateInstance2Proc m_createFn2;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are never initialized to anything. Should they really be here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I don't think so. I imagine the relevant creation functions will only be stored in the specificdllloader member objects.


std::string DxilDllPath;
HRESULT InitializeInternal(LPCSTR fnName);

public:
std::string GetDxilDllPath() { return DxilDllPath; }
bool DxilDllFailedToLoad() {
return !DxilDllPath.empty() && !DxilExtValSupport.IsEnabled();
}

HRESULT CreateInstance(REFCLSID clsid, REFIID riid, IUnknown **pResult);
HRESULT CreateInstance2(IMalloc *pMalloc, REFCLSID clsid, REFIID riid,
IUnknown **pResult);

HRESULT Initialize() { return InitializeInternal("DxcCreateInstance"); }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does InitializeInternal take a fnName argument if it's only ever called with a fixed string? Do we need InitializeInternal at all, or should we just update the implementation to be an implementation of Initialize()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, looks like we dont need it at all. I'll remove InitializeInternal and move its implementation to Initialize().

HRESULT InitializeForDll(LPCSTR dll, LPCSTR entryPoint) {
return InitializeInternal(dll);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't look right. InitializeInternal takes a fnName argument, not a dll name. If the InitializeForDll interface makes sense at all here, then I think you need to pass both of these parameters in.

I mention elsewhere in the review that I think a better name for this interface would be "overrideDll" or something to that effect. The users of this API are saying "use this other Dll I specified on the command line" or something to that effect. I guess we should pass on both parameters here when we call DxCompilerSupport's initializeForDll, and we should maybe forward the entryPointon to our call toDxilExtValSupport's initializeForDll` - though that will only really work if the dll we find in the environment is compatible with the one we're overriding with.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the right fix here is simply to change what's passed from dll to entryPoint, like you said. But, I don't think we should pass both args to InitializeInternal.
DxcDllExtValidationLoader is a specific instance of the IDllLoader interface that shouldn't accept arbitrary dlls AFAIK. We hard-code the two dlls that it cares about, and we should ignore any other dlls passed as a param to InitializeForDll.
I think we make an implementation of InitializeForDll just to satisfy the interface, but under the hood it ignores whatever's passed and uses the two dll's that it's specifically designed for.
Note the name of the class, it isn't called TwoSpecificDllLoaders, it's called DxcDllExtValidationLoader, so we already know which two dll's we should care about. I can add a comment to the function warning devs that the parameter is ignored, and the two dlls that are loaded are hard-coded.

TLDR: I'll replace dll with entry point, that is correct. But InitialzieInternal shouldn't care about user dlls, the dlls that are loaded should be hard-coded into the internal function itself.


bool HasCreateWithMalloc() const { return m_createFn2 != nullptr; }

bool IsEnabled() const { return DxCompilerSupport.IsEnabled(); }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to check both dlls here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. It is legal for this object to be initialized with no env var, and thus no dxil.dll loaded. So the 2nd dll won't be enabled.


bool GetCreateInstanceProcs(DxcCreateInstanceProc *pCreateFn,
DxcCreateInstance2Proc *pCreateFn2) const;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for? Is it used for anything?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was originally intended just to be defined for the SpecificDllLoader so that the DxcDllExtValidationLoader can access the creation functions. So I'll remove it from DxcDllExtValidationLoader and the interface.


void Cleanup() {
DxilExtValSupport.Cleanup();
DxCompilerSupport.Cleanup();
}

HMODULE Detach() {
// Can't Detach and return a handle for DxilSupport. Cleanup() instead.
DxilExtValSupport.Cleanup();
return DxCompilerSupport.Detach();
}
};
} // namespace dxc
74 changes: 60 additions & 14 deletions include/dxc/Support/dxcapi.use.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,52 @@ namespace dxc {
extern const char *kDxCompilerLib;
extern const char *kDxilLib;

// Interface for common dll operations
class IDllSupport {
public:
IDllSupport() = default;

IDllSupport(IDllSupport &&other) = default;

virtual ~IDllSupport() = default;

virtual HRESULT Initialize() = 0;

virtual HRESULT InitializeForDll(LPCSTR dll, LPCSTR entryPoint) = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could remove Initialize() from the interface here and force the creator of the object to initialize it themselves. There are a couple of places that might be a bit awkward to update to do that, but I think it'd be cleaner if users of this class couldn't just arbitrarily reinitialize it in a way that could very much be confusing.

InitializeForDll would be harder to get rid of, but if we were to rename it to overrideDll or something like that I think it would make it clearer that it's there as an explicit hook to override which Dll you're using.


template <typename TInterface>
HRESULT CreateInstance(REFCLSID clsid, TInterface **pResult) {
return CreateInstance(clsid, __uuidof(TInterface), (IUnknown **)pResult);
}

virtual HRESULT CreateInstance(REFCLSID clsid, REFIID riid,
IUnknown **pResult) = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would simplify things to implement this whole overload set and then add a protected function for the implementation, ie:

protected:
  virtual HRESULT CreateInstanceImpl(REFCLSID clsid, REFIID riid,
                                     IUnknown **pResult) = 0;
public:
  template <typename TInterface>
  HRESULT CreateInstance(REFCLSID clsid, TInterface **pResult) {
    return CreateInstanceImpl(clsid, __uuidof(TInterface),
                              (IUnknown **)pResult);
  }
  HRESULT CreateInstance(REFCLSID clsid, REFIID riid,
                         IUnknown **pResult) {
    return CreateInstanceImpl(clsid, riid, (IUnknown **)pResult);
  }

This also applies to CreateInstance2


template <typename TInterface>
HRESULT CreateInstance2(IMalloc *pMalloc, REFCLSID clsid,
TInterface **pResult) {
return CreateInstance2(pMalloc, clsid, __uuidof(TInterface),
(IUnknown **)pResult);
}

virtual HRESULT CreateInstance2(IMalloc *pMalloc, REFCLSID clsid, REFIID riid,
IUnknown **pResult) = 0;

virtual bool HasCreateWithMalloc() const = 0;

virtual bool IsEnabled() const = 0;

virtual bool
GetCreateInstanceProcs(DxcCreateInstanceProc *pCreateFn,
DxcCreateInstance2Proc *pCreateFn2) const = 0;

virtual void Cleanup() = 0;
virtual HMODULE Detach() = 0;
};

// Helper class to dynamically load the dxcompiler or a compatible libraries.
class DxcDllSupport {
protected:
class DxcDllSupport : public IDllSupport {

HMODULE m_dll;
DxcCreateInstanceProc m_createFn;
DxcCreateInstance2Proc m_createFn2;
Expand Down Expand Up @@ -95,11 +138,9 @@ class DxcDllSupport {
return InitializeInternal(dll, entryPoint);
}

template <typename TInterface>
HRESULT CreateInstance(REFCLSID clsid, TInterface **pResult) {
return CreateInstance(clsid, __uuidof(TInterface), (IUnknown **)pResult);
}

// Also bring visibility into the interface definition of this function
// which takes 2 args
using IDllSupport::CreateInstance;
HRESULT CreateInstance(REFCLSID clsid, REFIID riid, IUnknown **pResult) {
if (pResult == nullptr)
return E_POINTER;
Expand All @@ -109,13 +150,9 @@ class DxcDllSupport {
return hr;
}

template <typename TInterface>
HRESULT CreateInstance2(IMalloc *pMalloc, REFCLSID clsid,
TInterface **pResult) {
return CreateInstance2(pMalloc, clsid, __uuidof(TInterface),
(IUnknown **)pResult);
}

// Also bring visibility into the interface definition of this function
// which takes 3 args
using IDllSupport::CreateInstance2;
HRESULT CreateInstance2(IMalloc *pMalloc, REFCLSID clsid, REFIID riid,
IUnknown **pResult) {
if (pResult == nullptr)
Expand All @@ -132,6 +169,15 @@ class DxcDllSupport {

bool IsEnabled() const { return m_dll != nullptr; }

bool GetCreateInstanceProcs(DxcCreateInstanceProc *pCreateFn,
DxcCreateInstance2Proc *pCreateFn2) const {
if (pCreateFn == nullptr || pCreateFn2 == nullptr || m_createFn == nullptr)
return false;
*pCreateFn = m_createFn;
*pCreateFn2 = m_createFn2;
return true;
}

void Cleanup() {
if (m_dll != nullptr) {
m_createFn = nullptr;
Expand Down
1 change: 1 addition & 0 deletions lib/DxcSupport/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_llvm_library(LLVMDxcSupport
WinAdapter.cpp
WinIncludes.cpp
WinFunctions.cpp
dxcapi.extval.cpp
)

#generate header with platform-specific library name
Expand Down
61 changes: 61 additions & 0 deletions lib/DxcSupport/dxcapi.extval.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include "dxc/Support/WinIncludes.h"
#include <dxc/Support/Global.h> // for hresult handling with DXC_FAILED
#include <filesystem> // C++17 and later
// WinIncludes must come before dxcapi.extval.h
#include "dxc/Support/dxcapi.extval.h"

namespace dxc {

HRESULT DxcDllExtValidationSupport::CreateInstance(REFCLSID clsid, REFIID riid,
IUnknown **pResult) {
if (DxilExtValSupport.IsEnabled() && clsid == CLSID_DxcValidator)
return DxilExtValSupport.CreateInstance(clsid, riid, pResult);

return DxCompilerSupport.CreateInstance(clsid, riid, pResult);
}

HRESULT DxcDllExtValidationSupport::CreateInstance2(IMalloc *pMalloc,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can we just drop the 2 here and rely on overloading? The param list is different so I think the compiler would be happy

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should keep the 2, since the 2 is in reference to the 2nd creation function, which is stored as a member variable in dxcapi.use.h: m_createFn2.
This different name helps clarify that it depends on the different function represented by that other member variable.

REFCLSID clsid, REFIID riid,
IUnknown **pResult) {
if (DxilExtValSupport.IsEnabled() && clsid == CLSID_DxcValidator)
return DxilExtValSupport.CreateInstance2(pMalloc, clsid, riid, pResult);

return DxCompilerSupport.CreateInstance2(pMalloc, clsid, riid, pResult);
}

HRESULT DxcDllExtValidationSupport::InitializeInternal(LPCSTR fnName) {
// Load dxcompiler.dll
HRESULT Result = DxCompilerSupport.InitializeForDll(kDxCompilerLib, fnName);
// if dxcompiler.dll fails to load, return the failed HRESULT
if (DXC_FAILED(Result)) {
return Result;
}

// now handle external dxil.dll
const char *EnvVarVal = std::getenv("DXC_DXIL_DLL_PATH");
if (!EnvVarVal || std::string(EnvVarVal).empty()) {
return S_OK;
}

DxilDllPath = std::string(EnvVarVal);
std::filesystem::path DllPath(DxilDllPath);

// Check if path is absolute and exists
if (!DllPath.is_absolute() || !std::filesystem::exists(DllPath)) {
return E_INVALIDARG;
}

return DxilExtValSupport.InitializeForDll(DxilDllPath.c_str(), fnName);
}

bool DxcDllExtValidationSupport::GetCreateInstanceProcs(
DxcCreateInstanceProc *pCreateFn,
DxcCreateInstance2Proc *pCreateFn2) const {
if (pCreateFn == nullptr || pCreateFn2 == nullptr || m_createFn == nullptr)
return false;
*pCreateFn = m_createFn;
*pCreateFn2 = m_createFn2;
return true;
}

} // namespace dxc
95 changes: 95 additions & 0 deletions tools/clang/unittests/HLSL/ValidationTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
#include "dxc/DxilContainer/DxilContainerAssembler.h"
#include "dxc/DxilContainer/DxilPipelineStateValidation.h"
#include "dxc/DxilHash/DxilHash.h"
#include "dxc/Support/Unicode.h" // for wstring conversions like WideToUtf8String
#include "dxc/Support/WinIncludes.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Regex.h"
#include <wchar.h> // for _wgetenv

#ifdef _WIN32
#include <atlbase.h>
Expand All @@ -32,6 +34,7 @@
#include "dxc/Support/Global.h"

#include "dxc/DXIL/DxilShaderModel.h"
#include "dxc/Support/dxcapi.extval.h"
#include "dxc/Test/DxcTestUtils.h"
#include "dxc/Test/HlslTestUtils.h"

Expand Down Expand Up @@ -323,6 +326,7 @@ class ValidationTest : public ::testing::Test {
TEST_METHOD(PSVContentValidationCS)
TEST_METHOD(PSVContentValidationMS)
TEST_METHOD(PSVContentValidationAS)
TEST_METHOD(UnitTestExtValidationSupport)
TEST_METHOD(WrongPSVSize)
TEST_METHOD(WrongPSVSizeOnZeros)
TEST_METHOD(WrongPSVVersion)
Expand Down Expand Up @@ -4207,6 +4211,97 @@ TEST_F(ValidationTest, ValidateWithHash) {
VERIFY_ARE_EQUAL(memcmp(Result, pHeader->Hash.Digest, sizeof(Result)), 0);
}

#ifdef _WIN32
std::wstring GetEnvVarW(const std::wstring &VarName) {
if (const wchar_t *Result = _wgetenv(VarName.c_str()))
return std::wstring(Result);
return std::wstring();
}

void SetEnvVarW(const std::wstring &VarName, const std::wstring &VarValue) {
_wputenv_s(VarName.c_str(), VarValue.c_str());
}

// For now, 3 things are tested:
// 1. The environment variable is not set. GetDxilDllPath() is empty and
// DxilDllFailedToLoad() returns false
// 2. Given a bogus path in the environment variable, and an initialized
// DxcDllExtValidationSupport object, GetDxilDllPath()
// retrieves the bogus path despite DxcDllExtValidationSupport failing to load
// it as a dll, and DxilDllFailedToLoad() returns true.
// 3. CLSID_DxcCompiler, CLSID_DxcLinker, CLSID_DxcValidator
// may be created through DxcDllExtValidationSupport.
// This is all to simply test that the new class, DxcDllExtValidationSupport,
// works as intended.

TEST_F(ValidationTest, UnitTestExtValidationSupport) {
dxc::DxcDllExtValidationSupport ExtSupportEmpty;
dxc::DxcDllExtValidationSupport ExtSupportBogus;

// capture any existing value in the environment variable,
// so that it can be restored after the test
std::wstring OldEnvVal = GetEnvVarW(L"DXC_DXIL_DLL_PATH");

// 1. with no env var set, test GetDxilDllPath() and DxilDllFailedToLoad()

// make sure the variable is cleared, in case other tests may have set it
SetEnvVarW(L"DXC_DXIL_DLL_PATH", L"");

// empty initialization should succeed
VERIFY_SUCCEEDED(ExtSupportEmpty.Initialize());

VERIFY_IS_FALSE(ExtSupportEmpty.DxilDllFailedToLoad());
std::string EmptyPath = ExtSupportBogus.GetDxilDllPath();
VERIFY_ARE_EQUAL_STR(EmptyPath.c_str(), "");

// 2. Test with a bogus path in the environment variable
SetEnvVarW(L"DXC_DXIL_DLL_PATH", L"bogus");

if (!ExtSupportBogus.IsEnabled()) {
VERIFY_FAILED(ExtSupportBogus.Initialize());
}

// validate that m_dllExtSupport2 was able to capture the environment
// variable's value, and that loading the bogus path was unsuccessful
std::string BogusPath = ExtSupportBogus.GetDxilDllPath();
VERIFY_ARE_EQUAL_STR(BogusPath.c_str(), "bogus");
VERIFY_IS_TRUE(ExtSupportBogus.DxilDllFailedToLoad());

// 3. Test production of class IDs CLSID_DxcCompiler, CLSID_DxcLinker,
// and CLSID_DxcValidator through DxcDllExtValidationSupport.
CComPtr<IDxcCompiler> Compiler;
CComPtr<IDxcLinker> Linker;
CComPtr<IDxcValidator> Validator;

VERIFY_SUCCEEDED(ExtSupportBogus.CreateInstance(
CLSID_DxcCompiler, __uuidof(IDxcCompiler), (IUnknown **)&Compiler));
VERIFY_SUCCEEDED(ExtSupportBogus.CreateInstance(
CLSID_DxcLinker, __uuidof(IDxcLinker), (IUnknown **)&Linker));
VERIFY_SUCCEEDED(ExtSupportBogus.CreateInstance(
CLSID_DxcValidator, __uuidof(IDxcValidator), (IUnknown **)&Validator));

Linker.Release();
Validator.Release();
Compiler.Release();

CComPtr<IMalloc> Malloc;
CComPtr<IDxcCompiler2> Compiler2;
VERIFY_SUCCEEDED(DxcCoGetMalloc(1, &Malloc));
VERIFY_SUCCEEDED(ExtSupportBogus.CreateInstance2(Malloc, CLSID_DxcCompiler,
__uuidof(IDxcCompiler),
(IUnknown **)&Compiler2));
VERIFY_SUCCEEDED(ExtSupportBogus.CreateInstance2(
Malloc, CLSID_DxcLinker, __uuidof(IDxcLinker), (IUnknown **)&Linker));
VERIFY_SUCCEEDED(ExtSupportBogus.CreateInstance2(Malloc, CLSID_DxcValidator,
__uuidof(IDxcValidator),
(IUnknown **)&Validator));

// reset the environment variable to its previous value,
// or the empty string if there was no previous value
SetEnvVarW(L"DXC_DXIL_DLL_PATH", OldEnvVal);
}
#endif

TEST_F(ValidationTest, ValidatePreviewBypassHash) {
if (m_ver.SkipDxilVersion(1, ShaderModel::kHighestMinor))
return;
Expand Down