dim created this revision.
Herald added a subscriber: emaste.

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.


https://reviews.llvm.org/D32670

Files:
  include/locale
  
test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp

Index: test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp
===================================================================
--- /dev/null
+++ test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.inserters.arithmetic/minmax_showbase.pass.cpp
@@ -0,0 +1,132 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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>
+void test_min_oct(const char *expected)
+{
+    std::stringstream ss;
+    ss << std::oct << std::showbase << std::numeric_limits<T>::min();
+    assert(ss.str() == expected);
+}
+
+template <typename T>
+void test_max_oct(const char *expected)
+{
+    std::stringstream ss;
+    ss << std::oct << std::showbase << std::numeric_limits<T>::max();
+    assert(ss.str() == expected);
+}
+
+template <typename T>
+void test_min_dec(const char *expected)
+{
+    std::stringstream ss;
+    ss << std::dec << std::showbase << std::numeric_limits<T>::min();
+    assert(ss.str() == expected);
+}
+
+template <typename T>
+void test_max_dec(const char *expected)
+{
+    std::stringstream ss;
+    ss << std::dec << std::showbase << std::numeric_limits<T>::max();
+    assert(ss.str() == expected);
+}
+
+template <typename T>
+void test_min_hex(const char *expected)
+{
+    std::stringstream ss;
+    ss << std::hex << std::showbase << std::numeric_limits<T>::min();
+    assert(ss.str() == expected);
+}
+
+template <typename T>
+void test_max_hex(const char *expected)
+{
+    std::stringstream ss;
+    ss << std::hex << std::showbase << std::numeric_limits<T>::max();
+    assert(ss.str() == expected);
+}
+
+int main(void)
+{
+    test_min_oct<short>("0100000");
+    test_min_dec<short>("-32768");
+    test_min_hex<short>("0x8000");
+
+    test_max_oct<unsigned short>("0177777");
+    test_max_dec<unsigned short>("65535");
+    test_max_hex<unsigned short>("0xffff");
+
+    test_min_oct<int>("020000000000");
+    test_min_dec<int>("-2147483648");
+    test_min_hex<int>("0x80000000");
+
+    test_max_oct<unsigned int>("037777777777");
+    test_max_dec<unsigned int>("4294967295");
+    test_max_hex<unsigned int>("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_min_oct<long>("020000000000");
+        test_min_dec<long>("-2147483648");
+        test_min_hex<long>("0x80000000");
+
+        test_max_oct<unsigned long>("037777777777");
+        test_max_dec<unsigned long>("4294967295");
+        test_max_hex<unsigned long>("0xffffffff");
+    } else if (long_is_64) {
+        test_min_oct<long>("01000000000000000000000");
+        test_min_dec<long>("-9223372036854775808");
+        test_min_hex<long>("0x8000000000000000");
+
+        test_max_oct<unsigned long>("01777777777777777777777");
+        test_max_dec<unsigned long>("18446744073709551615");
+        test_max_hex<unsigned long>("0xffffffffffffffff");
+    }
+    if (long_long_is_64) {
+        test_min_oct<long long>("01000000000000000000000");
+        test_min_dec<long long>("-9223372036854775808");
+        test_min_hex<long long>("0x8000000000000000");
+
+        test_max_oct<unsigned long long>("01777777777777777777777");
+        test_max_dec<unsigned long long>("18446744073709551615");
+        test_max_hex<unsigned long long>("0xffffffffffffffff");
+    }
+
+    return 0;
+}
Index: include/locale
===================================================================
--- include/locale
+++ include/locale
@@ -1402,6 +1402,7 @@
     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 @@
     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 @@
     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 @@
     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);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to