summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dimitry@andric.com>2017-05-06 20:58:50 +0000
committerDimitry Andric <dimitry@andric.com>2017-05-06 20:58:50 +0000
commit52844c83d0630c748b434f26bcd8a43e48bca9d3 (patch)
treeb4d0556676f5bec30635d3aee364929d4d8e610d
parent33f7397cc0582f3a842cc4cba5fec605c3a09e48 (diff)
downloadbcm5719-llvm-52844c83d0630c748b434f26bcd8a43e48bca9d3.tar.gz
bcm5719-llvm-52844c83d0630c748b434f26bcd8a43e48bca9d3.zip
Ensure showbase does not overflow do_put buffers
Summary: In https://bugs.freebsd.org/207918, Daniel McRobb describes how using std::showbase with ostreams can cause truncation of unsigned long long when output format is octal. In fact, this can even happen with unsigned int and unsigned long. To ensure this does not happen, add one additional character to the do_put buffers if std::showbase is on. Also add a test case. Reviewers: EricWF, mclow.lists Reviewed By: EricWF Subscribers: cfe-commits, emaste Differential Revision: https://reviews.llvm.org/D32670 llvm-svn: 302362
-rw-r--r--libcxx/include/locale4
-rw-r--r--libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp97
2 files changed, 101 insertions, 0 deletions
diff --git a/libcxx/include/locale b/libcxx/include/locale
index d0909d58c91..f0e1c3b82ce 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -1402,6 +1402,7 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
this->__format_int(__fmt+1, __len, true, __iob.flags());
const unsigned __nbuf = (numeric_limits<long>::digits / 3)
+ ((numeric_limits<long>::digits % 3) != 0)
+ + ((__iob.flags() & ios_base::showbase) != 0)
+ 2;
char __nar[__nbuf];
int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
@@ -1428,6 +1429,7 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
this->__format_int(__fmt+1, __len, true, __iob.flags());
const unsigned __nbuf = (numeric_limits<long long>::digits / 3)
+ ((numeric_limits<long long>::digits % 3) != 0)
+ + ((__iob.flags() & ios_base::showbase) != 0)
+ 2;
char __nar[__nbuf];
int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
@@ -1454,6 +1456,7 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
this->__format_int(__fmt+1, __len, false, __iob.flags());
const unsigned __nbuf = (numeric_limits<unsigned long>::digits / 3)
+ ((numeric_limits<unsigned long>::digits % 3) != 0)
+ + ((__iob.flags() & ios_base::showbase) != 0)
+ 1;
char __nar[__nbuf];
int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
@@ -1480,6 +1483,7 @@ num_put<_CharT, _OutputIterator>::do_put(iter_type __s, ios_base& __iob,
this->__format_int(__fmt+1, __len, false, __iob.flags());
const unsigned __nbuf = (numeric_limits<unsigned long long>::digits / 3)
+ ((numeric_limits<unsigned long long>::digits % 3) != 0)
+ + ((__iob.flags() & ios_base::showbase) != 0)
+ 1;
char __nar[__nbuf];
int __nc = __libcpp_snprintf_l(__nar, sizeof(__nar), _LIBCPP_GET_C_LOCALE, __fmt, __v);
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp
new file mode 100644
index 00000000000..956cd171a1d
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// <ostream>
+
+// template <class charT, class traits = char_traits<charT> >
+// class basic_ostream;
+
+// operator<<(short n);
+// operator<<(unsigned short n);
+// operator<<(int n);
+// operator<<(unsigned int n);
+// operator<<(long n);
+// operator<<(unsigned long n);
+// operator<<(long long n);
+// operator<<(unsigned long long n);
+
+// Testing to make sure that the max length values are correctly inserted when
+// using std::showbase
+
+#include <cassert>
+#include <cstdint>
+#include <ios>
+#include <limits>
+#include <sstream>
+#include <type_traits>
+
+template <typename T>
+static void test(std::ios_base::fmtflags fmt, const char *expected)
+{
+ std::stringstream ss;
+ ss.setf(fmt, std::ios_base::basefield);
+ ss << std::showbase << (std::is_signed<T>::value ? std::numeric_limits<T>::min() : std::numeric_limits<T>::max());
+ assert(ss.str() == expected);
+}
+
+int main(void)
+{
+ const std::ios_base::fmtflags o = std::ios_base::oct;
+ const std::ios_base::fmtflags d = std::ios_base::dec;
+ const std::ios_base::fmtflags x = std::ios_base::hex;
+
+ test<short>(o, "0100000");
+ test<short>(d, "-32768");
+ test<short>(x, "0x8000");
+
+ test<unsigned short>(o, "0177777");
+ test<unsigned short>(d, "65535");
+ test<unsigned short>(x, "0xffff");
+
+ test<int>(o, "020000000000");
+ test<int>(d, "-2147483648");
+ test<int>(x, "0x80000000");
+
+ test<unsigned int>(o, "037777777777");
+ test<unsigned int>(d, "4294967295");
+ test<unsigned int>(x, "0xffffffff");
+
+ const bool long_is_32 = std::integral_constant<bool, sizeof(long) == sizeof(int32_t)>::value; // avoid compiler warnings
+ const bool long_is_64 = std::integral_constant<bool, sizeof(long) == sizeof(int64_t)>::value; // avoid compiler warnings
+ const bool long_long_is_64 = std::integral_constant<bool, sizeof(long long) == sizeof(int64_t)>::value; // avoid compiler warnings
+
+ if (long_is_32) {
+ test<long>(o, "020000000000");
+ test<long>(d, "-2147483648");
+ test<long>(x, "0x80000000");
+
+ test<unsigned long>(o, "037777777777");
+ test<unsigned long>(d, "4294967295");
+ test<unsigned long>(x, "0xffffffff");
+ } else if (long_is_64) {
+ test<long>(o, "01000000000000000000000");
+ test<long>(d, "-9223372036854775808");
+ test<long>(x, "0x8000000000000000");
+
+ test<unsigned long>(o, "01777777777777777777777");
+ test<unsigned long>(d, "18446744073709551615");
+ test<unsigned long>(x, "0xffffffffffffffff");
+ }
+ if (long_long_is_64) {
+ test<long long>(o, "01000000000000000000000");
+ test<long long>(d, "-9223372036854775808");
+ test<long long>(x, "0x8000000000000000");
+
+ test<unsigned long long>(o, "01777777777777777777777");
+ test<unsigned long long>(d, "18446744073709551615");
+ test<unsigned long long>(x, "0xffffffffffffffff");
+ }
+
+ return 0;
+}
OpenPOWER on IntegriCloud