Always point to own members in FlatComputePipelineDescriptor

This patch fixes a use-after-free issue in FlatComputePipelineDescriptor
by always making its pointer members point to its own members.

BUG=dawn:529, chromium:1246158, chromium:1246748
TEST=dawn_end2end_tests

Change-Id: I49b98357444edcdb1b225e961d1e4d6e5b11e978
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/63366
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/ComputePipeline.cpp b/src/dawn_native/ComputePipeline.cpp
index d1a4a8d..1b4753e 100644
--- a/src/dawn_native/ComputePipeline.cpp
+++ b/src/dawn_native/ComputePipeline.cpp
@@ -28,15 +28,15 @@
 
         // TODO(dawn:800): Remove after deprecation period.
         if (descriptor->compute.module == nullptr && descriptor->computeStage.module != nullptr) {
-            compute.module = descriptor->computeStage.module;
-            compute.entryPoint = descriptor->computeStage.entryPoint;
+            mComputeModule = descriptor->computeStage.module;
+            mEntryPoint = descriptor->computeStage.entryPoint;
         } else {
-            compute.module = descriptor->compute.module;
-            compute.entryPoint = descriptor->compute.entryPoint;
+            mComputeModule = descriptor->compute.module;
+            mEntryPoint = descriptor->compute.entryPoint;
         }
 
-        mComputeModule = compute.module;
-        mEntryPoint = compute.entryPoint;
+        compute.entryPoint = mEntryPoint.c_str();
+        compute.module = mComputeModule.Get();
     }
 
     void FlatComputePipelineDescriptor::SetLayout(Ref<PipelineLayoutBase> appliedLayout) {
diff --git a/src/tests/end2end/CreatePipelineAsyncTests.cpp b/src/tests/end2end/CreatePipelineAsyncTests.cpp
index e209eba..939794d 100644
--- a/src/tests/end2end/CreatePipelineAsyncTests.cpp
+++ b/src/tests/end2end/CreatePipelineAsyncTests.cpp
@@ -101,6 +101,40 @@
     ValidateCreateComputePipelineAsync();
 }
 
+// This is a regression test for a bug on the member "entryPoint" of FlatComputePipelineDescriptor.
+TEST_P(CreatePipelineAsyncTest, ReleaseEntryPointAfterCreatComputePipelineAsync) {
+    wgpu::ComputePipelineDescriptor csDesc;
+    csDesc.compute.module = utils::CreateShaderModule(device, R"(
+        [[block]] struct SSBO {
+            value : u32;
+        };
+        [[group(0), binding(0)]] var<storage, read_write> ssbo : SSBO;
+
+        [[stage(compute), workgroup_size(1)]] fn main() {
+            ssbo.value = 1u;
+        })");
+
+    std::string entryPoint = "main";
+
+    csDesc.compute.entryPoint = entryPoint.c_str();
+
+    device.CreateComputePipelineAsync(
+        &csDesc,
+        [](WGPUCreatePipelineAsyncStatus status, WGPUComputePipeline returnPipeline,
+           const char* message, void* userdata) {
+            EXPECT_EQ(WGPUCreatePipelineAsyncStatus::WGPUCreatePipelineAsyncStatus_Success, status);
+
+            CreatePipelineAsyncTask* task = static_cast<CreatePipelineAsyncTask*>(userdata);
+            task->computePipeline = wgpu::ComputePipeline::Acquire(returnPipeline);
+            task->isCompleted = true;
+            task->message = message;
+        },
+        &task);
+
+    entryPoint = "";
+    ValidateCreateComputePipelineAsync();
+}
+
 // Verify CreateComputePipelineAsync() works as expected when there is any error that happens during
 // the creation of the compute pipeline. The SPEC requires that during the call of
 // CreateComputePipelineAsync() any error won't be forwarded to the error scope / unhandled error