Fix nullptr crash in RecConfigOverrideFromEnvironment with runroot#12917
Fix nullptr crash in RecConfigOverrideFromEnvironment with runroot#12917brbzull0 wants to merge 2 commits intoapache:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes a crash in ATS records.yaml parsing when runroot is enabled and certain PROXY_CONFIG_* path environment variables are unset, by ensuring RecConfigOverrideFromEnvironment() never returns nullptr for those records. This keeps the function’s contract intact and prevents exceptions when converting the returned C string into a std::string.
Changes:
- Update
RecConfigOverrideFromEnvironment()to return the original record value (instead ofnullptr) for runroot-managed path records when no env override exists. - Add a gold test that unsets the four path env vars to reproduce the previous crash path and validates resulting record values via
traffic_ctl.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
src/records/RecConfigParse.cc |
Prevents nullptr from being returned during env override resolution under runroot, avoiding downstream std::string(nullptr) crashes. |
tests/gold_tests/records/records_runroot_null_override.test.py |
Adds regression coverage for the runroot + missing env-var scenario and verifies both env overrides and path-record behavior. |
Comments suppressed due to low confidence (1)
src/records/RecConfigParse.cc:129
RecConfigOverrideFromEnvironment()now returnsvalueregardless of whetherRecConfigOverrideFromRunroot(name)is true or false (whenenvvalis unset), so thiselse ifbranch is redundant and adds an unnecessaryRecConfigOverrideFromRunroot()call on the hot path while parsing every record. Consider removing theelse ifentirely (or otherwise making the runroot branch do something meaningfully different).
if (envval) {
return envval;
} else if (RecConfigOverrideFromRunroot(name)) {
return value;
}
return value;
zwoop
left a comment
There was a problem hiding this comment.
I think you should cleanup the else if, I think CoPilot said the same thing.
thanks for pointing this out. I think I may have introduced a side effect bug. I'll ammend and put this back for review. |
f5b761a to
46b6553
Compare
…source Change the return type to std::pair<std::string, RecConfigOverrideSource> so callers know whether a record was overridden and by whom (ENV or RUNROOT). When runroot is active, return the actual Layout path (e.g. Layout::bindir) instead of the old nullptr which caused undefined behaviour when converted to std::string. Replace the RecConfigOverrideFromRunroot() strcmp chain with a constexpr lookup table mapping record names to Layout members. All three callers now log the override source at debug level. Preserve nullptr for built-in defaults that are intentionally unset. Adds records_runroot_precedence autest.
46b6553 to
447753b
Compare
|
[approve ci] |
Ok, there was a deeper issue at the end. My original change was actually causing troubles. |
| @@ -0,0 +1,165 @@ | |||
| ''' | |||
| ''' | |||
There was a problem hiding this comment.
Why is this empty multi-line string here? Typo / leftovers ?
| case RecConfigOverrideSource::RUNROOT: | ||
| return "runroot"; | ||
| default: | ||
| return "none"; |
There was a problem hiding this comment.
Can this happen? Should it be an assert ? Alternatively, instead of a default:, why not have NONE as the label, future proofing this?
TL;DR
RecConfigOverrideFromEnvironmentreturned a plain string, so callers could only guess whether a value was overridden by comparing strings — and had no way to tell if the source was an env var or runroot, this was also generating UB because of a stirng created out of a nullptr.This change makes the function return the resolved value paired with a typed
RecConfigOverrideSource enum, giving callers explicit knowledge of what happened and why. Now it also returns either theenvvalue or therunrootvalue for some runroot records.A bit more details:
RecConfigOverrideFromEnvironment()previously returned a rawconst char *nullptrfor the runroot case. All three callers fed that intostd::string, which is undefined behaviour and crashed on newer toolchains.This PR:
Changes the return type to
std::pair<std::string, RecConfigOverrideSource>with a new enum (
NONE,ENV,RUNROOT) so callers know exactly whooverrode the value.
For runroot-managed path records, returns the actual resolved Layout path
(e.g.
Layout::bindir,Layout::logdir) instead of an empty string. Thismeans validation runs normally on every record — no special cases needed.
Replaces the
RecConfigOverrideFromRunroot()strcmp chain with aconstexprlookup table that maps record names directly to
Layout::*pointer-to-member.Adds debug-level log messages at all three call sites:
'record_name' overridden with 'value' by environment variable|runrootPreserves
nullptrfor built-in defaults that are intentionally unset(e.g.
proxy.config.ssl.keylog_file). This is safe because allnullptr-default records are
RECD_STRINGandRecDataSetFromStringhandles nullptr for that type.