[dawn][wire] Make sure to release WGPUObjects on Server teardown.

- The fuzzer found that if the server was deleted while an async
  pipeline creation is in flight, the callback would end up being
  called when the server's weak_ptr is already invalid and as a
  result, skip calling the callback implementation altogether. This
  results in the pipeline (if one was returned) being leaked.
- This change passes a shared_ptr of the ProcTable to the callback
  userdatas so that they can clean up any WGPUObjects that are
  returned from the callbacks if the server is already gone.

Bug: 476162309
Change-Id: Ie3bdb6f61a361952f7c7d32e44eb762c5f650f5e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/289215
Auto-Submit: Loko Kung <lokokung@google.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
diff --git a/generator/templates/dawn/wire/server/ServerBase.h b/generator/templates/dawn/wire/server/ServerBase.h
index edded22..0f16f4e29 100644
--- a/generator/templates/dawn/wire/server/ServerBase.h
+++ b/generator/templates/dawn/wire/server/ServerBase.h
@@ -28,6 +28,7 @@
 #ifndef DAWNWIRE_SERVER_SERVERBASE_AUTOGEN_H_
 #define DAWNWIRE_SERVER_SERVERBASE_AUTOGEN_H_
 
+#include <memory>
 #include <tuple>
 
 #include "dawn/common/Mutex.h"
@@ -43,14 +44,14 @@
 
     class ServerBase : public ChunkedCommandHandler, public ObjectIdResolver {
       public:
-        ServerBase(const DawnProcTable& procs) : mProcs(procs) {}
+        ServerBase(const DawnProcTable& procs) : mProcs(std::make_shared<DawnProcTable>(procs)) {}
         ~ServerBase() override = default;
 
         Mutex::AutoLock GetGuard() { return Mutex::AutoLock(&mMutex); }
 
       protected:
         // Proc table may be used by children as well.
-        DawnProcTable mProcs;
+        std::shared_ptr<const DawnProcTable> mProcs;
 
         // Template functions that implement helpers on KnownObjects.
         template <typename T>
@@ -103,7 +104,7 @@
 
         template <typename T>
         void Release(T handle) {
-            (mProcs.*WGPUTraits<T>::Release)(handle);
+            ((*mProcs).*WGPUTraits<T>::Release)(handle);
         }
         void DestroyAllObjects() {
             //* Release devices first to force completion of any async work.
diff --git a/generator/templates/dawn/wire/server/ServerDoers.cpp b/generator/templates/dawn/wire/server/ServerDoers.cpp
index 858afb2..26cb32f 100644
--- a/generator/templates/dawn/wire/server/ServerDoers.cpp
+++ b/generator/templates/dawn/wire/server/ServerDoers.cpp
@@ -63,7 +63,7 @@
                         {{ assert(ret|length == 0) }}
                         {{ assert(not method.returns) }}
                     {% endif %}
-                    mProcs.{{as_varName(type.name, method.name)}}(
+                    mProcs->{{as_varName(type.name, method.name)}}(
                         {%- for member in command.members if not member.is_return_value -%}
                             {{as_varName(member.name)}}
                             {%- if not loop.last -%}, {% endif %}
diff --git a/generator/templates/dawn/wire/server/WGPUTraits.h b/generator/templates/dawn/wire/server/WGPUTraits.h
index 5cf1681..1f51f89 100644
--- a/generator/templates/dawn/wire/server/WGPUTraits.h
+++ b/generator/templates/dawn/wire/server/WGPUTraits.h
@@ -33,7 +33,9 @@
 namespace dawn::wire::server {
 
 template <typename T>
-struct WGPUTraits;
+struct WGPUTraits {
+    static constexpr auto Release = nullptr;
+};
 
 {% for type in by_category["object"] %}
     {% set cType = as_cType(type.name) %}
diff --git a/src/dawn/wire/server/Server.cpp b/src/dawn/wire/server/Server.cpp
index f0faed8..5f76c87 100644
--- a/src/dawn/wire/server/Server.cpp
+++ b/src/dawn/wire/server/Server.cpp
@@ -30,7 +30,9 @@
 
 namespace dawn::wire::server {
 
-CallbackUserdata::CallbackUserdata(const std::weak_ptr<Server>& server) : server(server) {}
+CallbackUserdata::CallbackUserdata(const std::weak_ptr<Server>& server,
+                                   std::shared_ptr<const DawnProcTable>& procs)
+    : server(server), procs(procs) {}
 
 // static
 std::shared_ptr<Server> Server::Create(const DawnProcTable& procs,
@@ -86,7 +88,7 @@
 
     // The Buffer is externally owned so it shouldn't be destroyed when we receive a destroy
     // message from the client. Add a reference to counterbalance the eventual release.
-    mProcs.bufferAddRef(buffer);
+    mProcs->bufferAddRef(buffer);
 
     return WireResult::Success;
 }
@@ -110,7 +112,7 @@
 
     // The texture is externally owned so it shouldn't be destroyed when we receive a destroy
     // message from the client. Add a reference to counterbalance the eventual release.
-    mProcs.textureAddRef(texture);
+    mProcs->textureAddRef(texture);
 
     return WireResult::Success;
 }
@@ -134,7 +136,7 @@
 
     // The surface is externally owned so it shouldn't be destroyed when we receive a destroy
     // message from the client. Add a reference to counterbalance the eventual release.
-    mProcs.surfaceAddRef(surface);
+    mProcs->surfaceAddRef(surface);
 
     return WireResult::Success;
 }
@@ -150,7 +152,7 @@
 
     // The instance is externally owned so it shouldn't be destroyed when we receive a destroy
     // message from the client. Add a reference to counterbalance the eventual release.
-    mProcs.instanceAddRef(instance);
+    mProcs->instanceAddRef(instance);
 
     return WireResult::Success;
 }
@@ -184,7 +186,7 @@
     // is freed.
 
     // Set callback to post warning and other information to client.
-    mProcs.deviceSetLoggingCallback(
+    mProcs->deviceSetLoggingCallback(
         device->handle, {nullptr,
                          [](WGPULoggingType type, WGPUStringView message, void* userdata, void*) {
                              DeviceInfo* info = static_cast<DeviceInfo*>(userdata);
@@ -196,7 +198,7 @@
 
 void Server::ClearDeviceCallbacks(WGPUDevice device) {
     // Un-set the logging callback since we cannot forward them after the server has been destroyed.
-    mProcs.deviceSetLoggingCallback(device, kEmptyLoggingCallbackInfo);
+    mProcs->deviceSetLoggingCallback(device, kEmptyLoggingCallbackInfo);
 }
 
 }  // namespace dawn::wire::server
diff --git a/src/dawn/wire/server/Server.h b/src/dawn/wire/server/Server.h
index 6ded567..c94b4fc 100644
--- a/src/dawn/wire/server/Server.h
+++ b/src/dawn/wire/server/Server.h
@@ -67,9 +67,11 @@
 // void Server::MyCallbackHandler(MyUserdata* userdata, Other args) { }
 struct CallbackUserdata {
     const std::weak_ptr<Server> server;
+    const std::shared_ptr<const DawnProcTable> procs;
 
     CallbackUserdata() = delete;
-    explicit CallbackUserdata(const std::weak_ptr<Server>& server);
+    CallbackUserdata(const std::weak_ptr<Server>& server,
+                     std::shared_ptr<const DawnProcTable>& procs);
 };
 
 template <auto F, typename _ = decltype(F)>
@@ -84,13 +86,22 @@
         std::unique_ptr<Userdata> data(static_cast<Userdata*>(userdata));
         auto server = data->server.lock();
         if (!server) {
-            // Do nothing if the server has already been destroyed.
+            // If the server is destroyed, release any callback owned results and return.
+            (
+                []<typename T>(const DawnProcTable& procs, T arg) {
+                    if constexpr (WGPUTraits<T>::Release != nullptr) {
+                        if (arg) {
+                            (procs.*WGPUTraits<T>::Release)(arg);
+                        }
+                    }
+                }(*(data->procs), std::forward<Args>(args)),
+                ...);
             return;
         }
         // Forward the arguments and the typed userdata to the Server:: member function.
         {
             auto serverGuard = server.get()->GetGuard();
-            (server.get()->*F)(data.get(), std::forward<decltype(args)>(args)...);
+            (server.get()->*F)(data.get(), std::forward<Args>(args)...);
         }
         server.get()->Flush();
     }
@@ -191,7 +202,7 @@
     template <typename T,
               typename Enable = std::enable_if<std::is_base_of<CallbackUserdata, T>::value>>
     std::unique_ptr<T> MakeUserdata() {
-        return std::unique_ptr<T>(new T(mSelf));
+        return std::unique_ptr<T>(new T(mSelf, mProcs));
     }
 
     template <typename CallbackInfo,
@@ -222,11 +233,12 @@
     template <typename Struct>
     class FreeMembers : public Struct {
       public:
-        explicit FreeMembers(const DawnProcTable& procs) : Struct({}), mProcs(procs) {}
-        ~FreeMembers() { (mProcs.*WGPUTraits<Struct>::FreeMembers)(*this); }
+        explicit FreeMembers(std::shared_ptr<const DawnProcTable>& procs)
+            : Struct({}), mProcs(procs) {}
+        ~FreeMembers() { ((*mProcs).*WGPUTraits<Struct>::FreeMembers)(*this); }
 
       private:
-        const DawnProcTable& mProcs;
+        std::shared_ptr<const DawnProcTable> mProcs;
     };
 
     void SetForwardingDeviceCallbacks(Known<WGPUDevice> device);
diff --git a/src/dawn/wire/server/ServerAdapter.cpp b/src/dawn/wire/server/ServerAdapter.cpp
index 55c012f..15ec388 100644
--- a/src/dawn/wire/server/ServerAdapter.cpp
+++ b/src/dawn/wire/server/ServerAdapter.cpp
@@ -72,7 +72,7 @@
         },
         nullptr, device->info.get()};
 
-    mProcs.adapterRequestDevice(
+    mProcs->adapterRequestDevice(
         adapter->handle, &desc,
         MakeCallbackInfo<WGPURequestDeviceCallbackInfo, &Server::OnRequestDeviceCallback,
                          WGPUCallbackMode_AllowSpontaneous>(userdata.release()));
@@ -100,13 +100,13 @@
     // Note: We fail the callback here, instead of immediately upon receiving
     // the request to preserve callback ordering.
     FreeMembers<WGPUSupportedFeatures> supportedFeatures(mProcs);
-    mProcs.deviceGetFeatures(device, &supportedFeatures);
+    mProcs->deviceGetFeatures(device, &supportedFeatures);
     absl::Span<const WGPUFeatureName> features(supportedFeatures.features,
                                                supportedFeatures.featureCount);
     for (WGPUFeatureName feature : features) {
         if (!IsFeatureSupported(feature)) {
             // Release the device.
-            mProcs.deviceRelease(device);
+            mProcs->deviceRelease(device);
             device = nullptr;
 
             cmd.status = WGPURequestDeviceStatus_Error;
@@ -131,7 +131,7 @@
     WGPUResourceTableLimits resourceTableLimits = WGPU_RESOURCE_TABLE_LIMITS_INIT;
     texelCopyBufferRowAlignmentLimits.chain.next = &resourceTableLimits.chain;
 
-    mProcs.deviceGetLimits(device, &limits);
+    mProcs->deviceGetLimits(device, &limits);
     cmd.limits = &limits;
 
     // Assign the handle and allocated status if the device is created successfully.
diff --git a/src/dawn/wire/server/ServerBuffer.cpp b/src/dawn/wire/server/ServerBuffer.cpp
index 9d209fa..ba8e9e0 100644
--- a/src/dawn/wire/server/ServerBuffer.cpp
+++ b/src/dawn/wire/server/ServerBuffer.cpp
@@ -118,7 +118,7 @@
     userdata->offset = offset;
     userdata->size = size;
 
-    mProcs.bufferMapAsync(
+    mProcs->bufferMapAsync(
         buffer->handle, mode, offset, size,
         MakeCallbackInfo<WGPUBufferMapCallbackInfo, &Server::OnBufferMapAsyncCallback>(
             userdata.release()));
@@ -136,7 +136,7 @@
     // Create and register the buffer object.
     Reserved<WGPUBuffer> buffer;
     WIRE_TRY(Allocate(&buffer, bufferHandle));
-    buffer->handle = mProcs.deviceCreateBuffer(device->handle, descriptor);
+    buffer->handle = mProcs->deviceCreateBuffer(device->handle, descriptor);
     buffer->usage = descriptor->usage;
     buffer->mappedAtCreation = (descriptor->mappedAtCreation != 0u);
 
@@ -178,7 +178,7 @@
         writeHandle->SetDataLength(descriptor->size);
 
         if (descriptor->mappedAtCreation) {
-            void* mapping = mProcs.bufferGetMappedRange(buffer->handle, 0, descriptor->size);
+            void* mapping = mProcs->bufferGetMappedRange(buffer->handle, 0, descriptor->size);
             if (mapping == nullptr) {
                 DAWN_ASSERT(descriptor->size % 4 != 0);
                 // GetMappedRange can still fail if the buffer's size isn't aligned.
@@ -273,7 +273,7 @@
     if (isSuccess) {
         if (isRead) {
             // Get the serialization size of the message to initialize ReadHandle data.
-            readData = mProcs.bufferGetConstMappedRange(data->bufferObj, data->offset, data->size);
+            readData = mProcs->bufferGetConstMappedRange(data->bufferObj, data->offset, data->size);
             readDataUpdateInfoLength =
                 buffer->readHandle->SizeOfSerializeDataUpdate(data->offset, data->size);
             cmd.readDataUpdateInfoLength = readDataUpdateInfoLength;
@@ -287,7 +287,7 @@
             // modified (i.e. we don't want getMappedRange(0, wholeBufferSize) if only a
             // subset of the buffer is actually mapped) in case the implementation does some
             // range tracking.
-            buffer->writeHandle->SetTarget(static_cast<uint8_t*>(mProcs.bufferGetMappedRange(
+            buffer->writeHandle->SetTarget(static_cast<uint8_t*>(mProcs->bufferGetMappedRange(
                                                data->bufferObj, data->offset, data->size)) -
                                            data->offset);
         }
diff --git a/src/dawn/wire/server/ServerDevice.cpp b/src/dawn/wire/server/ServerDevice.cpp
index ef51d89..beebcb1 100644
--- a/src/dawn/wire/server/ServerDevice.cpp
+++ b/src/dawn/wire/server/ServerDevice.cpp
@@ -73,7 +73,7 @@
     userdata->eventManager = eventManager;
     userdata->future = future;
 
-    mProcs.devicePopErrorScope(
+    mProcs->devicePopErrorScope(
         device->handle,
         MakeCallbackInfo<WGPUPopErrorScopeCallbackInfo, &Server::OnDevicePopErrorScope>(
             userdata.release()));
@@ -109,7 +109,7 @@
     userdata->future = future;
     userdata->pipelineObjectID = pipeline.id;
 
-    mProcs.deviceCreateComputePipelineAsync(
+    mProcs->deviceCreateComputePipelineAsync(
         device->handle, descriptor,
         MakeCallbackInfo<WGPUCreateComputePipelineAsyncCallbackInfo,
                          &Server::OnCreateComputePipelineAsyncCallback>(userdata.release()));
@@ -149,7 +149,7 @@
     userdata->future = future;
     userdata->pipelineObjectID = pipeline.id;
 
-    mProcs.deviceCreateRenderPipelineAsync(
+    mProcs->deviceCreateRenderPipelineAsync(
         device->handle, descriptor,
         MakeCallbackInfo<WGPUCreateRenderPipelineAsyncCallbackInfo,
                          &Server::OnCreateRenderPipelineAsyncCallback>(userdata.release()));
diff --git a/src/dawn/wire/server/ServerInstance.cpp b/src/dawn/wire/server/ServerInstance.cpp
index ac3f29a..b92b8e7 100644
--- a/src/dawn/wire/server/ServerInstance.cpp
+++ b/src/dawn/wire/server/ServerInstance.cpp
@@ -48,7 +48,7 @@
     userdata->future = future;
     userdata->adapterObjectId = adapter.id;
 
-    mProcs.instanceRequestAdapter(
+    mProcs->instanceRequestAdapter(
         instance->handle, options,
         MakeCallbackInfo<WGPURequestAdapterCallbackInfo, &Server::OnRequestAdapterCallback,
                          WGPUCallbackMode_AllowSpontaneous>(userdata.release()));
@@ -81,7 +81,7 @@
 
     // Query and report the adapter supported features.
     FreeMembers<WGPUSupportedFeatures> supportedFeatures(mProcs);
-    mProcs.adapterGetFeatures(adapter, &supportedFeatures);
+    mProcs->adapterGetFeatures(adapter, &supportedFeatures);
     cmd.featuresCount = supportedFeatures.featureCount;
     cmd.features = supportedFeatures.features;
 
@@ -92,7 +92,7 @@
     // Query AdapterPropertiesMemoryHeaps if the feature is supported.
     FreeMembers<WGPUAdapterPropertiesMemoryHeaps> memoryHeapProperties(mProcs);
     memoryHeapProperties.chain.sType = WGPUSType_AdapterPropertiesMemoryHeaps;
-    if (mProcs.adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesMemoryHeaps)) {
+    if (mProcs->adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesMemoryHeaps)) {
         *propertiesChain = &memoryHeapProperties.chain;
         propertiesChain = &(*propertiesChain)->next;
     }
@@ -100,7 +100,7 @@
     // Query AdapterPropertiesD3D if the feature is supported.
     WGPUAdapterPropertiesD3D d3dProperties = {};
     d3dProperties.chain.sType = WGPUSType_AdapterPropertiesD3D;
-    if (mProcs.adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesD3D)) {
+    if (mProcs->adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesD3D)) {
         *propertiesChain = &d3dProperties.chain;
         propertiesChain = &(*propertiesChain)->next;
     }
@@ -108,7 +108,7 @@
     // Query AdapterPropertiesVk if the feature is supported.
     WGPUAdapterPropertiesVk vkProperties = {};
     vkProperties.chain.sType = WGPUSType_AdapterPropertiesVk;
-    if (mProcs.adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesVk)) {
+    if (mProcs->adapterHasFeature(adapter, WGPUFeatureName_AdapterPropertiesVk)) {
         *propertiesChain = &vkProperties.chain;
         propertiesChain = &(*propertiesChain)->next;
     }
@@ -117,7 +117,7 @@
     FreeMembers<WGPUAdapterPropertiesSubgroupMatrixConfigs> subgroupMatrixConfigs(mProcs);
     // WGPUAdapterPropertiesSubgroupMatrixConfigs subgroupMatrixConfigs{};
     subgroupMatrixConfigs.chain.sType = WGPUSType_AdapterPropertiesSubgroupMatrixConfigs;
-    if (mProcs.adapterHasFeature(adapter, WGPUFeatureName_ChromiumExperimentalSubgroupMatrix)) {
+    if (mProcs->adapterHasFeature(adapter, WGPUFeatureName_ChromiumExperimentalSubgroupMatrix)) {
         *propertiesChain = &subgroupMatrixConfigs.chain;
         propertiesChain = &(*propertiesChain)->next;
     }
@@ -131,13 +131,13 @@
     WGPUAdapterPropertiesExplicitComputeSubgroupSizeConfigs explicitComputeSubgroupSizeConfigs = {};
     explicitComputeSubgroupSizeConfigs.chain.sType =
         WGPUSType_AdapterPropertiesExplicitComputeSubgroupSizeConfigs;
-    if (mProcs.adapterHasFeature(adapter,
-                                 WGPUFeatureName_ChromiumExperimentalSubgroupSizeControl)) {
+    if (mProcs->adapterHasFeature(adapter,
+                                  WGPUFeatureName_ChromiumExperimentalSubgroupSizeControl)) {
         *propertiesChain = &explicitComputeSubgroupSizeConfigs.chain;
         propertiesChain = &(*propertiesChain)->next;
     }
 
-    mProcs.adapterGetInfo(adapter, &info);
+    mProcs->adapterGetInfo(adapter, &info);
     cmd.info = &info;
 
     // Query and report the adapter limits, including all known extension limits.
@@ -152,7 +152,7 @@
         WGPU_DAWN_TEXEL_COPY_BUFFER_ROW_ALIGNMENT_LIMITS_INIT;
     compatLimits.chain.next = &texelCopyBufferRowAlignmentLimits.chain;
 
-    mProcs.adapterGetLimits(adapter, &limits);
+    mProcs->adapterGetLimits(adapter, &limits);
     cmd.limits = &limits;
 
     SerializeCommand(cmd);
diff --git a/src/dawn/wire/server/ServerProgrammableEncoder.cpp b/src/dawn/wire/server/ServerProgrammableEncoder.cpp
index a1d8319..af8c6b8 100644
--- a/src/dawn/wire/server/ServerProgrammableEncoder.cpp
+++ b/src/dawn/wire/server/ServerProgrammableEncoder.cpp
@@ -36,8 +36,8 @@
                                                     uint32_t immediateDataRangeOffsetBytes,
                                                     const uint8_t* data,
                                                     size_t size) {
-    mProcs.renderPassEncoderSetImmediates(renderPassEncoder->handle, immediateDataRangeOffsetBytes,
-                                          data, size);
+    mProcs->renderPassEncoderSetImmediates(renderPassEncoder->handle, immediateDataRangeOffsetBytes,
+                                           data, size);
     return WireResult::Success;
 }
 
@@ -46,8 +46,8 @@
     uint32_t immediateDataRangeOffsetBytes,
     const uint8_t* data,
     size_t size) {
-    mProcs.renderBundleEncoderSetImmediates(renderBundleEncoder->handle,
-                                            immediateDataRangeOffsetBytes, data, size);
+    mProcs->renderBundleEncoderSetImmediates(renderBundleEncoder->handle,
+                                             immediateDataRangeOffsetBytes, data, size);
     return WireResult::Success;
 }
 
@@ -56,8 +56,8 @@
     uint32_t immediateDataRangeOffsetBytes,
     const uint8_t* data,
     size_t size) {
-    mProcs.computePassEncoderSetImmediates(computePassEncoder->handle,
-                                           immediateDataRangeOffsetBytes, data, size);
+    mProcs->computePassEncoderSetImmediates(computePassEncoder->handle,
+                                            immediateDataRangeOffsetBytes, data, size);
     return WireResult::Success;
 }
 
diff --git a/src/dawn/wire/server/ServerQueue.cpp b/src/dawn/wire/server/ServerQueue.cpp
index bcb8eef..ebe37b7 100644
--- a/src/dawn/wire/server/ServerQueue.cpp
+++ b/src/dawn/wire/server/ServerQueue.cpp
@@ -53,7 +53,7 @@
     userdata->eventManager = eventManager;
     userdata->future = future;
 
-    mProcs.queueOnSubmittedWorkDone(
+    mProcs->queueOnSubmittedWorkDone(
         queue->handle, MakeCallbackInfo<WGPUQueueWorkDoneCallbackInfo, &Server::OnQueueWorkDone>(
                            userdata.release()));
     return WireResult::Success;
@@ -68,8 +68,8 @@
         return WireResult::FatalError;
     }
 
-    mProcs.queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, data,
-                            static_cast<size_t>(size));
+    mProcs->queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, data,
+                             static_cast<size_t>(size));
     return WireResult::Success;
 }
 
@@ -100,8 +100,8 @@
     // it. If so, we can avoid a copy.
     uint8_t* sourceData = writeHandle->GetSourceData();
     if (sourceData) {
-        mProcs.queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, sourceData,
-                                static_cast<size_t>(size));
+        mProcs->queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, sourceData,
+                                 static_cast<size_t>(size));
         return WireResult::Success;
     }
 
@@ -121,8 +121,8 @@
         return WireResult::FatalError;
     }
 
-    mProcs.queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, backingData.get(),
-                            static_cast<size_t>(size));
+    mProcs->queueWriteBuffer(queue->handle, buffer->handle, bufferOffset, backingData.get(),
+                             static_cast<size_t>(size));
     return WireResult::Success;
 }
 
@@ -136,8 +136,8 @@
         return WireResult::FatalError;
     }
 
-    mProcs.queueWriteTexture(queue->handle, destination, data, static_cast<size_t>(dataSize),
-                             dataLayout, writeSize);
+    mProcs->queueWriteTexture(queue->handle, destination, data, static_cast<size_t>(dataSize),
+                              dataLayout, writeSize);
     return WireResult::Success;
 }
 
@@ -169,8 +169,8 @@
     // it. If so, we can avoid a copy.
     uint8_t* sourceData = writeHandle->GetSourceData();
     if (sourceData) {
-        mProcs.queueWriteTexture(queue->handle, destination, sourceData,
-                                 static_cast<size_t>(dataSize), dataLayout, writeSize);
+        mProcs->queueWriteTexture(queue->handle, destination, sourceData,
+                                  static_cast<size_t>(dataSize), dataLayout, writeSize);
         return WireResult::Success;
     }
 
@@ -190,8 +190,8 @@
         return WireResult::FatalError;
     }
 
-    mProcs.queueWriteTexture(queue->handle, destination, backingData.get(),
-                             static_cast<size_t>(dataSize), dataLayout, writeSize);
+    mProcs->queueWriteTexture(queue->handle, destination, backingData.get(),
+                              static_cast<size_t>(dataSize), dataLayout, writeSize);
     return WireResult::Success;
 }
 
diff --git a/src/dawn/wire/server/ServerShaderModule.cpp b/src/dawn/wire/server/ServerShaderModule.cpp
index 35439fb..8afa631 100644
--- a/src/dawn/wire/server/ServerShaderModule.cpp
+++ b/src/dawn/wire/server/ServerShaderModule.cpp
@@ -38,7 +38,7 @@
     userdata->eventManager = eventManager;
     userdata->future = future;
 
-    mProcs.shaderModuleGetCompilationInfo(
+    mProcs->shaderModuleGetCompilationInfo(
         shaderModule->handle,
         MakeCallbackInfo<WGPUCompilationInfoCallbackInfo,
                          &Server::OnShaderModuleGetCompilationInfo>(userdata.release()));
diff --git a/src/dawn/wire/server/ServerSurface.cpp b/src/dawn/wire/server/ServerSurface.cpp
index 081fb08..b981358 100644
--- a/src/dawn/wire/server/ServerSurface.cpp
+++ b/src/dawn/wire/server/ServerSurface.cpp
@@ -37,7 +37,7 @@
     WIRE_TRY(Allocate(&texture, textureHandle, AllocationState::Reserved));
 
     WGPUSurfaceTexture surfaceTexture;
-    mProcs.surfaceGetCurrentTexture(surface->handle, &surfaceTexture);
+    mProcs->surfaceGetCurrentTexture(surface->handle, &surfaceTexture);
 
     if (surfaceTexture.texture != nullptr) {
         return FillReservation(texture.id, surfaceTexture.texture);
@@ -45,7 +45,8 @@
         // The client always assumes that a texture will be associated with the reservation, so
         // create an error texture on the configured device.
         WGPUTextureDescriptor desc = WGPU_TEXTURE_DESCRIPTOR_INIT;
-        WGPUTexture errorTexture = mProcs.deviceCreateErrorTexture(configuredDevice->handle, &desc);
+        WGPUTexture errorTexture =
+            mProcs->deviceCreateErrorTexture(configuredDevice->handle, &desc);
         return FillReservation(texture.id, errorTexture);
     }
 }