From 8a68537de2a9761277b28f67f3b5e31d0db5d644 Mon Sep 17 00:00:00 2001
From: Austin Eng <enga@chromium.org>
Date: Tue, 22 Nov 2022 13:34:06 +0000
Subject: [PATCH] Check buffer state is not destroyed before internally calling
 unmap

Calling UnmapInternal would set the state to Unmapped, allowing the
buffer to be mapped again even though it is destroyed.

Bug: chromium:1388920
Change-Id: Ibb4da332bafd44a0d4900c8ea5bfbd674bbc35e0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/111121
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
---
 src/dawn/native/Buffer.cpp                       |  3 +++
 .../validation/BufferValidationTests.cpp         | 16 ++++++++++++++++
 2 files changed, 19 insertions(+)

diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp
index 87db6ac7c0..fd13a3c82f 100644
--- a/src/dawn/native/Buffer.cpp
+++ b/src/dawn/native/Buffer.cpp
@@ -422,6 +422,9 @@ void BufferBase::APIUnmap() {
 }
 
 void BufferBase::Unmap() {
+    if (mState == BufferState::Destroyed) {
+        return;
+    }
     UnmapInternal(WGPUBufferMapAsyncStatus_UnmappedBeforeCallback);
 }
 
diff --git a/src/dawn/tests/unittests/validation/BufferValidationTests.cpp b/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
index c943c4e820..3b2f3ae5e5 100644
--- a/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/BufferValidationTests.cpp
@@ -528,6 +528,22 @@ TEST_F(BufferValidationTest, UnmapDestroyedBuffer) {
     }
 }
 
+// Test that unmap then mapping a destroyed buffer is an error.
+// Regression test for crbug.com/1388920.
+TEST_F(BufferValidationTest, MapDestroyedBufferAfterUnmap) {
+    wgpu::Buffer buffer = CreateMapReadBuffer(4);
+    buffer.Destroy();
+    buffer.Unmap();
+
+    ASSERT_DEVICE_ERROR(buffer.MapAsync(
+        wgpu::MapMode::Read, 0, wgpu::kWholeMapSize,
+        [](WGPUBufferMapAsyncStatus status, void* userdata) {
+            EXPECT_EQ(WGPUBufferMapAsyncStatus_Error, status);
+        },
+        nullptr));
+    WaitForAllOperations(device);
+}
+
 // Test that it is valid to submit a buffer in a queue with a map usage if it is unmapped
 TEST_F(BufferValidationTest, SubmitBufferWithMapUsage) {
     wgpu::BufferDescriptor descriptorA;