Fix crash when count_distinct_implementation is set to an unknown function name by alexey-milovidov · Pull Request #101152 · ClickHouse/ClickHouse · GitHub
Skip to content

Fix crash when count_distinct_implementation is set to an unknown function name#101152

Closed
alexey-milovidov wants to merge 11 commits into
masterfrom
fix-optional-deref-in-rewriteAggregateFunctionName
Closed

Fix crash when count_distinct_implementation is set to an unknown function name#101152
alexey-milovidov wants to merge 11 commits into
masterfrom
fix-optional-deref-in-rewriteAggregateFunctionName

Conversation

@alexey-milovidov

@alexey-milovidov alexey-milovidov commented Mar 30, 2026

Copy link
Copy Markdown
Member

When count_distinct_implementation is set to a nonsensical value like 'null' and aggregate_functions_null_for_empty is enabled, rewriteAggregateFunctionNameIfNeeded in the new analyzer dereferences the result of tryGetProperties without checking if the optional has a value. Since the function name is unknown, tryGetProperties returns std::nullopt, and the subsequent properties->returns_default_when_only_null triggers a libc++ hardening assertion (optional operator-> on disengaged value), aborting the server.

The old analyzer path in TreeRewriter.cpp already had the correct properties && guard. This fix aligns the new analyzer with that pattern.

Found by BuzzHouse fuzzer: https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=101118&sha=8f61fec0aa6f37072934afaeb78da447750657a8&name_0=PR&name_1=BuzzHouse%20%28amd_msan%29
#101118

Changelog category (leave one):

  • Critical Bug Fix (crash, data loss, RBAC)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Fix server crash when count_distinct_implementation is set to an unknown function name and aggregate_functions_null_for_empty is enabled.

Documentation entry for user-facing changes

  • Documentation is written (mandatory for new features)

…unction name

The `rewriteAggregateFunctionNameIfNeeded` in the new analyzer was
dereferencing the result of `tryGetProperties` without checking if the
optional has a value. When `count_distinct_implementation` is set to a
nonsensical value like `'null'`, `tryGetProperties` returns `std::nullopt`,
and the subsequent `properties->returns_default_when_only_null` triggers
a libc++ hardening assertion (optional operator-> on disengaged value).

The old analyzer path in `TreeRewriter.cpp` already had the correct
`properties &&` guard. This fix aligns the new analyzer with that pattern.

Found by BuzzHouse fuzzer.

https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=101118&sha=8f61fec0aa6f37072934afaeb78da447750657a8&name_0=PR&name_1=BuzzHouse%20%28amd_msan%29

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@clickhouse-gh

clickhouse-gh Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

@clickhouse-gh clickhouse-gh Bot added pr-critical-bugfix pr-must-backport Pull request should be backported intentionally. Use this label with great care! labels Mar 30, 2026
…ctions_null_for_empty

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@@ -0,0 +1,3 @@
-- Regression test: setting count_distinct_implementation to an unknown function
-- name with aggregate_functions_null_for_empty caused a crash (optional deref on nullopt).
SELECT countDistinct(1) SETTINGS count_distinct_implementation = 'null', aggregate_functions_null_for_empty = 1; -- { serverError UNKNOWN_AGGREGATE_FUNCTION }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test is good - it reproduces the issue.

@clickhouse-gh

clickhouse-gh Bot commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

LLVM Coverage Report

Metric Baseline Current Δ
Lines 84.20% 84.20% +0.00%
Functions 90.90% 90.90% +0.00%
Branches 76.80% 76.70% -0.10%

Changed lines: 100.00% (6/6) · Uncovered code

Full report · Diff report

@Algunenano Algunenano self-assigned this Mar 30, 2026
alexey-milovidov and others added 7 commits March 30, 2026 08:12
The test `04068_count_distinct_implementation_invalid` conflicts with
`04068_constant_fold_union_intersect` added on master. Renumbered to 04070.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…in-rewriteAggregateFunctionName

# Conflicts:
#	src/Analyzer/Resolve/QueryAnalyzer.cpp
@alexey-milovidov

Copy link
Copy Markdown
Member Author

The Stress test (arm_msan) failure is fixed by #101239, which should be merged first. After it is merged, please update the branch to include the fix.

@@ -0,0 +1,3 @@
-- Regression test: setting count_distinct_implementation to an unknown function
-- name with aggregate_functions_null_for_empty caused a crash (optional deref on nullopt).
SELECT countDistinct(1) SETTINGS count_distinct_implementation = 'null', aggregate_functions_null_for_empty = 1; -- { serverError UNKNOWN_AGGREGATE_FUNCTION, UNKNOWN_FUNCTION }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regression test currently does not prove the claimed failure mode (server abort). In CI, Bugfix validation (functional tests) reports "Failed to reproduce the bug" while this query itself is [ OK ], which means both baseline and PR build accept this expectation.

Because the query is expected to return UNKNOWN_AGGREGATE_FUNCTION/UNKNOWN_FUNCTION, this test can pass even when there is no abort. Please make the test detect process-level failure (or use a reproducer that fails on base and passes on the fix), so bugfix validation can actually validate the fix.

@@ -0,0 +1,3 @@
-- Regression test: setting count_distinct_implementation to an unknown function

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR title/description says this change fixes an abort in rewriteAggregateFunctionNameIfNeeded, but this PR diff only adds a regression test and does not modify the analyzer code path itself. If the fix is intended to be in this PR, please include the actual source change (the missing properties && guard) so the bug is resolved, not only tested.

@Algunenano

Copy link
Copy Markdown
Member

@Algunenano Algunenano closed this Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-critical-bugfix pr-must-backport Pull request should be backported intentionally. Use this label with great care!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants