SlabAllocator: Remove dangling pointers.

The `LeakedDanglingUntriaged` was caused by "placement delete" not being
called.
The `LeakedDanglingUntriaged` was only about the ordering in between
releasing memory and clearing the pointer.

Bug: dawn:2341
Fixed: dawn:2341
Change-Id: I338189737a6862056c253e95d0161319e32a1513
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/169382
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Auto-Submit: Arthur Sonzogni <arthursonzogni@chromium.org>
diff --git a/src/dawn/common/SlabAllocator.cpp b/src/dawn/common/SlabAllocator.cpp
index f092c03..7e92555 100644
--- a/src/dawn/common/SlabAllocator.cpp
+++ b/src/dawn/common/SlabAllocator.cpp
@@ -31,7 +31,6 @@
 #include <cstdlib>
 #include <limits>
 #include <new>
-
 #include "dawn/common/Assert.h"
 #include "dawn/common/Math.h"
 
@@ -44,23 +43,26 @@
 
 // Slab
 
+SlabAllocatorImpl::Slab::Slab() = default;
 SlabAllocatorImpl::Slab::Slab(char allocation[], IndexLinkNode* head)
-    : allocation(allocation), freeList(head), prev(nullptr), next(nullptr), blocksInUse(0) {}
+    : allocation(allocation), freeList(head) {}
 
 SlabAllocatorImpl::Slab::Slab(Slab&& rhs) = default;
 
-SlabAllocatorImpl::SentinelSlab::SentinelSlab() : Slab(nullptr, nullptr) {}
+// SentinelSlab
 
+SlabAllocatorImpl::SentinelSlab::SentinelSlab() = default;
 SlabAllocatorImpl::SentinelSlab::SentinelSlab(SentinelSlab&& rhs) = default;
 
 SlabAllocatorImpl::SentinelSlab::~SentinelSlab() {
-    Slab* slab = this->next;
-    while (slab != nullptr) {
-        Slab* next = slab->next;
+    // Delete the full linked list.
+    while (next) {
+        Slab* slab = next;
+        slab->Splice();
         DAWN_ASSERT(slab->blocksInUse == 0);
-        // Delete the slab's allocation. The slab is allocated inside slab->allocation.
-        delete[] slab->allocation;
-        slab = next;
+        char* allocation = slab->allocation;
+        slab->~Slab();  // Placement delete.
+        delete allocation;
     }
 }
 
@@ -156,30 +158,22 @@
 }
 
 void SlabAllocatorImpl::SentinelSlab::Prepend(SlabAllocatorImpl::Slab* slab) {
-    if (this->next != nullptr) {
-        this->next->prev = slab;
+    if (next != nullptr) {
+        next->prev = slab;
     }
     slab->prev = this;
-    slab->next = this->next;
-    this->next = slab;
+    slab->next = next;
+    next = slab;
 }
 
 void SlabAllocatorImpl::Slab::Splice() {
-    SlabAllocatorImpl::Slab* originalPrev = this->prev;
-    SlabAllocatorImpl::Slab* originalNext = this->next;
-
-    this->prev = nullptr;
-    this->next = nullptr;
-
-    DAWN_ASSERT(originalPrev != nullptr);
-
-    // Set the originalNext's prev pointer.
-    if (originalNext != nullptr) {
-        originalNext->prev = originalPrev;
+    DAWN_ASSERT(prev != nullptr);
+    prev->next = next;
+    if (next != nullptr) {
+        next->prev = prev;
     }
-
-    // Now, set the originalNext as the originalPrev's new next.
-    originalPrev->next = originalNext;
+    prev = nullptr;
+    next = nullptr;
 }
 
 void* SlabAllocatorImpl::Allocate() {
diff --git a/src/dawn/common/SlabAllocator.h b/src/dawn/common/SlabAllocator.h
index a20718f..9196c10 100644
--- a/src/dawn/common/SlabAllocator.h
+++ b/src/dawn/common/SlabAllocator.h
@@ -91,25 +91,21 @@
 
     struct Slab : PlacementAllocated {
         // A slab is placement-allocated into an aligned pointer from a separate allocation.
-        // Ownership of the allocation is transferred to the slab on creation.
         // | ---------- allocation --------- |
         // | pad | Slab | data ------------> |
+        Slab();
         Slab(char allocation[], IndexLinkNode* head);
         Slab(Slab&& rhs);
 
+        // Extract the Slab from the linked list.
         void Splice();
 
-        // TODO(crbug.com/dawn/2341): Both pointer are dangling in
-        // `dawn_perf_tests`, and `this` is not released before the end of the
-        // test. A side effect from one test to the next might cause difficult
-        // to reproduce flakes. Test:
-        // DrawCallPerf.Run/Vulkan_llvmpipe__LLVM_16_0_6__256_bits__MultipleVertexBuffers
-        raw_ptr<char, LeakedDanglingUntriaged> allocation;
-        raw_ptr<IndexLinkNode, LeakedDanglingUntriaged> freeList;
+        raw_ptr<char> allocation = nullptr;
+        raw_ptr<IndexLinkNode> freeList = nullptr;
 
-        raw_ptr<Slab, DanglingUntriaged> prev;
-        raw_ptr<Slab, DanglingUntriaged> next;
-        Index blocksInUse;
+        raw_ptr<Slab> prev = nullptr;
+        raw_ptr<Slab> next = nullptr;
+        Index blocksInUse = 0;
     };
 
     SlabAllocatorImpl(Index blocksPerSlab, uint32_t objectSize, uint32_t objectAlignment);