dawn_wire: Gracefully handle all invalid and unknown sTypes
This CL makes the wire gracefully handle all invalid and unknown sTypes. All unknown sType structs are serialized and deserialized as the base WGPUChainedStruct with sType Invalid. Bug: dawn:369, dawn:654 Change-Id: Ia2571df81fc96e2c672d3ea13c03237a2d5fa5c1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/39460 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
07987ede36
commit
65a903bf75
|
@ -15,6 +15,7 @@
|
||||||
#include "dawn_wire/WireCmd_autogen.h"
|
#include "dawn_wire/WireCmd_autogen.h"
|
||||||
|
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
|
#include "common/Log.h"
|
||||||
#include "dawn_wire/Wire.h"
|
#include "dawn_wire/Wire.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -529,11 +530,9 @@ namespace dawn_wire {
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
default:
|
default:
|
||||||
// Invalid enum. Reserve space just for the transfer header (sType and hasNext).
|
// Invalid enum. Reserve space just for the transfer header (sType and hasNext).
|
||||||
// Stop iterating because this is an error.
|
|
||||||
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
|
|
||||||
ASSERT(chainedStruct->sType == WGPUSType_Invalid);
|
|
||||||
result += sizeof(WGPUChainedStructTransfer);
|
result += sizeof(WGPUChainedStructTransfer);
|
||||||
return result;
|
chainedStruct = chainedStruct->next;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -567,13 +566,19 @@ namespace dawn_wire {
|
||||||
default: {
|
default: {
|
||||||
// Invalid enum. Serialize just the transfer header with Invalid as the sType.
|
// Invalid enum. Serialize just the transfer header with Invalid as the sType.
|
||||||
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
|
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
|
||||||
ASSERT(chainedStruct->sType == WGPUSType_Invalid);
|
if (chainedStruct->sType != WGPUSType_Invalid) {
|
||||||
|
dawn::WarningLog() << "Unknown sType " << chainedStruct->sType << " discarded.";
|
||||||
|
}
|
||||||
|
|
||||||
WGPUChainedStructTransfer* transfer = reinterpret_cast<WGPUChainedStructTransfer*>(*buffer);
|
WGPUChainedStructTransfer* transfer = reinterpret_cast<WGPUChainedStructTransfer*>(*buffer);
|
||||||
transfer->sType = WGPUSType_Invalid;
|
transfer->sType = WGPUSType_Invalid;
|
||||||
transfer->hasNext = false;
|
transfer->hasNext = chainedStruct->next != nullptr;
|
||||||
|
|
||||||
*buffer += sizeof(WGPUChainedStructTransfer);
|
*buffer += sizeof(WGPUChainedStructTransfer);
|
||||||
return;
|
|
||||||
|
// Still move on in case there are valid structs after this.
|
||||||
|
chainedStruct = chainedStruct->next;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (chainedStruct != nullptr);
|
} while (chainedStruct != nullptr);
|
||||||
|
@ -615,8 +620,27 @@ namespace dawn_wire {
|
||||||
hasNext = transfer->chain.hasNext;
|
hasNext = transfer->chain.hasNext;
|
||||||
} break;
|
} break;
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
default:
|
default: {
|
||||||
return DeserializeResult::FatalError;
|
// Invalid enum. Deserialize just the transfer header with Invalid as the sType.
|
||||||
|
// TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
|
||||||
|
if (sType != WGPUSType_Invalid) {
|
||||||
|
dawn::WarningLog() << "Unknown sType " << sType << " discarded.";
|
||||||
|
}
|
||||||
|
|
||||||
|
const volatile WGPUChainedStructTransfer* transfer = nullptr;
|
||||||
|
DESERIALIZE_TRY(GetPtrFromBuffer(buffer, size, 1, &transfer));
|
||||||
|
|
||||||
|
WGPUChainedStruct* outStruct = nullptr;
|
||||||
|
DESERIALIZE_TRY(GetSpace(allocator, sizeof(WGPUChainedStruct), &outStruct));
|
||||||
|
outStruct->sType = WGPUSType_Invalid;
|
||||||
|
outStruct->next = nullptr;
|
||||||
|
|
||||||
|
// Still move on in case there are valid structs after this.
|
||||||
|
*outChainNext = outStruct;
|
||||||
|
outChainNext = &outStruct->next;
|
||||||
|
hasNext = transfer->hasNext;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} while (hasNext);
|
} while (hasNext);
|
||||||
|
|
||||||
|
|
|
@ -101,11 +101,10 @@ namespace dawn_wire { namespace client {
|
||||||
case WGPUSType_Invalid:
|
case WGPUSType_Invalid:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
|
||||||
dawn::WarningLog()
|
dawn::WarningLog()
|
||||||
<< "All objects may not be from the same client. "
|
<< "All objects may not be from the same client. "
|
||||||
<< "Unknown sType " << chainedStruct->sType << " discarded.";
|
<< "Unknown sType " << chainedStruct->sType << " ignored.";
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
chainedStruct = chainedStruct->next;
|
chainedStruct = chainedStruct->next;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,6 @@ class BindGroupValidationTest : public ValidationTest {
|
||||||
|
|
||||||
// Test the validation of BindGroupDescriptor::nextInChain
|
// Test the validation of BindGroupDescriptor::nextInChain
|
||||||
TEST_F(BindGroupValidationTest, NextInChainNullptr) {
|
TEST_F(BindGroupValidationTest, NextInChainNullptr) {
|
||||||
// TODO(crbug.com/dawn/654): Crashes with the wire. Diagnose and fix this.
|
|
||||||
DAWN_SKIP_TEST_IF(UsesWire());
|
|
||||||
|
|
||||||
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(device, {});
|
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(device, {});
|
||||||
|
|
||||||
wgpu::BindGroupDescriptor descriptor;
|
wgpu::BindGroupDescriptor descriptor;
|
||||||
|
@ -88,7 +85,7 @@ TEST_F(BindGroupValidationTest, NextInChainNullptr) {
|
||||||
|
|
||||||
// Check that nextInChain != nullptr is an error.
|
// Check that nextInChain != nullptr is an error.
|
||||||
wgpu::ChainedStruct chainedDescriptor;
|
wgpu::ChainedStruct chainedDescriptor;
|
||||||
chainedDescriptor.sType = wgpu::SType::ShaderModuleWGSLDescriptor;
|
chainedDescriptor.sType = wgpu::SType::Invalid;
|
||||||
descriptor.nextInChain = &chainedDescriptor;
|
descriptor.nextInChain = &chainedDescriptor;
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ TEST_F(WireExtensionTests, MutlipleChainedStructs) {
|
||||||
FlushClient();
|
FlushClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that a chained struct with Invalid sType is an error.
|
// Test that a chained struct with Invalid sType passes through as Invalid.
|
||||||
TEST_F(WireExtensionTests, InvalidSType) {
|
TEST_F(WireExtensionTests, InvalidSType) {
|
||||||
WGPUSamplerDescriptorDummyAnisotropicFiltering clientExt = {};
|
WGPUSamplerDescriptorDummyAnisotropicFiltering clientExt = {};
|
||||||
clientExt.chain.sType = WGPUSType_Invalid;
|
clientExt.chain.sType = WGPUSType_Invalid;
|
||||||
|
@ -132,7 +132,33 @@ TEST_F(WireExtensionTests, InvalidSType) {
|
||||||
clientDesc.label = "sampler with anisotropic filtering";
|
clientDesc.label = "sampler with anisotropic filtering";
|
||||||
|
|
||||||
wgpuDeviceCreateSampler(device, &clientDesc);
|
wgpuDeviceCreateSampler(device, &clientDesc);
|
||||||
FlushClient(false);
|
EXPECT_CALL(api, DeviceCreateSampler(apiDevice, NotNull()))
|
||||||
|
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* desc) -> WGPUSampler {
|
||||||
|
EXPECT_EQ(desc->nextInChain->sType, WGPUSType_Invalid);
|
||||||
|
EXPECT_EQ(desc->nextInChain->next, nullptr);
|
||||||
|
return api.GetNewSampler();
|
||||||
|
}));
|
||||||
|
FlushClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that a chained struct with unknown sType passes through as Invalid.
|
||||||
|
TEST_F(WireExtensionTests, UnknownSType) {
|
||||||
|
WGPUSamplerDescriptorDummyAnisotropicFiltering clientExt = {};
|
||||||
|
clientExt.chain.sType = static_cast<WGPUSType>(-1);
|
||||||
|
clientExt.chain.next = nullptr;
|
||||||
|
|
||||||
|
WGPUSamplerDescriptor clientDesc = {};
|
||||||
|
clientDesc.nextInChain = &clientExt.chain;
|
||||||
|
clientDesc.label = "sampler with anisotropic filtering";
|
||||||
|
|
||||||
|
wgpuDeviceCreateSampler(device, &clientDesc);
|
||||||
|
EXPECT_CALL(api, DeviceCreateSampler(apiDevice, NotNull()))
|
||||||
|
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* desc) -> WGPUSampler {
|
||||||
|
EXPECT_EQ(desc->nextInChain->sType, WGPUSType_Invalid);
|
||||||
|
EXPECT_EQ(desc->nextInChain->next, nullptr);
|
||||||
|
return api.GetNewSampler();
|
||||||
|
}));
|
||||||
|
FlushClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that if both an invalid and valid stype are passed on the chain, it is an error.
|
// Test that if both an invalid and valid stype are passed on the chain, it is an error.
|
||||||
|
@ -152,7 +178,21 @@ TEST_F(WireExtensionTests, ValidAndInvalidSTypeInChain) {
|
||||||
clientDesc.label = "sampler with anisotropic filtering";
|
clientDesc.label = "sampler with anisotropic filtering";
|
||||||
|
|
||||||
wgpuDeviceCreateSampler(device, &clientDesc);
|
wgpuDeviceCreateSampler(device, &clientDesc);
|
||||||
FlushClient(false);
|
EXPECT_CALL(api, DeviceCreateSampler(apiDevice, NotNull()))
|
||||||
|
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* desc) -> WGPUSampler {
|
||||||
|
const auto* ext =
|
||||||
|
reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
|
||||||
|
desc->nextInChain);
|
||||||
|
EXPECT_EQ(ext->chain.sType, WGPUSType_SamplerDescriptorDummyAnisotropicFiltering);
|
||||||
|
EXPECT_EQ(ext->maxAnisotropy, clientExt1.maxAnisotropy);
|
||||||
|
|
||||||
|
EXPECT_EQ(ext->chain.next->sType, WGPUSType_Invalid);
|
||||||
|
|
||||||
|
EXPECT_EQ(ext->chain.next->next, nullptr);
|
||||||
|
|
||||||
|
return api.GetNewSampler();
|
||||||
|
}));
|
||||||
|
FlushClient();
|
||||||
|
|
||||||
// Swap the order of the chained structs.
|
// Swap the order of the chained structs.
|
||||||
clientDesc.nextInChain = &clientExt2.chain;
|
clientDesc.nextInChain = &clientExt2.chain;
|
||||||
|
@ -160,7 +200,21 @@ TEST_F(WireExtensionTests, ValidAndInvalidSTypeInChain) {
|
||||||
clientExt1.chain.next = nullptr;
|
clientExt1.chain.next = nullptr;
|
||||||
|
|
||||||
wgpuDeviceCreateSampler(device, &clientDesc);
|
wgpuDeviceCreateSampler(device, &clientDesc);
|
||||||
FlushClient(false);
|
EXPECT_CALL(api, DeviceCreateSampler(apiDevice, NotNull()))
|
||||||
|
.WillOnce(Invoke([&](Unused, const WGPUSamplerDescriptor* desc) -> WGPUSampler {
|
||||||
|
EXPECT_EQ(desc->nextInChain->sType, WGPUSType_Invalid);
|
||||||
|
|
||||||
|
const auto* ext =
|
||||||
|
reinterpret_cast<const WGPUSamplerDescriptorDummyAnisotropicFiltering*>(
|
||||||
|
desc->nextInChain->next);
|
||||||
|
EXPECT_EQ(ext->chain.sType, WGPUSType_SamplerDescriptorDummyAnisotropicFiltering);
|
||||||
|
EXPECT_EQ(ext->maxAnisotropy, clientExt1.maxAnisotropy);
|
||||||
|
|
||||||
|
EXPECT_EQ(ext->chain.next, nullptr);
|
||||||
|
|
||||||
|
return api.GetNewSampler();
|
||||||
|
}));
|
||||||
|
FlushClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that (de)?serializing a chained struct with subdescriptors works.
|
// Test that (de)?serializing a chained struct with subdescriptors works.
|
||||||
|
|
Loading…
Reference in New Issue