Skip to content

Commit 8e70fa2

Browse files
authored
Fixed QueryInterface for ID3D12ShaderReflection interface (microsoft#5445)
QueryInterface would accept any interface IID, instead of only the ones it recognizes. Fixed by adding PublicAPI::Invalid, returned from IIDToAPI when not one of the recognized APIs, and only accepting IUnknown or the original interface IID provided at create time. CreateDxil{Shader|Library}Reflection would also completely ignore IID. Fixed by only accepting supported IIDs. Get*ParameterDesc for signature elements also incorrectly computed structure size (due to alignment) to memcpy for D3D11_43 version. Fixed by copying only up to the end of the last field in the old structure version. CreateReflectionObjectsForSignature had a special case avoiding filling in the MinPrecision member for D3D11_43, though this is unnecessary, since for that API version, the struct will be truncated to exclude the MinPrecision member when copying out the desc. Removed unnecessary special case. Added DxilContainerTest::CheckReflectionQueryInterface test for Create and QI scenarios for supported and unsupported IIDs. This also tests that the Get*ParameterDesc methods don't write beyond the structure size for the interface version. Fixes microsoft#3887
1 parent e4b9b88 commit 8e70fa2

File tree

2 files changed

+335
-21
lines changed

2 files changed

+335
-21
lines changed

lib/HLSL/DxilContainerReflection.cpp

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class DxilContainerReflection : public IDxcContainerReflection {
9999
class CShaderReflectionConstantBuffer;
100100
class CShaderReflectionType;
101101

102-
enum class PublicAPI { D3D12 = 0, D3D11_47 = 1, D3D11_43 = 2 };
102+
enum class PublicAPI { D3D12 = 0, D3D11_47 = 1, D3D11_43 = 2, Invalid };
103103

104104
#ifdef ADD_16_64_BIT_TYPES
105105
// Disable warning about value not being valid in enum
@@ -182,8 +182,10 @@ class DxilShaderReflection : public DxilModuleReflection,
182182
PublicAPI m_PublicAPI;
183183
void SetPublicAPI(PublicAPI value) { m_PublicAPI = value; }
184184
static PublicAPI IIDToAPI(REFIID iid) {
185-
PublicAPI api = PublicAPI::D3D12;
186-
if (IsEqualIID(IID_ID3D11ShaderReflection_43, iid))
185+
PublicAPI api = PublicAPI::Invalid;
186+
if (IsEqualIID(__uuidof(ID3D12ShaderReflection), iid))
187+
api = PublicAPI::D3D12;
188+
else if (IsEqualIID(IID_ID3D11ShaderReflection_43, iid))
187189
api = PublicAPI::D3D11_43;
188190
else if (IsEqualIID(IID_ID3D11ShaderReflection_47, iid))
189191
api = PublicAPI::D3D11_47;
@@ -193,17 +195,24 @@ class DxilShaderReflection : public DxilModuleReflection,
193195
DXC_MICROCOM_TM_CTOR(DxilShaderReflection)
194196
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,
195197
void **ppvObject) override {
196-
HRESULT hr =
197-
DoBasicQueryInterface<ID3D12ShaderReflection>(this, iid, ppvObject);
198-
if (hr == E_NOINTERFACE) {
199-
// ID3D11ShaderReflection is identical to ID3D12ShaderReflection, except
200-
// for some shorter data structures in some out parameters.
201-
PublicAPI api = IIDToAPI(iid);
202-
if (api == m_PublicAPI) {
203-
*ppvObject = (ID3D12ShaderReflection *)this;
204-
this->AddRef();
205-
hr = S_OK;
206-
}
198+
HRESULT hr = E_NOINTERFACE;
199+
200+
// There is non-standard handling of QueryInterface:
201+
// - although everything uses the same vtable as ID3D12ShaderReflection,
202+
// there are differences in behavior depending on the API version, and
203+
// there are 3 of these - it's not just d3d11 vs d3d12.
204+
// - when the object is created the API version is fixed
205+
// - from that point on, this object can only be QI'd for the matching API
206+
// version.
207+
PublicAPI api = IIDToAPI(iid);
208+
if (api == m_PublicAPI) {
209+
*ppvObject = static_cast<ID3D12ShaderReflection *>(this);
210+
this->AddRef();
211+
hr = S_OK;
212+
} else if (IsEqualIID(__uuidof(IUnknown), iid)) {
213+
*ppvObject = static_cast<IUnknown *>(this);
214+
this->AddRef();
215+
hr = S_OK;
207216
}
208217
return hr;
209218
}
@@ -299,10 +308,16 @@ HRESULT CreateDxilShaderReflection(const DxilProgramHeader *pProgramHeader,
299308
void **ppvObject) {
300309
if (!ppvObject)
301310
return E_INVALIDARG;
311+
PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
312+
if (api == PublicAPI::Invalid) {
313+
if (IsEqualIID(__uuidof(IUnknown), iid))
314+
api = PublicAPI::D3D12;
315+
else
316+
return E_NOINTERFACE;
317+
}
302318
CComPtr<DxilShaderReflection> pReflection =
303319
DxilShaderReflection::Alloc(DxcGetThreadMallocNoRef());
304320
IFROOM(pReflection.p);
305-
PublicAPI api = DxilShaderReflection::IIDToAPI(iid);
306321
pReflection->SetPublicAPI(api);
307322
// pRDATPart to be used for transition.
308323
IFR(pReflection->Load(pProgramHeader, pRDATPart));
@@ -315,6 +330,9 @@ HRESULT CreateDxilLibraryReflection(const DxilProgramHeader *pProgramHeader,
315330
void **ppvObject) {
316331
if (!ppvObject)
317332
return E_INVALIDARG;
333+
if (!IsEqualIID(__uuidof(ID3D12LibraryReflection), iid) &&
334+
!IsEqualIID(__uuidof(IUnknown), iid))
335+
return E_NOINTERFACE;
318336
CComPtr<DxilLibraryReflection> pReflection =
319337
DxilLibraryReflection::Alloc(DxcGetThreadMallocNoRef());
320338
IFROOM(pReflection.p);
@@ -2160,9 +2178,7 @@ void DxilShaderReflection::CreateReflectionObjectsForSignature(
21602178
Desc.ComponentType =
21612179
CompTypeToRegisterComponentType(SigElem->GetCompType());
21622180
Desc.Mask = SigElem->GetColsAsMask();
2163-
// D3D11_43 does not have MinPrecison.
2164-
if (m_PublicAPI != PublicAPI::D3D11_43)
2165-
Desc.MinPrecision = CompTypeToMinPrecision(SigElem->GetCompType());
2181+
Desc.MinPrecision = CompTypeToMinPrecision(SigElem->GetCompType());
21662182
if (m_bUsageInMetadata) {
21672183
unsigned UsageMask = SigElem->GetUsageMask();
21682184
if (SigElem->IsAllocated())
@@ -2585,7 +2601,8 @@ HRESULT DxilShaderReflection::GetInputParameterDesc(
25852601
else
25862602
memcpy(pDesc, &m_InputSignature[ParameterIndex],
25872603
// D3D11_43 does not have MinPrecison.
2588-
sizeof(D3D12_SIGNATURE_PARAMETER_DESC) - sizeof(D3D_MIN_PRECISION));
2604+
offsetof(D3D12_SIGNATURE_PARAMETER_DESC, Stream) +
2605+
sizeof(D3D12_SIGNATURE_PARAMETER_DESC::Stream));
25892606

25902607
return S_OK;
25912608
}
@@ -2599,7 +2616,8 @@ HRESULT DxilShaderReflection::GetOutputParameterDesc(
25992616
else
26002617
memcpy(pDesc, &m_OutputSignature[ParameterIndex],
26012618
// D3D11_43 does not have MinPrecison.
2602-
sizeof(D3D12_SIGNATURE_PARAMETER_DESC) - sizeof(D3D_MIN_PRECISION));
2619+
offsetof(D3D12_SIGNATURE_PARAMETER_DESC, Stream) +
2620+
sizeof(D3D12_SIGNATURE_PARAMETER_DESC::Stream));
26032621

26042622
return S_OK;
26052623
}
@@ -2613,7 +2631,8 @@ HRESULT DxilShaderReflection::GetPatchConstantParameterDesc(
26132631
else
26142632
memcpy(pDesc, &m_PatchConstantSignature[ParameterIndex],
26152633
// D3D11_43 does not have MinPrecison.
2616-
sizeof(D3D12_SIGNATURE_PARAMETER_DESC) - sizeof(D3D_MIN_PRECISION));
2634+
offsetof(D3D12_SIGNATURE_PARAMETER_DESC, Stream) +
2635+
sizeof(D3D12_SIGNATURE_PARAMETER_DESC::Stream));
26172636

26182637
return S_OK;
26192638
}

0 commit comments

Comments
 (0)