[libcxx-commits] [libcxx] ee2a92c - [libcxx] Remove VLA from libcxx locale header

Abhina Sreeskantharajan via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jun 8 10:59:45 PDT 2021


Author: Daniel McIntosh
Date: 2021-06-08T13:59:34-04:00
New Revision: ee2a92c29df6d37a4dc5d0f6795f0fe531962b9d

URL: https://github.com/llvm/llvm-project/commit/ee2a92c29df6d37a4dc5d0f6795f0fe531962b9d
DIFF: https://github.com/llvm/llvm-project/commit/ee2a92c29df6d37a4dc5d0f6795f0fe531962b9d.diff

LOG: [libcxx] Remove VLA from libcxx locale header

The buffer size (`__nbuf`) in `num_put::do_put` is currently not an
integral/core constant expression. As a result, `__nar` is a Variable Length
Array (VLA). VLAs are a GNU extension and not part of the base C++ standard, so
unless there is good reason to do so they probably shouldn't be used in any of
the standard library headers. The call to `__iob.flags()` is the only thing
keeping `__nbuf` from being a compile time constant, so the solution here is to
simply err on the side of caution and always allocate a buffer large enough to
fit the base prefix.

Note that, while the base prefix for hex (`0x`) is slightly longer than the
base prefix for octal (`0`), this isn't a concern. The difference in the space
needed for the value portion of the string is enough to make up for this.
(Unless we're working with small, oddly sized types such as a hypothetical
`uint9_t`, the space needed for the value portion in octal is at least 1 more
than the space needed for the value portion in hex).

This PR also adds `constexpr` to `__nbuf` to enforce compile time const-ness
going forward.

Reviewed By: Mordante, #libc, Quuxplusone, ldionne

Differential Revision: https://reviews.llvm.org/D103558

Added: 
    

Modified: 
    libcxx/include/locale

Removed: 
    


################################################################################
diff  --git a/libcxx/include/locale b/libcxx/include/locale
index 49d76839d9c9..8e584005da08 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -1460,10 +1460,10 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
     this->__format_int(__fmt+1, __len, true, __iob.flags());
     // Worst case is octal, with showbase enabled. Note that octal is always
     // printed as an unsigned value.
-    const unsigned __nbuf = (numeric_limits<unsigned long>::digits / 3)          // 1 char per 3 bits
-                            + ((numeric_limits<unsigned long>::digits % 3) != 0) // round up
-                            + ((__iob.flags() & ios_base::showbase) != 0)        // base prefix
-                            + 1;                                                 // terminating null character
+    _LIBCPP_CONSTEXPR const unsigned __nbuf
+        = (numeric_limits<unsigned long>::digits / 3)        // 1 char per 3 bits
+        + ((numeric_limits<unsigned long>::digits % 3) != 0) // round up
+        + 2; // base prefix + terminating null character
     char __nar[__nbuf];
     int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
     char* __ne = __nar + __nc;
@@ -1489,10 +1489,10 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
     this->__format_int(__fmt+1, __len, true, __iob.flags());
     // Worst case is octal, with showbase enabled. Note that octal is always
     // printed as an unsigned value.
-    const unsigned __nbuf = (numeric_limits<unsigned long long>::digits / 3)          // 1 char per 3 bits
-                            + ((numeric_limits<unsigned long long>::digits % 3) != 0) // round up
-                            + ((__iob.flags() & ios_base::showbase) != 0)             // base prefix
-                            + 1;                                                      // terminating null character
+    _LIBCPP_CONSTEXPR const unsigned __nbuf
+        = (numeric_limits<unsigned long long>::digits / 3)        // 1 char per 3 bits
+        + ((numeric_limits<unsigned long long>::digits % 3) != 0) // round up
+        + 2; // base prefix + terminating null character
     char __nar[__nbuf];
     int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
     char* __ne = __nar + __nc;
@@ -1517,10 +1517,10 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
     const char* __len = "l";
     this->__format_int(__fmt+1, __len, false, __iob.flags());
     // Worst case is octal, with showbase enabled.
-    const unsigned __nbuf = (numeric_limits<unsigned long>::digits / 3)          // 1 char per 3 bits
-                            + ((numeric_limits<unsigned long>::digits % 3) != 0) // round up
-                            + ((__iob.flags() & ios_base::showbase) != 0)        // base prefix
-                            + 1;                                                 // terminating null character
+    _LIBCPP_CONSTEXPR const unsigned __nbuf
+        = (numeric_limits<unsigned long>::digits / 3)        // 1 char per 3 bits
+        + ((numeric_limits<unsigned long>::digits % 3) != 0) // round up
+        + 2; // base prefix + terminating null character
     char __nar[__nbuf];
     int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
     char* __ne = __nar + __nc;
@@ -1545,10 +1545,10 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
     const char* __len = "ll";
     this->__format_int(__fmt+1, __len, false, __iob.flags());
     // Worst case is octal, with showbase enabled.
-    const unsigned __nbuf = (numeric_limits<unsigned long long>::digits / 3)          // 1 char per 3 bits
-                            + ((numeric_limits<unsigned long long>::digits % 3) != 0) // round up
-                            + ((__iob.flags() & ios_base::showbase) != 0)             // base prefix
-                            + 1;                                                      // terminating null character
+    _LIBCPP_CONSTEXPR const unsigned __nbuf
+        = (numeric_limits<unsigned long long>::digits / 3)        // 1 char per 3 bits
+        + ((numeric_limits<unsigned long long>::digits % 3) != 0) // round up
+        + 2; // base prefix + terminating null character
     char __nar[__nbuf];
     int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
     char* __ne = __nar + __nc;


        


More information about the libcxx-commits mailing list