From 8c74c8066767b4061c2a5d97b615a2c05e7c8394 Mon Sep 17 00:00:00 2001 From: Lucian Grijincu Date: Mon, 26 Jan 2015 13:43:36 -0800 Subject: [PATCH] folly: to: make exceptions more informative Summary: print the value which failed conversion to aid debugging. Test Plan: run code which throws in to<> and contbuild Reviewed By: tudorb@fb.com, andrei.alexandrescu@fb.com Subscribers: trunkagent, folly-diffs@ FB internal diff: D1786294 Signature: t1:1786294:1421795912:00cc10923990e5aac0a15eedec09deb8e8d470d1 --- folly/Conv.cpp | 12 +++++----- folly/Conv.h | 65 +++++++++++++++++++++++++++++++------------------- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/folly/Conv.cpp b/folly/Conv.cpp index 25c0069d..e5de9a2f 100644 --- a/folly/Conv.cpp +++ b/folly/Conv.cpp @@ -71,8 +71,8 @@ inline bool bool_str_cmp(const char** b, size_t len, const char* value) { bool str_to_bool(StringPiece* src) { auto b = src->begin(), e = src->end(); for (;; ++b) { - FOLLY_RANGE_CHECK(b < e, - "No non-whitespace characters found in input string"); + FOLLY_RANGE_CHECK_STRINGPIECE( + b < e, "No non-whitespace characters found in input string", *src); if (!isspace(*b)) break; } @@ -85,8 +85,8 @@ bool str_to_bool(StringPiece* src) { StringPiece tmp(*src); uint8_t value = to(&tmp); // Only accept 0 or 1 - FOLLY_RANGE_CHECK(value <= 1, - "Integer overflow when parsing bool: must be 0 or 1"); + FOLLY_RANGE_CHECK_STRINGPIECE( + value <= 1, "Integer overflow when parsing bool: must be 0 or 1", *src); b = tmp.begin(); result = (value == 1); break; @@ -126,11 +126,11 @@ bool str_to_bool(StringPiece* src) { } else if (bool_str_cmp(&b, len, "off")) { result = false; } else { - FOLLY_RANGE_CHECK(false, "Invalid value for bool"); + FOLLY_RANGE_CHECK_STRINGPIECE(false, "Invalid value for bool", *src); } break; default: - FOLLY_RANGE_CHECK(false, "Invalid value for bool"); + FOLLY_RANGE_CHECK_STRINGPIECE(false, "Invalid value for bool", *src); } src->assign(b, e); diff --git a/folly/Conv.h b/folly/Conv.h index 5a196463..31902c73 100644 --- a/folly/Conv.h +++ b/folly/Conv.h @@ -46,10 +46,16 @@ #define FOLLY_RANGE_CHECK_STRINGIZE(x) #x #define FOLLY_RANGE_CHECK_STRINGIZE2(x) FOLLY_RANGE_CHECK_STRINGIZE(x) -#define FOLLY_RANGE_CHECK(condition, message) \ +#define FOLLY_RANGE_CHECK(condition, message, src) \ ((condition) ? (void)0 : throw std::range_error( \ (std::string(__FILE__ "(" FOLLY_RANGE_CHECK_STRINGIZE2(__LINE__) "): ") \ - + (message)).c_str())) + + (message) + ": '" + (src) + "'").c_str())) + +#define FOLLY_RANGE_CHECK_BEGIN_END(condition, message, b, e) \ + FOLLY_RANGE_CHECK(condition, message, std::string((b), (e) - (b))) + +#define FOLLY_RANGE_CHECK_STRINGPIECE(condition, message, sp) \ + FOLLY_RANGE_CHECK(condition, message, std::string((sp).data(), (sp).size())) namespace folly { @@ -89,14 +95,14 @@ to(const Src & value) { < std::numeric_limits::max()) { FOLLY_RANGE_CHECK( (!greater_than::max()>(value)), - "Overflow" + "Overflow", std::to_string(value) ); } /* static */ if (std::is_signed::value && (!std::is_signed::value || sizeof(Src) > sizeof(Tgt))) { FOLLY_RANGE_CHECK( (!less_than::min()>(value)), - "Negative overflow" + "Negative overflow", std::to_string(value) ); } return static_cast(value); @@ -116,9 +122,9 @@ to(const Src & value) { /* static */ if (std::numeric_limits::max() < std::numeric_limits::max()) { FOLLY_RANGE_CHECK(value <= std::numeric_limits::max(), - "Overflow"); + "Overflow", std::to_string(value)); FOLLY_RANGE_CHECK(value >= -std::numeric_limits::max(), - "Negative overflow"); + "Negative overflow", std::to_string(value)); } return boost::implicit_cast(value); } @@ -1075,9 +1081,10 @@ __attribute__((__aligned__(16))) constexpr uint16_t shift1000[] = { if (*b != '0') return digits_to(b, e); } } - FOLLY_RANGE_CHECK(size == std::numeric_limits::digits10 + 1 && - strncmp(b, detail::MaxString::value, size) <= 0, - "Numeric overflow upon conversion"); + FOLLY_RANGE_CHECK_BEGIN_END( + size == std::numeric_limits::digits10 + 1 && + strncmp(b, detail::MaxString::value, size) <= 0, + "Numeric overflow upon conversion", b, e); } // Here we know that the number won't overflow when @@ -1120,7 +1127,8 @@ __attribute__((__aligned__(16))) constexpr uint16_t shift1000[] = { } assert(b == e); - FOLLY_RANGE_CHECK(size > 0, "Found no digits to convert in input"); + FOLLY_RANGE_CHECK_BEGIN_END(size > 0, + "Found no digits to convert in input", b, e); return result; } @@ -1152,18 +1160,19 @@ typename std::enable_if< std::is_integral::value && std::is_signed::value, Tgt>::type to(const char * b, const char * e) { - FOLLY_RANGE_CHECK(b < e, "Empty input string in conversion to integral"); + FOLLY_RANGE_CHECK(b < e, "Empty input string in conversion to integral", + to("b: ", intptr_t(b), " e: ", intptr_t(e))); if (!isdigit(*b)) { if (*b == '-') { Tgt result = -to::type>(b + 1, e); - FOLLY_RANGE_CHECK(result <= 0, "Negative overflow."); + FOLLY_RANGE_CHECK_BEGIN_END(result <= 0, "Negative overflow.", b, e); return result; } - FOLLY_RANGE_CHECK(*b == '+', "Invalid lead character"); + FOLLY_RANGE_CHECK_BEGIN_END(*b == '+', "Invalid lead character", b, e); ++b; } Tgt result = to::type>(b, e); - FOLLY_RANGE_CHECK(result >= 0, "Overflow."); + FOLLY_RANGE_CHECK_BEGIN_END(result >= 0, "Overflow", b, e); return result; } @@ -1186,7 +1195,8 @@ to(StringPiece * src) { auto b = src->data(), past = src->data() + src->size(); for (;; ++b) { - FOLLY_RANGE_CHECK(b < past, "No digits found in input string"); + FOLLY_RANGE_CHECK_STRINGPIECE(b < past, + "No digits found in input string", *src); if (!isspace(*b)) break; } @@ -1199,15 +1209,16 @@ to(StringPiece * src) { if (*m == '-') { negative = true; } else { - FOLLY_RANGE_CHECK(*m == '+', "Invalid leading character in conversion" - " to integral"); + FOLLY_RANGE_CHECK_STRINGPIECE(*m == '+', "Invalid leading character in " + "conversion to integral", *src); } ++b; ++m; } } - FOLLY_RANGE_CHECK(m < past, "No digits found in input string"); - FOLLY_RANGE_CHECK(isdigit(*m), "Non-digit character found"); + FOLLY_RANGE_CHECK_STRINGPIECE(m < past, "No digits found in input string", + *src); + FOLLY_RANGE_CHECK_STRINGPIECE(isdigit(*m), "Non-digit character found", *src); m = detail::findFirstNonDigit(m + 1, past); Tgt result; @@ -1217,10 +1228,11 @@ to(StringPiece * src) { auto t = detail::digits_to::type>(b, m); if (negative) { result = -t; - FOLLY_RANGE_CHECK(is_non_positive(result), "Negative overflow"); + FOLLY_RANGE_CHECK_STRINGPIECE(is_non_positive(result), + "Negative overflow", *src); } else { result = t; - FOLLY_RANGE_CHECK(is_non_negative(result), "Overflow"); + FOLLY_RANGE_CHECK_STRINGPIECE(is_non_negative(result), "Overflow", *src); } } src->advance(m - src->data()); @@ -1246,7 +1258,9 @@ namespace detail { */ inline void enforceWhitespace(const char* b, const char* e) { for (; b != e; ++b) { - FOLLY_RANGE_CHECK(isspace(*b), to("Non-whitespace: ", *b)); + FOLLY_RANGE_CHECK_BEGIN_END(isspace(*b), + to("Non-whitespace: ", *b), + b, e); } } @@ -1288,7 +1302,8 @@ to(StringPiece *const src) { std::numeric_limits::quiet_NaN(), nullptr, nullptr); - FOLLY_RANGE_CHECK(!src->empty(), "No digits found in input string"); + FOLLY_RANGE_CHECK_STRINGPIECE(!src->empty(), + "No digits found in input string", *src); int length; auto result = conv.StringToDouble(src->data(), @@ -1476,8 +1491,10 @@ to(const Src & value) { // to avoid defining this global macro name in other files that include Conv.h. #ifndef FOLLY_CONV_INTERNAL #undef FOLLY_RANGE_CHECK -#undef FOLLY_RANGE_CHECK_STRINGIZE2 +#undef FOLLY_RANGE_CHECK_BEGIN_END +#undef FOLLY_RANGE_CHECK_STRINGPIECE #undef FOLLY_RANGE_CHECK_STRINGIZE +#undef FOLLY_RANGE_CHECK_STRINGIZE2 #endif #endif /* FOLLY_BASE_CONV_H_ */ -- 2.34.1