|
| 1 | +#include <base/types.h> |
| 2 | +#include <AggregateFunctions/DDSketch.h> |
| 3 | +#include <AggregateFunctions/AggregateFunctionFactory.h> |
| 4 | +#include <AggregateFunctions/IAggregateFunction.h> |
| 5 | +#include <Columns/ColumnAggregateFunction.h> |
| 6 | +#include <Columns/ColumnsNumber.h> |
| 7 | +#include <DataTypes/DataTypesNumber.h> |
| 8 | +#include <IO/ReadBufferFromMemory.h> |
| 9 | +#include <IO/ReadBufferFromString.h> |
| 10 | +#include <IO/WriteBufferFromVector.h> |
| 11 | +#include <Common/Arena.h> |
| 12 | +#include <Common/Base64.h> |
| 13 | +#include <Common/FailPoint.h> |
| 14 | +#include <Common/tests/gtest_global_register.h> |
| 15 | + |
| 16 | +#include <gtest/gtest.h> |
| 17 | + |
| 18 | +namespace DB::FailPoints |
| 19 | +{ |
| 20 | + extern const char column_aggregate_function_ensureOwnership_exception[]; |
| 21 | +} |
| 22 | + |
| 23 | +TEST(ColumnAggregateFunction, EnsureOwnershipExceptionLeavesCorruptedState) |
| 24 | +{ |
| 25 | + tryRegisterAggregateFunctions(); |
| 26 | + |
| 27 | + using namespace DB; |
| 28 | + |
| 29 | + // Create the aggregate function quantileDD with relative accuracy 0.01 |
| 30 | + AggregateFunctionFactory & factory = AggregateFunctionFactory::instance(); |
| 31 | + DataTypes argument_types = {std::make_shared<DataTypeFloat64>()}; |
| 32 | + Array params = {Field(0.01), Field(0.5)}; |
| 33 | + AggregateFunctionProperties properties; |
| 34 | + auto aggregate_function = factory.get("quantileDD", NullsAction::EMPTY, argument_types, params, properties); |
| 35 | + |
| 36 | + // Create a source column with some data |
| 37 | + auto src_column = ColumnAggregateFunction::create(aggregate_function); |
| 38 | + Arena arena_src; |
| 39 | + auto data_column = ColumnFloat64::create(); |
| 40 | + data_column->insert(Field(1.0)); |
| 41 | + data_column->insert(Field(2.0)); |
| 42 | + data_column->insert(Field(3.0)); |
| 43 | + const IColumn * columns[1] = {data_column.get()}; |
| 44 | + |
| 45 | + for (size_t i = 0; i < 3; ++i) |
| 46 | + { |
| 47 | + src_column->insertDefault(); |
| 48 | + aggregate_function->add(src_column->getData()[i], columns, i, &arena_src); |
| 49 | + } |
| 50 | + |
| 51 | + // Create a view column from the source - this sets src pointer |
| 52 | + auto view_column = src_column->cloneEmpty(); |
| 53 | + view_column->insertRangeFrom(*src_column, 0, 3); |
| 54 | + |
| 55 | + // Enable failpoint that will trigger an exception during ensureOwnership |
| 56 | + // This will happen after at least one state is created and destroyed |
| 57 | + FailPointInjection::enableFailPoint(FailPoints::column_aggregate_function_ensureOwnership_exception); |
| 58 | + |
| 59 | + // Try to insert - this will call ensureOwnership() which will throw |
| 60 | + // After the exception, previously, data[] points to destroyed memory where mapping == nullptr |
| 61 | + ASSERT_THROW({ |
| 62 | + view_column->insertDefault(); |
| 63 | + }, Exception); |
| 64 | + |
| 65 | + // Disable failpoint |
| 66 | + FailPointInjection::disableFailPoint(FailPoints::column_aggregate_function_ensureOwnership_exception); |
| 67 | + |
| 68 | + /// Previously leads to a crash |
| 69 | + view_column->insertDefault(); |
| 70 | +} |
0 commit comments