diff --git a/src/DataTypes/DataTypesDecimal.cpp b/src/DataTypes/DataTypesDecimal.cpp index cbc38429183..0d48845b4fe 100644 --- a/src/DataTypes/DataTypesDecimal.cpp +++ b/src/DataTypes/DataTypesDecimal.cpp @@ -22,9 +22,9 @@ namespace ErrorCodes { extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; extern const int ILLEGAL_TYPE_OF_ARGUMENT; + extern const int DECIMAL_OVERFLOW; } -// template std::string DataTypeDecimal::doGetName() const @@ -61,10 +61,13 @@ template bool DataTypeDecimal::tryReadText(T & x, ReadBuffer & istr, UInt32 precision, UInt32 scale) { UInt32 unread_scale = scale; - bool done = tryReadDecimalText(istr, x, precision, unread_scale); + if (!tryReadDecimalText(istr, x, precision, unread_scale)) + return false; - x *= T::getScaleMultiplier(unread_scale); - return done; + if (common::mulOverflow(x.value, T::getScaleMultiplier(unread_scale), x.value)) + return false; + + return true; } template @@ -75,7 +78,9 @@ void DataTypeDecimal::readText(T & x, ReadBuffer & istr, UInt32 precision, UI readCSVDecimalText(istr, x, precision, unread_scale); else readDecimalText(istr, x, precision, unread_scale); - x *= T::getScaleMultiplier(unread_scale); + + if (common::mulOverflow(x.value, T::getScaleMultiplier(unread_scale), x.value)) + throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW); } template @@ -101,7 +106,9 @@ T DataTypeDecimal::parseFromString(const String & str) const T x; UInt32 unread_scale = this->scale; readDecimalText(buf, x, this->precision, unread_scale, true); - x *= T::getScaleMultiplier(unread_scale); + + if (common::mulOverflow(x.value, T::getScaleMultiplier(unread_scale), x.value)) + throw Exception("Decimal math overflow", ErrorCodes::DECIMAL_OVERFLOW); return x; } diff --git a/tests/performance/decimal_parse.xml b/tests/performance/decimal_parse.xml new file mode 100644 index 00000000000..19e940b13df --- /dev/null +++ b/tests/performance/decimal_parse.xml @@ -0,0 +1,3 @@ + + SELECT count() FROM zeros(10000000) WHERE NOT ignore(toDecimal32OrZero(toString(rand() % 10000), 5)) + diff --git a/tests/queries/0_stateless/01260_ubsan_decimal_parse.reference b/tests/queries/0_stateless/01260_ubsan_decimal_parse.reference new file mode 100644 index 00000000000..945da8ffd36 --- /dev/null +++ b/tests/queries/0_stateless/01260_ubsan_decimal_parse.reference @@ -0,0 +1 @@ +0.000000 diff --git a/tests/queries/0_stateless/01260_ubsan_decimal_parse.sql b/tests/queries/0_stateless/01260_ubsan_decimal_parse.sql new file mode 100644 index 00000000000..2c7cda512e8 --- /dev/null +++ b/tests/queries/0_stateless/01260_ubsan_decimal_parse.sql @@ -0,0 +1 @@ +SELECT toDecimal32OrZero(CAST(-7174046, 'String'), 6);