about summary refs log tree commit diff
path: root/absl/strings/internal
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/internal')
-rw-r--r--absl/strings/internal/str_format/convert_test.cc25
-rw-r--r--absl/strings/internal/str_format/float_conversion.cc20
2 files changed, 37 insertions, 8 deletions
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc
index dd167f76e68f..20c6229fcb37 100644
--- a/absl/strings/internal/str_format/convert_test.cc
+++ b/absl/strings/internal/str_format/convert_test.cc
@@ -704,6 +704,31 @@ TEST_F(FormatConvertTest, FloatRound) {
             "1837869002408041296803276054561138153076171875");
 }
 
+// We don't actually store the results. This is just to exercise the rest of the
+// machinery.
+struct NullSink {
+  friend void AbslFormatFlush(NullSink *sink, string_view str) {}
+};
+
+template <typename... T>
+bool FormatWithNullSink(absl::string_view fmt, const T &... a) {
+  NullSink sink;
+  FormatArgImpl args[] = {FormatArgImpl(a)...};
+  return FormatUntyped(&sink, UntypedFormatSpecImpl(fmt), absl::MakeSpan(args));
+}
+
+TEST_F(FormatConvertTest, ExtremeWidthPrecision) {
+  for (const char *fmt : {"f"}) {
+    for (double d : {1e-100, 1.0, 1e100}) {
+      constexpr int max = std::numeric_limits<int>::max();
+      EXPECT_TRUE(FormatWithNullSink(std::string("%.*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%1.*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%*") + fmt, max, d));
+      EXPECT_TRUE(FormatWithNullSink(std::string("%*.*") + fmt, max, max, d));
+    }
+  }
+}
+
 TEST_F(FormatConvertTest, LongDouble) {
 #ifdef _MSC_VER
   // MSVC has a different rounding policy than us so we can't test our
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc
index cdccc86f551c..a761a5a5f9ce 100644
--- a/absl/strings/internal/str_format/float_conversion.cc
+++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -440,8 +440,10 @@ struct Padding {
   int right_spaces;
 };
 
-Padding ExtraWidthToPadding(int total_size, const FormatState &state) {
-  int missing_chars = std::max(state.conv.width() - total_size, 0);
+Padding ExtraWidthToPadding(size_t total_size, const FormatState &state) {
+  if (state.conv.width() < 0 || state.conv.width() <= total_size)
+    return {0, 0, 0};
+  int missing_chars = state.conv.width() - total_size;
   if (state.conv.has_left_flag()) {
     return {0, 0, missing_chars};
   } else if (state.conv.has_zero_flag()) {
@@ -462,8 +464,8 @@ void FinalPrint(absl::string_view data, int trailing_zeros,
   }
 
   auto padding =
-      ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) +
-                              static_cast<int>(data.size()) + trailing_zeros,
+      ExtraWidthToPadding((state.sign_char != '\0' ? 1 : 0) + data.size() +
+                              static_cast<size_t>(trailing_zeros),
                           state);
 
   state.sink->Append(padding.left_spaces, ' ');
@@ -536,8 +538,9 @@ void FormatFFast(Int v, int exp, const FormatState &state) {
 // worry about anything after the `.`.
 void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
   BinaryToDecimal::RunConversion(v, exp, [&](BinaryToDecimal btd) {
-    const int total_digits =
-        btd.TotalDigits() + (state.ShouldPrintDot() ? state.precision + 1 : 0);
+    const size_t total_digits =
+        btd.TotalDigits() +
+        (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
 
     const auto padding = ExtraWidthToPadding(
         total_digits + (state.sign_char != '\0' ? 1 : 0), state);
@@ -562,8 +565,9 @@ void FormatFPositiveExpSlow(uint128 v, int exp, const FormatState &state) {
 // This one is guaranteed to be < 1.0, so we don't have to worry about integral
 // digits.
 void FormatFNegativeExpSlow(uint128 v, int exp, const FormatState &state) {
-  const int total_digits =
-      /* 0 */ 1 + (state.ShouldPrintDot() ? state.precision + 1 : 0);
+  const size_t total_digits =
+      /* 0 */ 1 +
+      (state.ShouldPrintDot() ? static_cast<size_t>(state.precision) + 1 : 0);
   auto padding =
       ExtraWidthToPadding(total_digits + (state.sign_char ? 1 : 0), state);
   padding.zeros += 1;