[emscripten] Validate invalid callback modes
- Add ValidateCallbackMode helper. It allows only valid modes, or if
callback is nullptr, it also allows WGPUCallbackMode(0).
- Use it to validate every CallbackMode (of which there are 9).
- Default WGPUCallbackMode(0) to AllowSpontaneous in TrackedEvent.
- Simplify TrackEvent() which no longer needs to deal with this.
- Remove workaround for kDefaultDescriptor in RequestDevice.
No-Try: true
Bug: 42241221
Change-Id: Icca908e39e189ff257fd38bf61831728f2f68873
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/242096
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp b/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp
index 2f58dad..d1f9d62 100644
--- a/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp
+++ b/third_party/emdawnwebgpu/pkg/webgpu/src/webgpu.cpp
@@ -29,8 +29,16 @@
#ifndef NDEBUG
#include <cstdio>
#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__)
+#define DCHECK_PRINTF(condition, ...) \
+ do { \
+ if (!(condition)) { \
+ fprintf(stderr, __VA_ARGS__); \
+ assert(false); \
+ } \
+ } while (0)
#else
#define DEBUG_PRINTF(...)
+#define DCHECK_PRINTF(...)
#endif
using FutureID = uint64_t;
@@ -383,6 +391,25 @@
WorkDone,
};
+bool ValidateCallbackMode(WGPUCallbackMode mode, bool hasCallback) {
+ if (mode == WGPUCallbackMode_WaitAnyOnly ||
+ mode == WGPUCallbackMode_AllowProcessEvents ||
+ mode == WGPUCallbackMode_AllowSpontaneous ||
+ (int(mode) == 0 && !hasCallback)) {
+ return true;
+ } else {
+ DEBUG_PRINTF("Invalid WGPUCallbackMode %d\n", mode);
+ return false;
+ }
+}
+
+template <typename CallbackInfo>
+bool ValidateCallbackMode(const CallbackInfo& info) {
+ // This small templated function delegates to the larger non-templated
+ // function to avoid unnecessary monomorphization.
+ return ValidateCallbackMode(info.mode, info.callback);
+}
+
class EventManager;
class TrackedEvent : NonMovable {
@@ -393,7 +420,13 @@
protected:
TrackedEvent(InstanceID instance, WGPUCallbackMode mode)
- : mInstanceId(instance), mMode(mode) {}
+ : mInstanceId(instance),
+ // Mode can only be 0 if there's no callback, so just pick any default.
+ mMode(int(mode) == 0 ? WGPUCallbackMode_AllowSpontaneous : mode) {
+ assert(mMode == WGPUCallbackMode_WaitAnyOnly ||
+ mMode == WGPUCallbackMode_AllowProcessEvents ||
+ mMode == WGPUCallbackMode_AllowSpontaneous);
+ }
private:
friend class EventManager;
@@ -523,8 +556,11 @@
std::vector<FutureID> futures;
std::unordered_map<FutureID, WGPUFutureWaitInfo*> futureIdToInfo;
for (size_t i = 0; i < count; ++i) {
- futures.push_back(infos[i].future.id);
- futureIdToInfo.emplace(infos[i].future.id, &infos[i]);
+ FutureID id = infos[i].future.id;
+ DCHECK_PRINTF(id != kNullFutureId && id < mNextFutureId,
+ "Invalid future id %" PRIu64 "\n", id);
+ futures.push_back(id);
+ futureIdToInfo.emplace(id, &infos[i]);
}
// We need to clamp and convert the timeout to verify that the timeout in
@@ -600,7 +636,7 @@
return anyCompleted ? WGPUWaitStatus_Success : WGPUWaitStatus_TimedOut;
}
- std::pair<FutureID, bool> TrackEvent(std::unique_ptr<TrackedEvent> event) {
+ FutureID TrackEvent(std::unique_ptr<TrackedEvent> event) {
FutureID futureId = mNextFutureId++;
InstanceID instance = event->mInstanceId;
std::unique_lock<std::mutex> lock(mMutex);
@@ -612,22 +648,19 @@
// The instance has already been unregistered so just complete this
// event as shutdown now.
event->Complete(futureId, EventCompletionType::Shutdown);
- return {futureId, false};
+ return futureId;
}
it->second.insert(futureId);
- mEvents.try_emplace(futureId, std::move(event));
break;
}
- case WGPUCallbackMode_AllowSpontaneous: {
- mEvents.try_emplace(futureId, std::move(event));
+ // Any invalid callback mode should already have been validated by
+ // ValidateCallbackMode, but it still may be 0 if there's no callback.
+ default:
+ case WGPUCallbackMode_AllowSpontaneous:
break;
- }
- default: {
- // Invalid callback mode, so we just return kNullFutureId.
- return {kNullFutureId, false};
- }
}
- return {futureId, true};
+ mEvents.try_emplace(futureId, std::move(event));
+ return futureId;
}
template <typename Event, typename... ReadyArgs>
@@ -747,7 +780,7 @@
public:
// Reservation constructor used when calling RequestDevice.
WGPUDeviceImpl(const EventSource* source,
- const WGPUDeviceDescriptor* descriptor,
+ const WGPUDeviceDescriptor& descriptor,
WGPUQueue queue);
// Injection constructor used when we already have a backing Device.
WGPUDeviceImpl(const EventSource* source, WGPUQueue queue);
@@ -1333,7 +1366,7 @@
WGPUDeviceLostReason_FailedCreation, "Device creation failed.");
// Free the device now that there should be no pointers to it.
- [[maybe_unused]] bool deviceFreed = device->Release();
+ bool deviceFreed = device->Release();
assert(deviceFreed);
}
}
@@ -1437,11 +1470,11 @@
size_t offset,
size_t size,
WGPUBufferMapCallbackInfo callbackInfo) {
- auto [futureId, tracked] = GetEventManager().TrackEvent(
- std::make_unique<MapAsyncEvent>(GetInstanceId(), this, callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId = GetEventManager().TrackEvent(
+ std::make_unique<MapAsyncEvent>(GetInstanceId(), this, callbackInfo));
if (mMapState == WGPUBufferMapState_Pending) {
GetEventManager().SetFutureReady<MapAsyncEvent>(
@@ -1495,14 +1528,14 @@
// ----------------------------------------------------------------------------
WGPUDeviceImpl::WGPUDeviceImpl(const EventSource* source,
- const WGPUDeviceDescriptor* descriptor,
+ const WGPUDeviceDescriptor& descriptor,
WGPUQueue queue)
: EventSource(source),
- mUncapturedErrorCallbackInfo(descriptor->uncapturedErrorCallbackInfo) {
+ mUncapturedErrorCallbackInfo(descriptor.uncapturedErrorCallbackInfo) {
// Create the DeviceLostEvent now.
- std::tie(mDeviceLostFutureId, std::ignore) =
+ mDeviceLostFutureId =
GetEventManager().TrackEvent(std::make_unique<DeviceLostEvent>(
- source->GetInstanceId(), this, descriptor->deviceLostCallbackInfo));
+ source->GetInstanceId(), this, descriptor.deviceLostCallbackInfo));
mQueue.Acquire(queue);
}
@@ -1630,12 +1663,12 @@
WGPUFuture WGPUShaderModuleImpl::GetCompilationInfo(
WGPUCompilationInfoCallbackInfo callbackInfo) {
- auto [futureId, tracked] =
- GetEventManager().TrackEvent(std::make_unique<CompilationInfoEvent>(
- GetInstanceId(), this, callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId =
+ GetEventManager().TrackEvent(std::make_unique<CompilationInfoEvent>(
+ GetInstanceId(), this, callbackInfo));
// If we already have the compilation info cached, we don't need to call into
// JS.
@@ -1738,26 +1771,24 @@
WGPUAdapter adapter,
const WGPUDeviceDescriptor* descriptor,
WGPURequestDeviceCallbackInfo callbackInfo) {
- auto [futureId, tracked] =
- GetEventManager().TrackEvent(std::make_unique<RequestDeviceEvent>(
- adapter->GetInstanceId(), callbackInfo));
- if (!tracked) {
- return WGPUFuture{kNullFutureId};
- }
-
- static const WGPUDeviceDescriptor kDefaultDescriptor = []() {
- WGPUDeviceDescriptor desc = WGPU_DEVICE_DESCRIPTOR_INIT;
- desc.deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
- return desc;
- }();
+ static const WGPUDeviceDescriptor kDefaultDescriptor =
+ WGPU_DEVICE_DESCRIPTOR_INIT;
if (descriptor == nullptr) {
descriptor = &kDefaultDescriptor;
}
+ if (!ValidateCallbackMode(callbackInfo) ||
+ !ValidateCallbackMode(descriptor->deviceLostCallbackInfo)) {
+ return WGPUFuture{kNullFutureId};
+ }
+ FutureID futureId =
+ GetEventManager().TrackEvent(std::make_unique<RequestDeviceEvent>(
+ adapter->GetInstanceId(), callbackInfo));
+
// For RequestDevice, we always create a Device and Queue up front. The
// Device is also immediately associated with the DeviceLostEvent.
WGPUQueue queue = new WGPUQueueImpl(adapter);
- WGPUDevice device = new WGPUDeviceImpl(adapter, descriptor, queue);
+ WGPUDevice device = new WGPUDeviceImpl(adapter, *descriptor, queue);
auto deviceLostFutureId = device->GetLostFuture().id;
emwgpuAdapterRequestDevice(adapter, futureId, deviceLostFutureId, device,
@@ -1855,12 +1886,12 @@
WGPUDevice device,
const WGPUComputePipelineDescriptor* descriptor,
WGPUCreateComputePipelineAsyncCallbackInfo callbackInfo) {
- auto [futureId, tracked] =
- GetEventManager().TrackEvent(std::make_unique<CreateComputePipelineEvent>(
- device->GetInstanceId(), callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId =
+ GetEventManager().TrackEvent(std::make_unique<CreateComputePipelineEvent>(
+ device->GetInstanceId(), callbackInfo));
WGPUComputePipeline pipeline = emwgpuCreateComputePipeline(device);
emwgpuDeviceCreateComputePipelineAsync(device, futureId, descriptor,
@@ -1872,12 +1903,12 @@
WGPUDevice device,
const WGPURenderPipelineDescriptor* descriptor,
WGPUCreateRenderPipelineAsyncCallbackInfo callbackInfo) {
- auto [futureId, tracked] =
- GetEventManager().TrackEvent(std::make_unique<CreateRenderPipelineEvent>(
- device->GetInstanceId(), callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId =
+ GetEventManager().TrackEvent(std::make_unique<CreateRenderPipelineEvent>(
+ device->GetInstanceId(), callbackInfo));
WGPURenderPipeline pipeline = emwgpuCreateRenderPipeline(device);
emwgpuDeviceCreateRenderPipelineAsync(device, futureId, descriptor, pipeline);
@@ -1906,12 +1937,12 @@
WGPUFuture wgpuDevicePopErrorScope(WGPUDevice device,
WGPUPopErrorScopeCallbackInfo callbackInfo) {
- auto [futureId, tracked] =
- GetEventManager().TrackEvent(std::make_unique<PopErrorScopeEvent>(
- device->GetInstanceId(), callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId =
+ GetEventManager().TrackEvent(std::make_unique<PopErrorScopeEvent>(
+ device->GetInstanceId(), callbackInfo));
emwgpuDevicePopErrorScope(device, futureId);
return WGPUFuture{futureId};
@@ -1929,12 +1960,12 @@
WGPUInstance instance,
WGPURequestAdapterOptions const* options,
WGPURequestAdapterCallbackInfo callbackInfo) {
- auto [futureId, tracked] =
- GetEventManager().TrackEvent(std::make_unique<RequestAdapterEvent>(
- instance->GetInstanceId(), callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId =
+ GetEventManager().TrackEvent(std::make_unique<RequestAdapterEvent>(
+ instance->GetInstanceId(), callbackInfo));
WGPUAdapter adapter = emwgpuCreateAdapter(instance);
emwgpuInstanceRequestAdapter(instance, futureId, options, adapter);
@@ -1963,11 +1994,11 @@
WGPUFuture wgpuQueueOnSubmittedWorkDone(
WGPUQueue queue,
WGPUQueueWorkDoneCallbackInfo callbackInfo) {
- auto [futureId, tracked] = GetEventManager().TrackEvent(
- std::make_unique<WorkDoneEvent>(queue->GetInstanceId(), callbackInfo));
- if (!tracked) {
+ if (!ValidateCallbackMode(callbackInfo)) {
return WGPUFuture{kNullFutureId};
}
+ FutureID futureId = GetEventManager().TrackEvent(
+ std::make_unique<WorkDoneEvent>(queue->GetInstanceId(), callbackInfo));
emwgpuQueueOnSubmittedWorkDone(queue, futureId);
return WGPUFuture{futureId};