[gardening] Fix VM zone allocator assertion and size accounting

When reallocating a piece of memory that was just allocated one can
re-allocate to larger or smaller new size.

The latter was disallowed by an assertion, which seems like a bug.

Closes https://github.com/dart-lang/sdk/issues/50060

TEST=vm/cc/ZoneRealloc

Change-Id: Iee9f72fead285fb8150ba8639b6de655afc515ba
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/261340
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index d5abb3b..c38cc45 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -310,9 +310,8 @@
           reinterpret_cast<uword>(old_data) + (new_len * kElementSize);
       // ...and there is sufficient space.
       if (new_end <= limit_) {
-        ASSERT(new_len >= old_len);
         position_ = Utils::RoundUp(new_end, kAlignment);
-        size_ += (new_end - old_end);
+        size_ += static_cast<intptr_t>(new_len - old_len);
         return old_data;
       }
     }
diff --git a/runtime/vm/zone_test.cc b/runtime/vm/zone_test.cc
index 9231cda..13ca394 100644
--- a/runtime/vm/zone_test.cc
+++ b/runtime/vm/zone_test.cc
@@ -111,6 +111,28 @@
   Dart_ShutdownIsolate();
 }
 
+VM_UNIT_TEST_CASE(ZoneRealloc) {
+  TestCase::CreateTestIsolate();
+  Thread* thread = Thread::Current();
+  {
+    TransitionNativeToVM transition(thread);
+    StackZone stack_zone(thread);
+    auto zone = thread->zone();
+
+    const intptr_t kOldLen = 32;
+    const intptr_t kNewLen = 16;
+    const intptr_t kNewLen2 = 16;
+
+    auto data_old = zone->Alloc<uint8_t>(kOldLen);
+    auto data_new = zone->Realloc<uint8_t>(data_old, kOldLen, kNewLen);
+    RELEASE_ASSERT(data_old == data_new);
+
+    auto data_new2 = zone->Realloc<uint8_t>(data_old, kNewLen, kNewLen2);
+    RELEASE_ASSERT(data_old == data_new2);
+  }
+  Dart_ShutdownIsolate();
+}
+
 VM_UNIT_TEST_CASE(ZoneAllocated) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;