Fix potential overflow in integer division #12119

This commit is contained in:
Alexey Milovidov 2020-07-05 03:28:08 +03:00
parent c696354dd4
commit 73a5c38398
4 changed files with 29 additions and 7 deletions

View File

@ -26,12 +26,11 @@ struct DivideIntegralByConstantImpl
static NO_INLINE void vectorConstant(const A * __restrict a_pos, B b, ResultType * __restrict c_pos, size_t size)
{
if (unlikely(b == 0))
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
/// Division by -1. By the way, we avoid FPE by division of the largest negative number by -1.
/// And signed integer overflow is well defined in C++20.
if (unlikely(is_signed_v<B> && b == -1))
{
for (size_t i = 0; i < size; ++i)
@ -39,8 +38,20 @@ struct DivideIntegralByConstantImpl
return;
}
/// Division with too large divisor.
if (unlikely(b > std::numeric_limits<A>::max()
|| (std::is_signed_v<A> && std::is_signed_v<B> && b < std::numeric_limits<A>::lowest())))
{
for (size_t i = 0; i < size; ++i)
c_pos[i] = 0;
return;
}
#pragma GCC diagnostic pop
if (unlikely(static_cast<A>(b) == 0))
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
libdivide::divider<A> divider(b);
const A * a_end = a_pos + size;

View File

@ -27,12 +27,10 @@ struct ModuloByConstantImpl
static NO_INLINE void vectorConstant(const A * __restrict src, B b, ResultType * __restrict dst, size_t size)
{
if (unlikely(b == 0))
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare"
/// Modulo with too small divisor.
if (unlikely((std::is_signed_v<B> && b == -1) || b == 1))
{
for (size_t i = 0; i < size; ++i)
@ -40,8 +38,20 @@ struct ModuloByConstantImpl
return;
}
/// Modulo with too large divisor.
if (unlikely(b > std::numeric_limits<A>::max()
|| (std::is_signed_v<A> && std::is_signed_v<B> && b < std::numeric_limits<A>::lowest())))
{
for (size_t i = 0; i < size; ++i)
dst[i] = src[i];
return;
}
#pragma GCC diagnostic pop
if (unlikely(static_cast<A>(b) == 0))
throw Exception("Division by zero", ErrorCodes::ILLEGAL_DIVISION);
libdivide::divider<A> divider(b);
/// Here we failed to make the SSE variant from libdivide give an advantage.

View File

@ -21,6 +21,8 @@ IColumn::Selector createBlockSelector(
const std::vector<UInt64> & slots)
{
const auto total_weight = slots.size();
assert(total_weight != 0);
size_t num_rows = column.size();
IColumn::Selector selector(num_rows);

View File

@ -15,7 +15,6 @@
#include <DataStreams/ConvertingBlockInputStream.h>
#include <DataStreams/OneBlockInputStream.h>
#include <Interpreters/InterpreterInsertQuery.h>
#include <Interpreters/createBlockSelector.h>
#include <Interpreters/ExpressionActions.h>
#include <Interpreters/Context.h>