Repository navigation
Conversation
… of throwing
The /proc/cpuinfo scraper in AsynchronousMetrics::update used std::stod,
std::stoi and substr on host text, and stepped the buffer past EOF when the
last line had no EOL. An unexpected line threw std::invalid_argument or
std::out_of_range (or failed the pos_addr <= end_addr chassert), and
tryLogCurrentException aborts on a std::logic_error on debug and sanitizer
builds and with abort_on_logical_error. On a default build it logged a stack
trace on every update and dropped the metric for all cores.
- cpu MHz: the colon was tested for truthiness, not npos, and stod(substr(colon + 2))
threw on an empty value or a colon at the end of the line, so an npos check
alone is not enough. Now find(':') != npos, then tryReadText on the rest.
- processor: std::from_chars instead of std::stoi. A line that does not parse
unsets the core id, so the next cpu MHz is not attributed to the previous core.
- EOL: checkChar('\n') instead of ++position(), a no-op at EOF.
The loop moves to readCPUFrequenciesFromProcCPUInfo(ReadBuffer &) so it can be
unit-tested. Valid x86 and s390x input gives the same values as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Internal second-model review: adjudication log (click to expand)Pre-publication review by an independent model (engine: codex; 2 findings; 1 full pass).
Severity: ❌ blocker / Session id: cron:clickhouse-review-slot-8:20261017-222100 |
Pre-PR validation gate (click to expand)
Session id: cron:clickhouse-impl-slot-4:20261017-215100 |
|
cc @Algunenano @pamarcos, could you review this and add the |
|
Workflow [PR], commit [a805db7] AI ReviewSummaryThe PR makes Missing context / blind spots
Final VerdictStatus: ✅ Approve, subject to the remaining CI checks. |
Related: #39193
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Description
AsynchronousMetrics::updateparses/proc/cpuinfowithstd::stoi/std::stodand an unconditional++position(). A line it does not expect throwsstd::invalid_argumentorstd::out_of_range, andtryLogCurrentExceptionturns thatstd::logic_errorinto an abort on debug and sanitizer builds and withabort_on_logical_error. This was observed aborting the server mid-run in sanitizer CI jobs. A default release build instead logs a stack trace on every update and dropsCPUFrequencyMHzfor all cores.There are three sites:
cpu MHz:if (auto colon = s.find_first_of(':'))tests truthiness instead ofnpos, andstd::stod(s.substr(colon + 2))throws even with a colon present: on an empty value after the colon or a colon at the end of the line.processor:std::stoithrows when no digit follows or the number does not fitint.\n: the step past EOF failschassert(pos_addr <= end_addr)in the nextreadEscapedStringUntilEOL.The loop moves to
readCPUFrequenciesFromProcCPUInfo(ReadBuffer &). It uses non-throwing parses (std::from_chars,tryReadText) andcheckChar('\n'), and it skips a line it cannot parse. A frequency after an unparseableprocessorline is no longer attributed to the previous core. Valid x86 and s390x (#39193) input gives the same values as before.Validation: I bind-mounted a crafted file over
/proc/cpuinfoin a private mount namespace (printf 'processor\t: 0\ncpu MHz\t\t: \n'is enough). A master debug server aborts during startup on each of six malformed shapes. With the fix, all of them stay up, and a file with one badcpu MHzline still reports the other core. On a snapshot of a real 384-core/proc/cpuinfo, both binaries return identicalCPUFrequencyMHz. A new gtest covers valid and malformed input, and reverting any one of the three changes makes it fail.🤖 Generated with Claude Code
Workflow [PR]
Sync PR [sync-upstream/pr/126540]