From 1c55be261c449f93984f2dbf9b962a1123f394e1 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 13 Feb 2021 03:45:06 +0300 Subject: [PATCH] Fix UBSan report in arrayDifference --- src/Functions/array/arrayDifference.cpp | 33 +++++++++++++++---- .../01716_array_difference_overflow.reference | 1 + .../01716_array_difference_overflow.sql | 2 ++ 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 tests/queries/0_stateless/01716_array_difference_overflow.reference create mode 100644 tests/queries/0_stateless/01716_array_difference_overflow.sql diff --git a/src/Functions/array/arrayDifference.cpp b/src/Functions/array/arrayDifference.cpp index 2c71c58867f..b4b30079a4e 100644 --- a/src/Functions/array/arrayDifference.cpp +++ b/src/Functions/array/arrayDifference.cpp @@ -47,6 +47,29 @@ struct ArrayDifferenceImpl } + template + static void NO_SANITIZE_UNDEFINED impl(const Element * __restrict src, Result * __restrict dst, size_t begin, size_t end) + { + /// First element is zero, then the differences of ith and i-1th elements. + + Element prev{}; + for (size_t pos = begin; pos < end; ++pos) + { + if (pos == begin) + { + dst[pos] = 0; + prev = src[pos]; + } + else + { + Element curr = src[pos]; + dst[pos] = curr - prev; + prev = curr; + } + } + } + + template static bool executeType(const ColumnPtr & mapped, const ColumnArray & array, ColumnPtr & res_ptr) { @@ -73,14 +96,10 @@ struct ArrayDifferenceImpl size_t pos = 0; for (auto offset : offsets) { - // skip empty arrays - if (pos < offset) - { - res_values[pos] = 0; - for (++pos; pos < offset; ++pos) - res_values[pos] = static_cast(data[pos]) - static_cast(data[pos - 1]); - } + impl(data.data(), res_values.data(), pos, offset); + pos = offset; } + res_ptr = ColumnArray::create(std::move(res_nested), array.getOffsetsPtr()); return true; } diff --git a/tests/queries/0_stateless/01716_array_difference_overflow.reference b/tests/queries/0_stateless/01716_array_difference_overflow.reference new file mode 100644 index 00000000000..5297534679e --- /dev/null +++ b/tests/queries/0_stateless/01716_array_difference_overflow.reference @@ -0,0 +1 @@ +[0,9223372036854710272] diff --git a/tests/queries/0_stateless/01716_array_difference_overflow.sql b/tests/queries/0_stateless/01716_array_difference_overflow.sql new file mode 100644 index 00000000000..3d153725294 --- /dev/null +++ b/tests/queries/0_stateless/01716_array_difference_overflow.sql @@ -0,0 +1,2 @@ +-- Overflow is Ok and behaves as the CPU does it. +SELECT arrayDifference([65536, -9223372036854775808]);