[dawn][vk] Fix or triage all DAWN_UNSAFE_TODOs

DAWN_UNSAFE_TODOs could be fixed except:

 - Those that requires a Span constructor from C-style arrays.
 - DynamicUploader::WithReservation uses that need to be fixed across
   all backends at the same time.
 - GetMappedPointerImpl use that return a void* instead of a Span and
   will need to be fixed across all backends at the same time.

Bug: 439062058, 532554331, 534203108, 501491697
Change-Id: I4280583430433b635e7bb94291f38c4f80a2f0ed
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/323855
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/ResourceMemoryAllocation.cpp b/src/dawn/native/ResourceMemoryAllocation.cpp
index d733875..e52d051 100644
--- a/src/dawn/native/ResourceMemoryAllocation.cpp
+++ b/src/dawn/native/ResourceMemoryAllocation.cpp
@@ -31,14 +31,13 @@
 
 namespace dawn::native {
 
-ResourceMemoryAllocation::ResourceMemoryAllocation()
-    : mOffset(0), mResourceHeap(nullptr), mMappedPointer(nullptr) {}
+ResourceMemoryAllocation::ResourceMemoryAllocation() {}
 
 ResourceMemoryAllocation::ResourceMemoryAllocation(const AllocationInfo& info,
                                                    uint64_t offset,
                                                    ResourceHeapBase* resourceHeap,
-                                                   uint8_t* mappedPointer)
-    : mInfo(info), mOffset(offset), mResourceHeap(resourceHeap), mMappedPointer(mappedPointer) {}
+                                                   Span<std::byte> mappedSpan)
+    : mInfo(info), mOffset(offset), mResourceHeap(resourceHeap), mMappedSpan(mappedSpan) {}
 
 ResourceHeapBase* ResourceMemoryAllocation::GetResourceHeap() const {
     DAWN_ASSERT(mInfo.mMethod != AllocationMethod::kInvalid);
@@ -54,11 +53,12 @@
     return mInfo;
 }
 
-uint8_t* ResourceMemoryAllocation::GetMappedPointer() const {
-    return mMappedPointer;
+Span<std::byte> ResourceMemoryAllocation::GetMappedSpan() const {
+    return mMappedSpan;
 }
 
 void ResourceMemoryAllocation::Invalidate() {
+    mMappedSpan = {};
     mResourceHeap = nullptr;
     mInfo = {};
 }
diff --git a/src/dawn/native/ResourceMemoryAllocation.h b/src/dawn/native/ResourceMemoryAllocation.h
index 24ac4eb..f3d97b3 100644
--- a/src/dawn/native/ResourceMemoryAllocation.h
+++ b/src/dawn/native/ResourceMemoryAllocation.h
@@ -31,6 +31,7 @@
 #include <cstdint>
 
 #include "partition_alloc/pointers/raw_ptr.h"
+#include "src/utils/span.h"
 
 namespace dawn::native {
 
@@ -76,7 +77,7 @@
     ResourceMemoryAllocation(const AllocationInfo& info,
                              uint64_t offset,
                              ResourceHeapBase* resourceHeap,
-                             uint8_t* mappedPointer = nullptr);
+                             Span<std::byte> mappedSpan = {});
     virtual ~ResourceMemoryAllocation() = default;
 
     ResourceMemoryAllocation(const ResourceMemoryAllocation&) = default;
@@ -84,7 +85,7 @@
 
     ResourceHeapBase* GetResourceHeap() const;
     uint64_t GetOffset() const;
-    uint8_t* GetMappedPointer() const;
+    Span<std::byte> GetMappedSpan() const;
     AllocationInfo GetInfo() const;
 
     virtual void Invalidate();
@@ -94,8 +95,9 @@
     uint64_t mOffset = 0;
     // TODO(crbug.com/485825675): Investigate why this pointer is dangling.
     raw_ptr<ResourceHeapBase, DanglingUntriaged> mResourceHeap = nullptr;
-    // TODO(crbug.com/485825675): Investigate why this pointer is dangling.
-    raw_ptr<uint8_t, DanglingUntriaged | AllowPtrArithmetic> mMappedPointer = nullptr;
+    // TODO(https://crbug.com/526537224): Use RawSpan even if we point at driver memory that's not
+    // owned by partition_alloc.
+    Span<std::byte> mMappedSpan = {};
 };
 }  // namespace dawn::native
 
diff --git a/src/dawn/native/vulkan/BackendVk.cpp b/src/dawn/native/vulkan/BackendVk.cpp
index 51e37fa..a49853c 100644
--- a/src/dawn/native/vulkan/BackendVk.cpp
+++ b/src/dawn/native/vulkan/BackendVk.cpp
@@ -204,31 +204,33 @@
 };
 
 // Suppress validation errors that are known. Returns false in that case.
-bool ShouldReportDebugMessage(const char* messageId, const char* message) {
+bool ShouldReportDebugMessage(const char* cMessageId, const char* cMessage) {
     // If a driver gives us a nullptr pMessage (which would be a violation of the Vulkan spec)
     // then ignore this message.
-    if (message == nullptr) {
+    if (cMessage == nullptr) {
         return false;
     }
+    std::string_view message = cMessage;
 
     // Some Vulkan drivers send "error" messages of "VK_SUCCESS" when zero devices are
     // available; seen in crbug.com/1464122. This is not a real error that we care about.
     // The messageId is ignored because drivers may report
     // __FILE__: __LINE__ info here.
-    // https://github.com/Mesa3D/mesa/blob/22.2/src/amd/vulkan/radv_device.c#L1201
-    if (DAWN_UNSAFE_TODO(strcmp(message, "VK_SUCCESS")) == 0) {
+    // https://gitlab.freedesktop.org/mesa/mesa/-/blob/22.2/src/amd/vulkan/radv_device.c#L1201
+    if (message == "VK_SUCCESS") {
         return false;
     }
 
     // The Vulkan spec does allow pMessageIdName to be nullptr, but it may still contain a valid
     // message. Since we can't compare it with our skipped message list allow it through.
-    if (messageId == nullptr) {
+    if (cMessageId == nullptr) {
         return true;
     }
+    std::string_view messageId = cMessageId;
 
     for (const SkippedMessage& msg : kSkippedMessages) {
-        if (DAWN_UNSAFE_TODO(strstr(messageId, msg.messageId)) != nullptr &&
-            DAWN_UNSAFE_TODO(strstr(message, msg.messageContents)) != nullptr) {
+        if (messageId.find(msg.messageId) != std::string_view::npos &&
+            message.find(msg.messageContents) != std::string_view::npos) {
             return false;
         }
     }
@@ -272,8 +274,10 @@
     // Look through all the object labels attached to the debug message and try to parse
     // a device debug prefix out of one of them. If a debug prefix is found and matches
     // a registered device, forward the message on to it.
-    for (uint32_t i = 0; i < pCallbackData->objectCount; ++i) {
-        const VkDebugUtilsObjectNameInfoEXT& object = DAWN_UNSAFE_TODO(pCallbackData->pObjects[i]);
+    Span<const VkDebugUtilsObjectNameInfoEXT> objects =
+        // SAFETY: pObjects is defined as a pointer to objectCount VkDebugUtilsObjectNameInfoEXTs.
+        DAWN_UNSAFE_BUFFERS({pCallbackData->pObjects, pCallbackData->objectCount});
+    for (const auto& object : objects) {
         std::string deviceDebugPrefix = GetDeviceDebugPrefixFromDebugName(object.pObjectName);
         if (deviceDebugPrefix.empty()) {
             continue;
diff --git a/src/dawn/native/vulkan/BufferVk.cpp b/src/dawn/native/vulkan/BufferVk.cpp
index 02a2721..6631a21 100644
--- a/src/dawn/native/vulkan/BufferVk.cpp
+++ b/src/dawn/native/vulkan/BufferVk.cpp
@@ -328,16 +328,17 @@
             // interferes with using the UploadData() fast path.
             if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
                 DAWN_TRY(MapMemoryAndPerformOperation(
-                    0, mAllocatedSize.value(),
-                    [](std::span<uint8_t> mapped) { std::ranges::fill(mapped, 0x01); }));
+                    0, mAllocatedSize.value(), [](std::span<std::byte> mapped) {
+                        std::ranges::fill(mapped, std::byte(0x01));
+                    }));
             }
             if (device->IsToggleEnabled(Toggle::LazyClearResourceOnFirstUse) &&
                 paddingClearSize > 0) {
                 DAWN_TRY(
                     MapMemoryAndPerformOperation(paddingClearOffset, paddingClearSize,
-                                                 [&paddingClearSize](std::span<uint8_t> mapped) {
+                                                 [&paddingClearSize](std::span<std::byte> mapped) {
                                                      DAWN_CHECK(mapped.size() == paddingClearSize);
-                                                     std::ranges::fill(mapped, 0x0);
+                                                     std::ranges::fill(mapped, std::byte(0x0));
                                                  }));
             }
         } else {
@@ -561,7 +562,7 @@
 
 bool Buffer::IsCPUWritableAtCreation() const {
     // TODO(enga): Handle CPU-visible memory on UMA
-    return mMemoryAllocation.GetMappedPointer() != nullptr;
+    return mMemoryAllocation.GetMappedSpan().data() != nullptr;
 }
 
 MaybeError Buffer::MapAtCreationImpl() {
@@ -578,6 +579,7 @@
     // The real mapped pointer is never returned for zero sized buffers. MappedAtCreation buffers
     // are initialized in BufferBase already.
     if (NeedsInitialization() && GetSize() > 0 && newState == BufferState::Mapped) {
+        // TODO(https://crbug.com/501491697): Spanify GetMappedPointerImpl.
         DAWN_UNSAFE_TODO(std::memset(GetMappedPointerImpl(), 0, GetAllocatedSize()));
         GetDevice()->IncrementLazyClearCountForTesting();
         SetInitialized(true);
@@ -630,7 +632,7 @@
 }
 
 void* Buffer::GetMappedPointerImpl() {
-    uint8_t* memory = mMemoryAllocation.GetMappedPointer();
+    std::byte* memory = mMemoryAllocation.GetMappedSpan().data();
     DAWN_ASSERT(memory != nullptr);
     return memory;
 }
@@ -664,11 +666,11 @@
     uint64_t mapSize = needsZeroInitialization ? mAllocatedSize.value() : data.size();
     uint64_t mapOffset = needsZeroInitialization ? 0 : bufferOffset;
 
-    return MapMemoryAndPerformOperation(mapOffset, mapSize, [&](std::span<uint8_t> mapped) {
+    return MapMemoryAndPerformOperation(mapOffset, mapSize, [&](std::span<std::byte> mapped) {
         uint64_t dstOffset = 0;
         if (needsZeroInitialization) {
             DAWN_ASSERT(mapped.size() == mAllocatedSize);
-            std::ranges::fill(mapped, 0x0);
+            std::ranges::fill(mapped, std::byte(0x0));
             GetDevice()->IncrementLazyClearCountForTesting();
             dstOffset = bufferOffset;
         }
@@ -693,12 +695,12 @@
     DAWN_ASSERT(GetLastUsageSerial() <= device->GetQueue()->GetCompletedCommandSerial());
 
     VkDeviceMemory deviceMemory = ToBackend(mMemoryAllocation.GetResourceHeap())->GetMemory();
-    uint8_t* memory = nullptr;
+    Span<std::byte> memory;
     uint64_t realOffset = requestedOffset;
 
     if (isMappable) {
         // Mappable buffers are already persistently mapped.
-        memory = mMemoryAllocation.GetMappedPointer();
+        memory = mMemoryAllocation.GetMappedSpan();
     } else {
         // TODO(crbug.com/dawn/774): Persistently map frequently updated buffers instead of
         // mapping/unmapping each time.
@@ -717,7 +719,10 @@
         DAWN_TRY(CheckVkSuccess(device->fn.MapMemory(device->GetVkDevice(), deviceMemory, offset,
                                                      mapSize, 0, &mappedPointer),
                                 "vkMapMemory"));
-        memory = static_cast<uint8_t*>(mappedPointer);
+        // SAFETY: A successful call to vkMapMemory returns a pointer to `size` bytes of mapped
+        // data. (of the full allocation when size == VK_WHOLE_SIZE).
+        memory = DAWN_UNSAFE_BUFFERS(
+            {static_cast<std::byte*>(mappedPointer), checked_cast<size_t>(mapSize)});
     }
 
     VkMappedMemoryRange mappedMemoryRange = {};
@@ -732,7 +737,7 @@
     }
 
     // Pass a span that is exactly the offset/size requested even if a larger range was mapped.
-    op(std::span(DAWN_UNSAFE_TODO(memory + realOffset), requestedSize));
+    op(memory.subspan(realOffset, requestedSize));
 
     if (!mHostCoherent) {
         // For non-coherent memory we need to explicitly flush the memory range to make the host
diff --git a/src/dawn/native/vulkan/CommandBufferVk.cpp b/src/dawn/native/vulkan/CommandBufferVk.cpp
index 8d3be5a..9828fd0 100644
--- a/src/dawn/native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn/native/vulkan/CommandBufferVk.cpp
@@ -599,25 +599,26 @@
     switch (baseType) {
         case TextureComponentType::Float: {
             const std::array<float, 4> appliedClearColor = ConvertToFloatColor(clearColor);
-            for (uint32_t j = 0; j < 4; ++j) {
-                DAWN_UNSAFE_TODO(clearValue.color.float32[j]) = appliedClearColor[j];
-            }
+            // TODO(https://crbug.com/532554331): Use Span's constructor from C-style arrays.
+            Span<float> floatValues = DAWN_UNSAFE_TODO(Span<float>(clearValue.color.float32, 4u));
+            floatValues.CopyFrom(appliedClearColor);
             break;
         }
         case TextureComponentType::Uint: {
             const std::array<uint32_t, 4> appliedClearColor =
                 ConvertToUnsignedIntegerColor(clearColor);
-            for (uint32_t j = 0; j < 4; ++j) {
-                DAWN_UNSAFE_TODO(clearValue.color.uint32[j]) = appliedClearColor[j];
-            }
+            // TODO(https://crbug.com/532554331): Use Span's constructor from C-style arrays.
+            Span<uint32_t> u32Values =
+                DAWN_UNSAFE_TODO(Span<uint32_t>(clearValue.color.uint32, 4u));
+            u32Values.CopyFrom(appliedClearColor);
             break;
         }
         case TextureComponentType::Sint: {
             const std::array<int32_t, 4> appliedClearColor =
                 ConvertToSignedIntegerColor(clearColor);
-            for (uint32_t j = 0; j < 4; ++j) {
-                DAWN_UNSAFE_TODO(clearValue.color.int32[j]) = appliedClearColor[j];
-            }
+            // TODO(https://crbug.com/532554331): Use Span's constructor from C-style arrays.
+            Span<int32_t> i32Values = DAWN_UNSAFE_TODO(Span<int32_t>(clearValue.color.int32, 4u));
+            i32Values.CopyFrom(appliedClearColor);
             break;
         }
     }
@@ -1526,6 +1527,7 @@
 
                 Buffer* dstBuffer = ToBackend(write->buffer.Get());
 
+                // TODO(https://crbug.com/534203108): Spanify WithUploadReservation.
                 DAWN_UNSAFE_TODO(DAWN_TRY(device->GetDynamicUploader()->WithUploadReservation(
                     data.size(), kCopyBufferToBufferOffsetAlignment,
                     [&](UploadReservation reservation) -> MaybeError {
diff --git a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
index 792fa95..285cd75 100644
--- a/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
+++ b/src/dawn/native/vulkan/ResourceMemoryAllocatorVk.cpp
@@ -244,6 +244,10 @@
                            "vkMapMemory"),
             { mAllocatorsPerType[memoryType]->DeallocateResourceHeap(std::move(resourceHeap)); });
     }
+    Span<std::byte> mappedSpan =
+        // SAFETY: A successful call to vkMapMemory returns a pointer to `size` bytes of mapped
+        // data. (of the full allocation when size == VK_WHOLE_SIZE).
+        DAWN_UNSAFE_BUFFERS({static_cast<std::byte*>(mappedPointer), checked_cast<size_t>(size)});
 
     mUsedMemoryTracker->Increment(size);
     mLazyUsedMemoryTracker->Increment(isLazyMemoryType ? size : 0);
@@ -252,8 +256,7 @@
     info.mMethod = AllocationMethod::kDirect;
     info.mRequestedSize = size;
     info.mIsLazyAllocated = isLazyMemoryType;
-    return ResourceMemoryAllocation(info, /*offset*/ 0, resourceHeap.release(),
-                                    static_cast<uint8_t*>(mappedPointer));
+    return ResourceMemoryAllocation(info, /*offset*/ 0, resourceHeap.release(), mappedSpan);
 }
 
 void ResourceMemoryAllocator::Deallocate(ResourceMemoryAllocation* allocation) {
diff --git a/src/dawn/native/vulkan/ResourceTableVk.cpp b/src/dawn/native/vulkan/ResourceTableVk.cpp
index 5f62c69..e06bce3 100644
--- a/src/dawn/native/vulkan/ResourceTableVk.cpp
+++ b/src/dawn/native/vulkan/ResourceTableVk.cpp
@@ -231,6 +231,7 @@
     Device* device = ToBackend(GetDevice());
 
     // Allocate enough space for all the data to modify and schedule the copies.
+    // TODO(https://crbug.com/534203108): Spanify WithUploadReservation.
     return device->GetDynamicUploader()->WithUploadReservation(
         sizeof(uint32_t) * updates.size(), kCopyBufferToBufferOffsetAlignment,
         [&](UploadReservation reservation) -> MaybeError {
diff --git a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
index 4e5eda7..6764893 100644
--- a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
+++ b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
@@ -858,20 +858,21 @@
         "which is required for view format reinterpretation.");
 
     if (imageFormatListInfo && mayNeedViewReinterpretation) {
-        auto viewFormatsBegin = imageFormatListInfo->pViewFormats;
-        auto viewFormatsEnd = DAWN_UNSAFE_TODO(imageFormatListInfo->pViewFormats +
-                                               imageFormatListInfo->viewFormatCount);
+        // SAFETY: Vulkan requires that pViewFormats point at viewFormatCount valid formats and the
+        // application giving us its VkImageCreateInfo needs to conform to that.
+        Span<const VkFormat> viewFormats = DAWN_UNSAFE_BUFFERS(
+            {imageFormatListInfo->pViewFormats, imageFormatListInfo->viewFormatCount});
         VkFormat baseVkFormat = VulkanImageFormat(device, properties.format);
 
         DAWN_INVALID_IF(
-            std::find(viewFormatsBegin, viewFormatsEnd, baseVkFormat) == viewFormatsEnd,
+            std::ranges::find(viewFormats, baseVkFormat) == viewFormats.end(),
             "VkImageFormatCreateInfo did not contain VkFormat 0x%x which may be required to "
             "create a texture view with %s.",
             baseVkFormat, properties.format);
 
         for (const auto* f : compatibleViewFormats) {
             VkFormat vkFormat = VulkanImageFormat(device, f->format);
-            DAWN_INVALID_IF(std::find(viewFormatsBegin, viewFormatsEnd, vkFormat) == viewFormatsEnd,
+            DAWN_INVALID_IF(std::ranges::find(viewFormats, vkFormat) == viewFormats.end(),
                             "VkImageFormatCreateInfo did not contain VkFormat 0x%x which may be "
                             "required to create a texture view with %s.",
                             vkFormat, f->format);
diff --git a/src/dawn/native/vulkan/SwapChainVk.cpp b/src/dawn/native/vulkan/SwapChainVk.cpp
index 7b43f38..7aeb73b 100644
--- a/src/dawn/native/vulkan/SwapChainVk.cpp
+++ b/src/dawn/native/vulkan/SwapChainVk.cpp
@@ -32,6 +32,7 @@
 #include <utility>
 
 #include "src/dawn/common/Compiler.h"
+#include "src/dawn/common/Range.h"
 #include "src/dawn/native/ChainUtils.h"
 #include "src/dawn/native/Instance.h"
 #include "src/dawn/native/Surface.h"
@@ -309,16 +310,15 @@
         "Vulkan SwapChain must support opaque alpha.");
 #else
     // TODO(dawn:286): investigate composite alpha for WebGPU native
-    VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[4] = {
+    std::array<VkCompositeAlphaFlagBitsKHR, 4u> compositeAlphaFlags = {
         VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
         VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
         VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
         VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
     };
-    for (uint32_t i = 0; i < 4; i++) {
-        if (surfaceInfo.capabilities.supportedCompositeAlpha &
-            DAWN_UNSAFE_TODO(compositeAlphaFlags[i])) {
-            config.alphaMode = DAWN_UNSAFE_TODO(compositeAlphaFlags[i]);
+    for (uint32_t i : Range(4u)) {
+        if (surfaceInfo.capabilities.supportedCompositeAlpha & compositeAlphaFlags[i]) {
+            config.alphaMode = compositeAlphaFlags[i];
             break;
         }
     }
diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp
index fc12bd0..0ac2cd9 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -1337,6 +1337,7 @@
             blocksPerRow * largestMipSize.height * largestMipSize.depthOrArrayLayers;
         uint64_t uploadSize = blockInfo.ToBytes(uploadBlocks);
 
+        // TODO(https://crbug.com/534203108): Spanify WithUploadReservation.
         DAWN_UNSAFE_TODO(DAWN_TRY(device->GetDynamicUploader()->WithUploadReservation(
             uploadSize, blockInfo.byteSize, [&](UploadReservation reservation) -> MaybeError {
                 memset(reservation.mappedPointer, sign_dcast(uClearColor), uploadSize);
diff --git a/src/dawn/native/vulkan/UtilsVulkan.cpp b/src/dawn/native/vulkan/UtilsVulkan.cpp
index f3c152f..0d0bdc8 100644
--- a/src/dawn/native/vulkan/UtilsVulkan.cpp
+++ b/src/dawn/native/vulkan/UtilsVulkan.cpp
@@ -347,24 +347,23 @@
     return objectName.str();
 }
 
-std::string GetDeviceDebugPrefixFromDebugName(const char* debugName) {
-    if (debugName == nullptr) {
+std::string GetDeviceDebugPrefixFromDebugName(const char* cDebugName) {
+    if (cDebugName == nullptr) {
         return {};
     }
 
-    if (DAWN_UNSAFE_TODO(strncmp(debugName, kDeviceDebugPrefix, sizeof(kDeviceDebugPrefix) - 1)) !=
-        0) {
+    std::string_view debugName = cDebugName;
+
+    if (debugName.starts_with(kDeviceDebugPrefix)) {
         return {};
     }
 
-    const char* separator =
-        DAWN_UNSAFE_TODO(strstr(debugName + sizeof(kDeviceDebugPrefix), kDeviceDebugSeparator));
-    if (separator == nullptr) {
+    size_t separatorIndex = debugName.find(kDeviceDebugSeparator);
+    if (separatorIndex == std::string_view::npos) {
         return {};
     }
 
-    size_t length = sign_cast(separator - debugName);
-    return std::string(debugName, length);
+    return std::string(debugName.substr(0u, separatorIndex));
 }
 
 std::string FormatAPIVersion(uint32_t version) {
diff --git a/src/dawn/native/vulkan/VulkanInfo.cpp b/src/dawn/native/vulkan/VulkanInfo.cpp
index 8e30013..ee9a383 100644
--- a/src/dawn/native/vulkan/VulkanInfo.cpp
+++ b/src/dawn/native/vulkan/VulkanInfo.cpp
@@ -175,10 +175,16 @@
         VkPhysicalDeviceMemoryProperties memory;
         vkFunctions.GetPhysicalDeviceMemoryProperties(vkPhysicalDevice, &memory);
 
-        info.memoryTypes.assign(memory.memoryTypes,
-                                DAWN_UNSAFE_TODO(memory.memoryTypes + memory.memoryTypeCount));
-        info.memoryHeaps.assign(memory.memoryHeaps,
-                                DAWN_UNSAFE_TODO(memory.memoryHeaps + memory.memoryHeapCount));
+        // TODO(https://crbug.com/532554331): Use Span's constructor from C-style arrays.
+        Span<const VkMemoryType> driverMemoryTypes =
+            DAWN_UNSAFE_TODO(Span<const VkMemoryType>(memory.memoryTypes, VK_MAX_MEMORY_TYPES))
+                .first(memory.memoryTypeCount);
+        Span<const VkMemoryHeap> driverMemoryHeaps =
+            DAWN_UNSAFE_TODO(Span<const VkMemoryHeap>(memory.memoryHeaps, VK_MAX_MEMORY_HEAPS))
+                .first(memory.memoryHeapCount);
+
+        info.memoryTypes.assign(driverMemoryTypes.begin(), driverMemoryTypes.end());
+        info.memoryHeaps.assign(driverMemoryHeaps.begin(), driverMemoryHeaps.end());
     }
 
     // Gather info about device queue families
diff --git a/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp b/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp
index 9f6d761..978b4d8 100644
--- a/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp
+++ b/src/dawn/native/vulkan/external_memory/MemoryServiceImplementationDmaBuf.cpp
@@ -354,14 +354,11 @@
 
         std::array<VkSubresourceLayout, ExternalImageDescriptorDmaBuf::kMaxPlanes> planeLayouts;
         for (uint32_t plane = 0u; plane < planeCount; ++plane) {
-            DAWN_UNSAFE_TODO(planeLayouts[plane]).offset =
-                dmaBufDescriptor->planeLayouts[plane].offset;
-            DAWN_UNSAFE_TODO(planeLayouts[plane]).size =
-                0;  // VK_EXT_image_drm_format_modifier mandates size = 0.
-            DAWN_UNSAFE_TODO(planeLayouts[plane]).rowPitch =
-                dmaBufDescriptor->planeLayouts[plane].stride;
-            DAWN_UNSAFE_TODO(planeLayouts[plane]).arrayPitch = 0;  // Not an array texture
-            DAWN_UNSAFE_TODO(planeLayouts[plane]).depthPitch = 0;  // Not a depth texture
+            planeLayouts[plane].offset = dmaBufDescriptor->planeLayouts[plane].offset;
+            planeLayouts[plane].size = 0;  // VK_EXT_image_drm_format_modifier mandates size = 0.
+            planeLayouts[plane].rowPitch = dmaBufDescriptor->planeLayouts[plane].stride;
+            planeLayouts[plane].arrayPitch = 0;  // Not an array texture
+            planeLayouts[plane].depthPitch = 0;  // Not a depth texture
         }
 
         VkImageDrmFormatModifierExplicitCreateInfoEXT explicitCreateInfo = {};