Fix segfault and 404s with if blocks and inherited proxy_cache_purge - #69
Merged
denji merged 3 commits intoSep 23, 2026
Merged
Conversation
The inline form (proxy_cache_purge PURGE from ...) is accepted in a
location that has no proxy_cache of its own, either written there
directly or inherited from the server level. In such a location both
u->conf->cache_zone and u->conf->cache_value are NULL at request time,
and ngx_http_cache_purge_cache_get() passed the NULL complex value to
ngx_http_complex_value(), which dereferences it:
nginx[1297]: segfault at 18 ip ... error 4 in nginx
(ngx_http_complex_value+0x1b: mov 0x18(%rsi),%rdi -> val->lengths)
Return 404 and log an error instead. All four callers (fastcgi, proxy,
scgi, uwsgi) pass the return code straight through as the response.
An "if" block inside a location creates an anonymous child location.
When the 3-argument form (proxy_cache_purge zone key) is used in the
parent, the child inherits proxy.enable == 0 but not the zone and key,
which live in proxy_separate_zone / proxy_separate_value /
proxy_separate_key. r->content_handler is still the purge handler of
the parent, so a request that takes the if-branch runs the handler with
the child's config, fails the separate-syntax check and falls through
to the inline code path, where no cache is configured.
A common configuration triggers this for every request with a query
string:
location ~ "/purge(?<path>/.*)$" {
set $params "";
if ($args != "") {
set $params ?$args;
}
proxy_cache_purge zone GET$path$params;
}
Without the previous commit this was a segfault; with it, a 404.
Copy the three fields from the parent in merge_loc_conf when the child
does not configure proxy_cache_purge itself.
…inherited Commit 11b1c94 takes original_handler from the parent whenever the purge directive was not set in the location itself, to handle the anonymous child location that nginx creates for an "if" block. The same condition is true for every named location that inherits the directive from the server level or from an enclosing location, for example: server { proxy_cache_purge PURGE from 127.0.0.1; location / { proxy_pass http://backend; proxy_cache zone; } } There prev->original_handler is the server-level value, NULL, so every non-PURGE request to "location /" returned 404 instead of being proxied. v3.0.2 is not affected. Take the parent's handler only for anonymous (if / limit_except) locations, identified by clcf->noname.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Segfault on PURGE in a location without
proxy_cache(inline form,set directly or inherited from the server level).
ngx_http_cache_purge_cache_get()passed a NULLcache_valuetongx_http_complex_value(). Seen in production on nginx 1.30.4:segfault at 18 ... in nginx(val->lengths). Now returns 404 and logs an error.The 3-arg form did not survive an
ifblock. The anonymous if-childlocation did not inherit
proxy_separate_zone/value/key, so e.g.if ($args != "") { set $params ?$args; }sent every request with aquery string down the inline path: a segfault before fix 1, a 404 after it.
Regression from 11b1c94: with
proxy_cache_purgeat the server level,every non-PURGE request to a
proxy_passlocation returned 404, becauseprev->original_handler(the server-level NULL) was inherited by namedlocations too. It is now inherited only by anonymous (
if/limit_except)locations (
clcf->noname). v3.0.2 is not affected.Tested with t/Dockerfile: all five suites pass on nginx 1.28.2 and 1.30.4.
Without the patches, TEST 21-24 fail on current master.