[libcxxabi] [llvm] [libcxxabi] Fix PODSmallVector zero-capacity growth (PR #215386)

Zaara Syeda via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 11 14:55:18 PDT 2026


https://github.com/syzaara updated https://github.com/llvm/llvm-project/pull/215386

>From 7b69185d7914be6232140d174c932051af7830d4 Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at ca.ibm.com>
Date: Mon, 10 Aug 2026 16:25:37 -0400
Subject: [PATCH 1/3] [libcxxabi] Fix PODSmallVector zero-capacity growth

Fix PODSmallVector growth for PODSmallVector<T, 0>. Since the initial capacity
is zero, the first growth attempts reserve(0), which does not increase the
capacity. Allocate space for at least one element on the initial growth.
---
 libcxxabi/src/demangle/ItaniumDemangle.h     | 3 ++-
 libcxxabi/test/unittest_demangle.pass.cpp    | 7 +++++++
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 3 ++-
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 2ae943e1998f1..e24941987eecc 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -123,7 +123,7 @@ template <class T, size_t N> class PODSmallVector {
   // NOLINTNEXTLINE(readability-identifier-naming)
   void push_back(const T &Elem) {
     if (Last == Cap)
-      reserve(size() * 2);
+      reserve(std::max<size_t>(1, size() * 2));
     *Last++ = Elem;
   }
 
@@ -143,6 +143,7 @@ template <class T, size_t N> class PODSmallVector {
 
   bool empty() const { return First == Last; }
   size_t size() const { return static_cast<size_t>(Last - First); }
+  size_t capacity() const { return static_cast<size_t>(Cap - First); }
   T &back() {
     DEMANGLE_ASSERT(Last != First, "Calling back() on empty vector!");
     return *(Last - 1);
diff --git a/libcxxabi/test/unittest_demangle.pass.cpp b/libcxxabi/test/unittest_demangle.pass.cpp
index 3f86e9c49a8a5..5df4f1d0cf62c 100644
--- a/libcxxabi/test/unittest_demangle.pass.cpp
+++ b/libcxxabi/test/unittest_demangle.pass.cpp
@@ -81,6 +81,13 @@ void testPODSmallVector() {
       (void)x;
     }
   }
+
+  {
+    itanium_demangle::PODSmallVector<int, 0> PSV;
+    PSV.push_back(10);
+    assert(PSV.size() == 1);
+    assert(PSV.capacity() >= PSV.size());
+  }
 }
 
 int main(int, char**) {
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 0f1deb3d710e2..6187926907176 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -123,7 +123,7 @@ template <class T, size_t N> class PODSmallVector {
   // NOLINTNEXTLINE(readability-identifier-naming)
   void push_back(const T &Elem) {
     if (Last == Cap)
-      reserve(size() * 2);
+      reserve(std::max<size_t>(1, size() * 2));
     *Last++ = Elem;
   }
 
@@ -143,6 +143,7 @@ template <class T, size_t N> class PODSmallVector {
 
   bool empty() const { return First == Last; }
   size_t size() const { return static_cast<size_t>(Last - First); }
+  size_t capacity() const { return static_cast<size_t>(Cap - First); }
   T &back() {
     DEMANGLE_ASSERT(Last != First, "Calling back() on empty vector!");
     return *(Last - 1);

>From f7439f85c84db36efa33021e96a20cfcbbf57ca6 Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at ca.ibm.com>
Date: Mon, 10 Aug 2026 17:42:17 -0400
Subject: [PATCH 2/3] Address review comments

---
 libcxxabi/src/demangle/ItaniumDemangle.h     | 2 +-
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index e24941987eecc..0db933b3314bc 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -123,7 +123,7 @@ template <class T, size_t N> class PODSmallVector {
   // NOLINTNEXTLINE(readability-identifier-naming)
   void push_back(const T &Elem) {
     if (Last == Cap)
-      reserve(std::max<size_t>(1, size() * 2));
+      reserve(N == 0 && size() == 0 ? 1 : size() * 2);
     *Last++ = Elem;
   }
 
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 6187926907176..8b410dd8b1d6a 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -123,7 +123,7 @@ template <class T, size_t N> class PODSmallVector {
   // NOLINTNEXTLINE(readability-identifier-naming)
   void push_back(const T &Elem) {
     if (Last == Cap)
-      reserve(std::max<size_t>(1, size() * 2));
+      reserve(N == 0 && size() == 0 ? 1 : size() * 2);
     *Last++ = Elem;
   }
 

>From 3eaa0c8786060e5ff57739ff5546dc2cff40334e Mon Sep 17 00:00:00 2001
From: Zaara Syeda <syzaara at ca.ibm.com>
Date: Tue, 11 Aug 2026 17:54:53 -0400
Subject: [PATCH 3/3] Address review comments

---
 libcxxabi/src/demangle/ItaniumDemangle.h     | 3 ++-
 libcxxabi/test/unittest_demangle.pass.cpp    | 7 -------
 llvm/include/llvm/Demangle/ItaniumDemangle.h | 3 ++-
 3 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/libcxxabi/src/demangle/ItaniumDemangle.h b/libcxxabi/src/demangle/ItaniumDemangle.h
index 0db933b3314bc..c3d2dbf32ac28 100644
--- a/libcxxabi/src/demangle/ItaniumDemangle.h
+++ b/libcxxabi/src/demangle/ItaniumDemangle.h
@@ -43,6 +43,7 @@ template <class T, size_t N> class PODSmallVector {
                 "T is required to be a trivially copyable type");
   static_assert(std::is_trivially_default_constructible<T>::value,
                 "T is required to be trivially default constructible");
+  static_assert(N > 0, "PODSmallVector requires a non-zero inline capacity");
   T *First = nullptr;
   T *Last = nullptr;
   T *Cap = nullptr;
@@ -123,7 +124,7 @@ template <class T, size_t N> class PODSmallVector {
   // NOLINTNEXTLINE(readability-identifier-naming)
   void push_back(const T &Elem) {
     if (Last == Cap)
-      reserve(N == 0 && size() == 0 ? 1 : size() * 2);
+      reserve(size() * 2);
     *Last++ = Elem;
   }
 
diff --git a/libcxxabi/test/unittest_demangle.pass.cpp b/libcxxabi/test/unittest_demangle.pass.cpp
index 5df4f1d0cf62c..3f86e9c49a8a5 100644
--- a/libcxxabi/test/unittest_demangle.pass.cpp
+++ b/libcxxabi/test/unittest_demangle.pass.cpp
@@ -81,13 +81,6 @@ void testPODSmallVector() {
       (void)x;
     }
   }
-
-  {
-    itanium_demangle::PODSmallVector<int, 0> PSV;
-    PSV.push_back(10);
-    assert(PSV.size() == 1);
-    assert(PSV.capacity() >= PSV.size());
-  }
 }
 
 int main(int, char**) {
diff --git a/llvm/include/llvm/Demangle/ItaniumDemangle.h b/llvm/include/llvm/Demangle/ItaniumDemangle.h
index 8b410dd8b1d6a..3aecb3042268b 100644
--- a/llvm/include/llvm/Demangle/ItaniumDemangle.h
+++ b/llvm/include/llvm/Demangle/ItaniumDemangle.h
@@ -43,6 +43,7 @@ template <class T, size_t N> class PODSmallVector {
                 "T is required to be a trivially copyable type");
   static_assert(std::is_trivially_default_constructible<T>::value,
                 "T is required to be trivially default constructible");
+  static_assert(N > 0, "PODSmallVector requires a non-zero inline capacity");
   T *First = nullptr;
   T *Last = nullptr;
   T *Cap = nullptr;
@@ -123,7 +124,7 @@ template <class T, size_t N> class PODSmallVector {
   // NOLINTNEXTLINE(readability-identifier-naming)
   void push_back(const T &Elem) {
     if (Last == Cap)
-      reserve(N == 0 && size() == 0 ? 1 : size() * 2);
+      reserve(size() * 2);
     *Last++ = Elem;
   }
 



More information about the llvm-commits mailing list