forked from OSchip/llvm-project
[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
This commit is contained in:
parent
4d680b06c9
commit
ee2a92c29d
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue