Avoid invalid dereference in RANGE_HASHED() dictionary

UBsan report the following [1], when query does not contains any columns
from the dictionary:

```sql
SELECT
    toUInt32(toUInt32(NULL, toUInt32(NULL, inf, NULL), NULL)),
    toUInt32(toUInt32(toUInt32(toUInt32(toUInt32(NULL, 1., NULL)), toUInt32(toUInt32(NULL, 0.5, NULL)), toUInt32(NULL, NULL)), toUInt32(toUInt32(NULL, 1., NULL)), toUInt32(NULL, NULL)), toUInt32(toUInt32(toUInt32(toUInt32(NULL, 1000.0001220703125, NULL)), toUInt32(toUInt32(NULL, 10.000100135803223, NULL)), toUInt32(NULL, NULL)), NULL, NULL, NULL))
FROM somedict
```

```
std::__1::vector<DB::ColumnWithTypeAndName, std::__1::allocator<DB::ColumnWithTypeAndName> >::back() @ 0x128c07a6 in /workspace/clickhouse
./obj-x86_64-linux-gnu/../src/Dictionaries/RangeDictionaryBlockInputStream.h:0: DB::RangeDictionaryBlockInputStream<DB::RangeHashedDictionary, unsigned short, unsigned long>::fillBlock(DB::PODArray<unsigned long, 4096ul, Allocator<false, false>, 15ul, 16ul> const&, DB::PODArray<unsigned short, 4096ul, Allocator<false, false>, 15ul, 16ul> const&, DB::PODArray<unsigned short, 4096ul, Allocator<false, false>, 15ul, 16ul> const&) const @ 0x1692335e in /workspace/clickhouse
./obj-x86_64-linux-gnu/../src/Dictionaries/RangeDictionaryBlockInputStream.h:0: DB::RangeDictionaryBlockInputStream<DB::RangeHashedDictionary, unsigned short, unsigned long>::getBlock(unsigned long, unsigned long) const @ 0x16922f96 in /workspace/clickhouse
./obj-x86_64-linux-gnu/../src/Dictionaries/DictionaryBlockInputStreamBase.cpp:23: DB::DictionaryBlockInputStreamBase::getHeader() const @ 0x166ab57c in /workspace/clickhouse
```

  [1]: https://clickhouse-test-reports.s3.yandex.net/19451/64c0bf98290362fa216c05b070aa122a12af3c25/fuzzer_ubsan/report.html#fail1
This commit is contained in:
Azat Khuzhin 2021-02-11 21:07:37 +03:00
parent d88f7bc0c8
commit 2907385400
3 changed files with 11 additions and 5 deletions

View File

@ -47,7 +47,8 @@ private:
const std::string & default_name,
const std::unordered_set<std::string> & column_names_set,
const PaddedPODArray<T> & values,
ColumnsWithTypeAndName & columns) const;
ColumnsWithTypeAndName & columns,
bool force = false) const;
Block fillBlock(
const PaddedPODArray<Key> & ids_to_fill,
@ -121,13 +122,14 @@ void RangeDictionaryBlockInputStream<DictionaryType, RangeType, Key>::addSpecial
const std::string & default_name,
const std::unordered_set<std::string> & column_names_set,
const PaddedPODArray<T> & values,
ColumnsWithTypeAndName & columns) const
ColumnsWithTypeAndName & columns,
bool force) const
{
std::string name = default_name;
if (attribute)
name = attribute->name;
if (column_names_set.find(name) != column_names_set.end())
if (force || column_names_set.find(name) != column_names_set.end())
columns.emplace_back(getColumnFromPODArray(values), type, name);
}
@ -159,7 +161,7 @@ Block RangeDictionaryBlockInputStream<DictionaryType, RangeType, Key>::fillBlock
std::unordered_set<std::string> names(column_names.begin(), column_names.end());
addSpecialColumn(structure.id, std::make_shared<DataTypeUInt64>(), "ID", names, ids_to_fill, columns);
addSpecialColumn(structure.id, std::make_shared<DataTypeUInt64>(), "ID", names, ids_to_fill, columns, true);
auto ids_column = columns.back().column;
addSpecialColumn(structure.range_min, structure.range_max->type, "Range Start", names, block_start_dates, columns);
addSpecialColumn(structure.range_max, structure.range_max->type, "Range End", names, block_end_dates, columns);

View File

@ -1,3 +1,4 @@
1 2019-01-05 2020-01-10 1
1
date_table
somedict

View File

@ -29,6 +29,9 @@ LIFETIME(MIN 300 MAX 360);
SELECT * from somedict;
-- No dictionary columns
SELECT 1 FROM somedict;
SHOW TABLES;
DROP DATABASE IF EXISTS database_for_dict;
DROP DATABASE database_for_dict;