Skip to content

Do not mark move operations that allocate through memory-tracking containers as noexcept#106096

Merged
Algunenano merged 10 commits into
ClickHouse:masterfrom
Algunenano:fix-noexcept-public
Jun 1, 2026
Merged

Do not mark move operations that allocate through memory-tracking containers as noexcept#106096
Algunenano merged 10 commits into
ClickHouse:masterfrom
Algunenano:fix-noexcept-public

Conversation

@Algunenano
Copy link
Copy Markdown
Member

@Algunenano Algunenano commented May 29, 2026

A recent change (d45e6cd6d6bc, "Convert std containers in src/QueryPipeline to *WithMemoryTracking aliases") made QueryPlanResourceHolder's move-assignment able to throw: it appends into VectorWithMemoryTracking members, which allocate through the throwing memory tracker and raise MEMORY_LIMIT_EXCEEDED. The function (and the QueryPipeline / BlockIO move-assignments that call it) are marked noexcept, so under a memory limit the throw hits the noexcept boundary and calls std::terminate. It reproduces with a SELECT ... SETTINGS extremes = 1, max_memory_usage = '4Mi', which terminates the server while the result BlockIO is move-assigned in TCPHandler.

This removes noexcept from that move-assignment chain (QueryPlanResourceHolder, QueryPipeline, BlockIO).

While auditing other noexcept specifications it also fixes:

  • ConstraintsDescription / ColumnDescription move operations and ActionsDAG::decorrelate, which allocate (rebuild derived data, clone ASTs, append to vectors) and can throw.
  • pImpl settings classes: their noexcept move constructors and move assignments either allocated a new impl via make_unique, or move-assigned the impl in place (*impl = std::move(*settings.impl)). The latter is also unsafe: BaseSettings/Data move walks per-field SettingFields, and SettingFieldString (and friends) declare a copy assignment but no move, so the rvalue assignment falls back to copying a String, which allocates and can throw. Both move ops are now = default, so they simply steal the unique_ptr (noexcept and allocation-free); the impl/BaseSettings is never moved.

Closes ClickHouse/ClickHouse#106079
References ClickHouse/ClickHouse#105580

Changelog category (leave one):

  • Not for changelog (changelog entry is not required)

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

...

…ppends through memory-tracking containers and can throw MEMORY_LIMIT_EXCEEDED, terminating the server
…on move ops and ActionsDAG::decorrelate; they allocate and can throw
…-free by defaulting them (steal impl instead of make_unique)
@clickhouse-gh
Copy link
Copy Markdown
Contributor

clickhouse-gh Bot commented May 29, 2026

Workflow [PR], commit [632873c]

Summary:

job_name test_name status info comment
Stateless tests (arm_asan_ubsan, targeted) FAIL
Server died FAIL cidb IGNORED

AI Review

Summary

This PR removes incorrect noexcept from move-assignment paths that can allocate through memory-tracking containers, defaults pImpl settings moves so they steal unique_ptr storage instead of rebuilding BaseSettings, and makes the HMAC OpenSSL enumeration path safe under memory fault injection. The current head addresses the earlier review threads, and I did not find remaining correctness blockers in the changed diff.

Final Verdict

Status: ✅ Approve

@clickhouse-gh clickhouse-gh Bot added the pr-not-for-changelog This PR should not be mentioned in the changelog label May 29, 2026
Comment thread src/QueryPipeline/BlockIO.h Outdated
Comment thread src/Core/Settings.cpp
Comment thread src/Interpreters/FileCache/FileCacheSettings.cpp Outdated
@nickitat nickitat self-assigned this May 29, 2026
…; an in-place *impl = std::move copies SettingFieldString (which has no move op) and can throw under the noexcept wrapper
Copy link
Copy Markdown
Member

@nickitat nickitat left a comment

Choose a reason for hiding this comment

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

If there is a focused reproducer, let's add it as a test.

Comment thread src/QueryPipeline/QueryPlanResourceHolder.h Outdated
…s throw (std::bad_alloc), not only via the memory-tracking containers
…ans of a UNION query so a fault lands in QueryPlanResourceHolder::append; the server must not terminate
Comment thread src/QueryPipeline/QueryPlanResourceHolder.h Outdated
…ryPlanResourceHolder, which allocates and can throw (move ctor stays noexcept, it steals the holder)
…onally can throw; marking them noexcept would reintroduce the std::terminate (same NOLINT as StorageInMemoryMetadata)
@Algunenano
Copy link
Copy Markdown
Member Author

Found another, different, issue in the CI preventing the merge:

2026-05-30 03:23:58 Reason: having stderror:  
2026-05-30 03:23:58 Path: /home/ubuntu/actions-runner/_work/clickhouse-private/clickhouse-private/tests/queries/0_stateless/04299_move_assignment_memory_limit.5328.stderr-fatal
2026-05-30 03:23:58 (version 26.6.1.358, build id: B0BB22175DCD6D0AA8F70682DCF0C1DFA5D52010, git hash: 79e852b2ba7b19da4a2ba350ad16cf935d08220c) (from thread 519605) Terminate called for uncaught exception:
2026-05-30 03:23:58 Code: 241. DB::Exception: Query memory tracker: fault injected. Would use 7.56 MiB (attempt to allocate chunk of 80.00 B), maximum: 0.00 B. (MEMORY_LIMIT_EXCEEDED), Stack trace (when copying this message, always include the lines below):
2026-05-30 03:23:58 
2026-05-30 03:23:58 0. src/Common/Exception.cpp:141:1: DB::Exception::Exception(DB::Exception::MessageMasked&&, int, bool) @ 0x00000000174cb52a
2026-05-30 03:23:58 1. src/Common/Exception.h:171:100: DB::Exception::Exception(String&&, int, String, bool) @ 0x00000000107e048e
2026-05-30 03:23:58 2. src/Common/Exception.h:57:54: DB::Exception::Exception(PreformattedMessage&&, int) @ 0x00000000107dfd04
2026-05-30 03:23:58 3. src/Common/Exception.h:189:77: DB::Exception::Exception<char const*, char const*, String, String, String>(int, FormatStringHelperImpl<std::type_identity<char const*>::type, std::type_identity<char const*>::type, std::type_identity<String>::type, std::type_identity<String>::type, std::type_identity<String>::type>, char const*&&, char const*&&, String&&, String&&, String&&) @ 0x00000000175557ef
2026-05-30 03:23:58 4. src/Common/MemoryTracker.cpp:352:19: MemoryTracker::allocImpl(long, bool, MemoryTracker*, double) @ 0x0000000017552f77
2026-05-30 03:23:58 5. src/Common/MemoryTracker.cpp:511:29: MemoryTracker::allocImpl(long, bool, MemoryTracker*, double) @ 0x000000001755270d
2026-05-30 03:23:58 6. src/Common/CurrentMemoryTracker.cpp:88:40: CurrentMemoryTracker::allocImpl(long, bool) @ 0x0000000017492ec2
2026-05-30 03:23:58 7. src/Common/CurrentMemoryTracker.cpp:111:12: std::pair<std::__tree_iterator<std::__value_type<String, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, std::__tree_node<std::__value_type<String, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, void*>*, long>, bool> std::__tree<std::__value_type<String, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, std::__map_value_compare<String, std::pair<String const, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, std::less<String>>, AllocatorWithMemoryTracking<std::pair<String const, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>>>::__emplace_unique[abi:fqe220101]<std::piecewise_construct_t const&, std::tuple<String const&>, std::tuple<>>(std::piecewise_construct_t const&, std::tuple<String const&>&&, std::tuple<>&&)::'lambda'(String const&, std::piecewise_construct_t const&, std::tuple<String const&>&&, std::tuple<>&&)::operator()(String const&, std::piecewise_construct_t const&, std::tuple<String const&>&&, std::tuple<>&&) const @ 0x0000000011c22505
2026-05-30 03:23:58 8. contrib/llvm-project/libcxx/include/__utility/try_key_extraction.h:91:10: DB::(anonymous namespace)::FunctionHMAC::fetchAndGroupSupportedAlgorithms()::'lambda'(evp_md_st const*, char const*, char const*, void*)::__invoke(evp_md_st const*, char const*, char const*, void*) @ 0x0000000011c22045
2026-05-30 03:23:58 9. contrib/openssl/crypto/objects/o_names.c:347:13: OBJ_NAME_do_all_sorted @ 0x0000000024eaf82a
2026-05-30 03:23:58 10. contrib/openssl/crypto/evp/names.c:281:5: EVP_MD_do_all_sorted @ 0x0000000024e561b7
2026-05-30 03:23:58 11. src/Functions/HMAC.cpp:48:9: void std::__call_once_proxy[abi:fqe220101]<std::tuple<DB::(anonymous namespace)::FunctionHMAC::getGroupedAlgorithms()::'lambda'()&&>>(void*) @ 0x0000000011c21cfc
2026-05-30 03:23:58 12. contrib/llvm-project/libcxx/src/call_once.cpp:58:5: std::__call_once(unsigned long volatile&, void*, void (*)(void*)) @ 0x00000000250db00b
2026-05-30 03:23:58 13. contrib/llvm-project/libcxx/include/__mutex/once_flag.h:135:5: DB::(anonymous namespace)::FunctionHMAC::getSupportedAlgorithmsAsString(bool) @ 0x0000000011c216e3
2026-05-30 03:23:58 14. src/Functions/HMAC.cpp:198:9: DB::registerFunctionFunctionHMAC(DB::FunctionFactory&) @ 0x0000000011c1f839
2026-05-30 03:23:58 15. src/Functions/registerFunctions.cpp:14:9: DB::registerFunctions() @ 0x0000000015ee6a88
2026-05-30 03:23:58 16. programs/client/Client.cpp:357:5: DB::Client::main(std::vector<String, std::allocator<String>> const&) @ 0x00000000178a71cb
2026-05-30 03:23:58 17. base/poco/Util/src/Application.cpp:315:8: Poco::Util::Application::run() @ 0x0000000023f035b1
2026-05-30 03:23:58 18. programs/client/Client.cpp:1372:23: mainEntryClickHouseClient(int, char**) @ 0x00000000178ba9a6
2026-05-30 03:23:58 19. programs/main.cpp:477:21: main @ 0x00000000107d8b1
2026-05-30 03:23:58 ########## Short fault info ############
2026-05-30 03:23:58 (version 26.6.1.358, build id: B0BB22175DCD6D0AA8F70682DCF0C1DFA5D52010, git hash: 79e852b2ba7b19da4a2ba350ad16cf935d08220c, architecture: x86_64) (from thread 519605) Received signal 6 (internal)
2026-05-30 03:23:58 Signal description: Aborted
2026-05-30 03:23:58 Sent by tkill.
2026-05-30 03:23:58 Stack trace: 0x00007fc6aa4119fd 0x00007fc6aa3bd476 0x00007fc6aa3a37f3 0x00000000177e9cd6 0x000000002513e5c3 0x000000002513ee29 0x000000002514489a 0x000000002513e05b 0x0000000017492f95 0x0000000011c22505 0x0000000011c22045 0x0000000024eaf82a 0x0000000024e561b7 0x0000000011c21cfc 0x00000000250db00b 0x0000000011c216e3 0x0000000011c1f839 0x0000000015ee6a88 0x00000000178a71cb 0x0000000023f035b1 0x00000000178ba9a6 0x00000000107d8b11 0x00007fc6aa3a4d90 0x00007fc6aa3a4e40 0x0000000008ca7bae
2026-05-30 03:23:58 ########################################
2026-05-30 03:23:58 (version 26.6.1.358, build id: B0BB22175DCD6D0AA8F70682DCF0C1DFA5D52010, git hash: 79e852b2ba7b19da4a2ba350ad16cf935d08220c) (from thread 519605) (no query) Received signal Aborted (6)
2026-05-30 03:23:58 Sent by tkill.
2026-05-30 03:23:58 Stack trace: 0x00007fc6aa4119fd 0x00007fc6aa3bd476 0x00007fc6aa3a37f3 0x00000000177e9cd6 0x000000002513e5c3 0x000000002513ee29 0x000000002514489a 0x000000002513e05b 0x0000000017492f95 0x0000000011c22505 0x0000000011c22045 0x0000000024eaf82a 0x0000000024e561b7 0x0000000011c21cfc 0x00000000250db00b 0x0000000011c216e3 0x0000000011c1f839 0x0000000015ee6a88 0x00000000178a71cb 0x0000000023f035b1 0x00000000178ba9a6 0x00000000107d8b11 0x00007fc6aa3a4d90 0x00007fc6aa3a4e40 0x0000000008ca7bae
2026-05-30 03:23:58 2. __GI___pthread_kill @ 0x00000000000969fd
2026-05-30 03:23:58 3. gsignal @ 0x0000000000042476
2026-05-30 03:23:58 4. __ieee754_lgamma_r @ 0x00000000000287f3
2026-05-30 03:23:58 5. src/Common/SignalHandlers.cpp:0: terminate_handler() @ 0x00000000177e9cd6
2026-05-30 03:23:58 6. contrib/llvm-project/libcxxabi/src/cxa_handlers.cpp:59:9: std::__terminate(void (*)()) @ 0x000000002513e5c3
2026-05-30 03:23:58 7.0. inlined from contrib/llvm-project/libcxxabi/src/cxa_personality.cpp:0: __cxxabiv1::scan_eh_tab(__cxxabiv1::(anonymous namespace)::scan_results&, _Unwind_Action, bool, _Unwind_Exception*, _Unwind_Context*)
2026-05-30 03:23:58 7. contrib/llvm-project/libcxxabi/src/cxa_personality.cpp:1073:9: __gxx_personality_v0 @ 0x000000002513ee29
2026-05-30 03:23:58 8.0. inlined from contrib/llvm-project/libunwind/src/UnwindLevel1.c:172: unwind_phase1
2026-05-30 03:23:58 8. contrib/llvm-project/libunwind/src/UnwindLevel1.c:479:11: _Unwind_RaiseException @ 0x000000002514489a
2026-05-30 03:23:58 9. contrib/llvm-project/libcxxabi/src/cxa_exception.cpp:651:5: __cxa_rethrow @ 0x000000002513e05b
2026-05-30 03:23:58 10. src/Common/CurrentMemoryTracker.cpp:93:17: CurrentMemoryTracker::allocImpl(long, bool) @ 0x0000000017492f95
2026-05-30 03:23:58 11.0. inlined from src/Common/CurrentMemoryTracker.cpp:111: CurrentMemoryTracker::alloc(long)
2026-05-30 03:23:58 11.1. inlined from src/Common/AllocatorWithMemoryTracking.h:44: allocate
2026-05-30 03:23:58 11.2. inlined from contrib/llvm-project/libcxx/include/__memory/allocator_traits.h:259: allocate
2026-05-30 03:23:58 11.3. inlined from contrib/llvm-project/libcxx/include/__tree:1949: __construct_node<const std::piecewise_construct_t &, std::tuple<const std::basic_string<char, std::char_traits<char>, std::allocator<char> > &>, std::tuple<> >
2026-05-30 03:23:58 11. contrib/llvm-project/libcxx/include/__tree:1043:12: std::pair<std::__tree_iterator<std::__value_type<String, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, std::__tree_node<std::__value_type<String, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, void*>*, long>, bool> std::__tree<std::__value_type<String, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, std::__map_value_compare<String, std::pair<String const, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>, std::less<String>>, AllocatorWithMemoryTracking<std::pair<String const, std::set<String, std::less<String>, AllocatorWithMemoryTracking<String>>>>>::__emplace_unique[abi:fqe220101]<std::piecewise_construct_t const&, std::tuple<String const&>, std::tuple<>>(std::piecewise_construct_t const&, std::tuple<String const&>&&, std::tuple<>&&)::'lambda'(String const&, std::piecewise_construct_t const&, std::tuple<String const&>&&, std::tuple<>&&)::operator()(String const&, std::piecewise_construct_t const&, std::tuple<String const&>&&, std::tuple<>&&) const @ 0x0000000011c22505
2026-05-30 03:23:58 12.0. inlined from contrib/llvm-project/libcxx/include/__utility/try_key_extraction.h:91: __try_key_extraction_impl<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::pair<std::__tree_iterator<std::__value_type<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, AllocatorWithMemoryTracking<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__tree_node<std::__value_type<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::set<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, AllocatorWithMemoryTracking<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, void *> *, long>, bool>, (lambda at contrib/llvm-project/libcxx/include/__tree:1038:9), (lambda at contrib/llvm-project/libcxx/include/__tree:1050:9), const std::piecewise_construct_t &, std::tuple<const std::basic_string<char, std::char_traits<char>, std::allocator<char> > &>, std::tuple<>, 0>
2026-05-30 03:23:58 12.1. inlined from contrib/llvm-project/libcxx/include/__utility/try_key_extraction.h:108: __try_key_extraction<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, (lambda at contrib/llvm-project/libcxx/include/__tree:1038:9), (lambda at contrib/llvm-project/libcxx/include/__tree:1050:9), const std::piecewise_construct_t &, std::tuple<const std::basic_string<char, std::char_traits<char>, std::allocator<char> > &>, std::tuple<> >
2026-05-30 03:23:58 12.2. inlined from contrib/llvm-project/libcxx/include/__tree:1037: __emplace_unique<const std::piecewise_construct_t &, std::tuple<const std::basic_string<char, std::char_traits<char>, std::allocator<char> > &>, std::tuple<> >
2026-05-30 03:23:58 12.3. inlined from contrib/llvm-project/libcxx/include/map:1501: operator[]
2026-05-30 03:23:58 12.4. inlined from src/Functions/HMAC.cpp:53: operator()
2026-05-30 03:23:58 12. src/Functions/HMAC.cpp:49:10: DB::(anonymous namespace)::FunctionHMAC::fetchAndGroupSupportedAlgorithms()::'lambda'(evp_md_st const*, char const*, char const*, void*)::__invoke(evp_md_st const*, char const*, char const*, void*) @ 0x0000000011c22045
2026-05-30 03:23:58 13. contrib/openssl/crypto/objects/o_names.c:347:13: OBJ_NAME_do_all_sorted @ 0x0000000024eaf82a
2026-05-30 03:23:58 14. contrib/openssl/crypto/evp/names.c:281:5: EVP_MD_do_all_sorted @ 0x0000000024e561b7
2026-05-30 03:23:58 15.0. inlined from src/Functions/HMAC.cpp:48: fetchAndGroupSupportedAlgorithms
2026-05-30 03:23:58 15.1. inlined from src/Functions/HMAC.cpp:78: operator()
2026-05-30 03:23:58 15.2. inlined from contrib/llvm-project/libcxx/include/__type_traits/invoke.h:90: __invoke<(lambda at src/Functions/HMAC.cpp:78:51)>
2026-05-30 03:23:58 15.3. inlined from contrib/llvm-project/libcxx/include/__mutex/once_flag.h:91: operator()<0UL>
2026-05-30 03:23:58 15.4. inlined from contrib/llvm-project/libcxx/include/__mutex/once_flag.h:90: operator()
2026-05-30 03:23:58 15. contrib/llvm-project/libcxx/include/__mutex/once_flag.h:113:9: void std::__call_once_proxy[abi:fqe220101]<std::tuple<DB::(anonymous namespace)::FunctionHMAC::getGroupedAlgorithms()::'lambda'()&&>>(void*) @ 0x0000000011c21cfc
2026-05-30 03:23:58 16. contrib/llvm-project/libcxx/src/call_once.cpp:58:5: std::__call_once(unsigned long volatile&, void*, void (*)(void*)) @ 0x00000000250db00b
2026-05-30 03:23:58 17.0. inlined from contrib/llvm-project/libcxx/include/__mutex/once_flag.h:135: call_once<(lambda at src/Functions/HMAC.cpp:78:51)>
2026-05-30 03:23:58 17.1. inlined from src/Functions/HMAC.cpp:78: getGroupedAlgorithms
2026-05-30 03:23:58 17. src/Functions/HMAC.cpp:172:5: DB::(anonymous namespace)::FunctionHMAC::getSupportedAlgorithmsAsString(bool) @ 0x0000000011c216e3
2026-05-30 03:23:58 18. src/Functions/HMAC.cpp:198:9: DB::registerFunctionFunctionHMAC(DB::FunctionFactory&) @ 0x0000000011c1f839
2026-05-30 03:23:58 19. src/Functions/registerFunctions.cpp:14:9: DB::registerFunctions() @ 0x0000000015ee6a88
2026-05-30 03:23:58 20. programs/client/Client.cpp:357:5: DB::Client::main(std::vector<String, std::allocator<String>> const&) @ 0x00000000178a71cb
2026-05-30 03:23:58 21. base/poco/Util/src/Application.cpp:315:8: Poco::Util::Application::run() @ 0x0000000023f035b1
2026-05-30 03:23:58 22. programs/client/Client.cpp:1372:23: mainEntryClickHouseClient(int, char**) @ 0x00000000178ba9a6
2026-05-30 03:23:58 23. programs/main.cpp:477:21: main @ 0x00000000107d8b11
2026-05-30 03:23:58 24. __ieee754_pow_ifunc @ 0x0000000000029d90
2026-05-30 03:23:58 25. __libc_start_main@GLIBC_2.2.5 @ 0x0000000000029e40
2026-05-30 03:23:58 26. _start @ 0x0000000008ca7bae

Fixing it here

…SSL callback exception-safe; otherwise memory_tracker_fault_probability injects a fault that unwinds through C and terminates
@clickhouse-gh
Copy link
Copy Markdown
Contributor

clickhouse-gh Bot commented Jun 1, 2026

LLVM Coverage Report

Metric Baseline Current Δ
Lines 84.40% 84.50% +0.10%
Functions 91.40% 91.40% +0.00%
Branches 77.00% 77.10% +0.10%

Changed lines: Changed C/C++ lines covered by tests: 84/114 (73.68%) | Lost baseline coverage (was covered on master, now uncovered in this PR): 2 line(s) · Uncovered code

Full report · Diff report

@Algunenano Algunenano enabled auto-merge June 1, 2026 12:29
@Algunenano Algunenano added this pull request to the merge queue Jun 1, 2026
Merged via the queue into ClickHouse:master with commit ecb53ca Jun 1, 2026
164 of 166 checks passed
@Algunenano Algunenano deleted the fix-noexcept-public branch June 1, 2026 13:11
@robot-ch-test-poll1 robot-ch-test-poll1 added the pr-synced-to-cloud The PR is synced to the cloud repo label Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-not-for-changelog This PR should not be mentioned in the changelog pr-synced-to-cloud The PR is synced to the cloud repo

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Assertion 'px != 0' failed (STID: 2659-205f)

3 participants