Null backend: disallow more than 256M of Buffer allocations

Should prevent some uninteresting fuzzer failures.

Bug: dawn:37
Change-Id: I6b2bef01deb700239e02ef5afa9313023ec83899
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7483
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/null/DeviceNull.cpp b/src/dawn_native/null/DeviceNull.cpp
index eeaae7e..95904d3 100644
--- a/src/dawn_native/null/DeviceNull.cpp
+++ b/src/dawn_native/null/DeviceNull.cpp
@@ -68,6 +68,10 @@
 
     Device::~Device() {
         mDynamicUploader = nullptr;
+
+        // Ensure any in-flight maps have been cleaned up.
+        SubmitPendingOperations();
+        ASSERT(mMemoryUsage == 0);
     }
 
     ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
@@ -79,6 +83,7 @@
         return new BindGroupLayout(this, descriptor);
     }
     ResultOrError<BufferBase*> Device::CreateBufferImpl(const BufferDescriptor* descriptor) {
+        DAWN_TRY(IncrementMemoryUsage(descriptor->size));
         return new Buffer(this, descriptor);
     }
     CommandBufferBase* Device::CreateCommandBuffer(CommandEncoderBase* encoder) {
@@ -138,6 +143,20 @@
         return DAWN_UNIMPLEMENTED_ERROR("Device unable to copy from staging buffer.");
     }
 
+    MaybeError Device::IncrementMemoryUsage(size_t bytes) {
+        static_assert(kMaxMemoryUsage <= std::numeric_limits<size_t>::max() / 2, "");
+        if (bytes > kMaxMemoryUsage || mMemoryUsage + bytes > kMaxMemoryUsage) {
+            return DAWN_CONTEXT_LOST_ERROR("Out of memory.");
+        }
+        mMemoryUsage += bytes;
+        return {};
+    }
+
+    void Device::DecrementMemoryUsage(size_t bytes) {
+        ASSERT(mMemoryUsage >= bytes);
+        mMemoryUsage -= bytes;
+    }
+
     Serial Device::GetCompletedCommandSerial() const {
         return mCompletedSerial;
     }
@@ -189,6 +208,8 @@
     }
 
     Buffer::~Buffer() {
+        DestroyInternal();
+        ToBackend(GetDevice())->DecrementMemoryUsage(GetSize());
     }
 
     MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) {
diff --git a/src/dawn_native/null/DeviceNull.h b/src/dawn_native/null/DeviceNull.h
index 0c770fc..da5beff 100644
--- a/src/dawn_native/null/DeviceNull.h
+++ b/src/dawn_native/null/DeviceNull.h
@@ -102,6 +102,9 @@
                                            uint64_t destinationOffset,
                                            uint64_t size) override;
 
+        MaybeError IncrementMemoryUsage(size_t bytes);
+        void DecrementMemoryUsage(size_t bytes);
+
       private:
         ResultOrError<BindGroupBase*> CreateBindGroupImpl(
             const BindGroupDescriptor* descriptor) override;
@@ -128,6 +131,9 @@
         Serial mCompletedSerial = 0;
         Serial mLastSubmittedSerial = 0;
         std::vector<std::unique_ptr<PendingOperation>> mPendingOperations;
+
+        static constexpr size_t kMaxMemoryUsage = 256 * 1024 * 1024;
+        size_t mMemoryUsage = 0;
     };
 
     class Buffer : public BufferBase {