ngx_chain_get_free_buf crashes with free=0 after return next_body_filter

Maxim Dounin mdounin at mdounin.ru
Mon Dec 3 18:09:49 UTC 2012


Hello!

On Mon, Dec 03, 2012 at 09:27:36PM +0400, Ruslan Khusnullin wrote:

> Hello, I cannot find an issue root cause and hope for your help.
> 
> My nginx plugin crashes and core dumps on the line containing return in
> body_filter function:
> 
> ngx_http_output_body_filter_pt my_next_body_filter;
> static ngx_int_t ngx_http_my_init (ngx_conf_t * cf) {
>     my_next_body_filter = ngx_http_top_body_filter;
>     ngx_http_top_body_filter = ngx_http_my_body_filter;
>     return NGX_OK;
> }
> 
> static ngx_http_module_t ngx_http_my_module_ctx = {
>     NULL,                                /* preconfiguration */
>     ngx_http_my_init,            /* postconfiguration */
>     ...
> };
> 
> static ngx_int_t ngx_http_my_body_filter (ngx_http_request_t * r,
> ngx_chain_t * in) {
>     ngx_http_my_loc_conf_t * cf;
>     cf = ngx_http_get_module_loc_conf (r, ngx_http_my_module);
>     if (cf == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR;

Note: returning NGX_HTTP_INTERNAL_SERVER_ERROR is completely wrong 
here, and it will result in undefined behaviour if ever returned.

You should either return NGX_ERROR here (probably logging an alert 
message) or just assume it should never happen unless process 
memory is corrupted and just dereference the pointer (this way 
you'll get proper segmentation fault instead of undefined 
behviour).

>     if (! cf->enabled || in == NULL || r->header_only) {
>         return my_next_body_filter (r, in);
>     }
>     ...
> }
> 
> I saw the same (or very similar) return statement in other official modules
> and they seem no crashing. I can't understand why my module is crashing.
> 
> Here is what I've catched from gdb:
> (gdb) bt
> #0  ngx_chain_get_free_buf (p=0x80f5020, free=0x0) at src/core/ngx_buf.c:160
> #1  0x08089fbe in ngx_http_chunked_body_filter (r=0x80de458, in=0xbfffe798)
> at src/http/modules/ngx_http_chunked_filter_module.c:150

This part of the backtrace suggests the r->chunked flag was 
somehow set outside of chunked filter, with chunked filter context 
not set (== NULL).

[...]

> #16 0x080752a1 in ngx_http_send_error_page (r=0x80de458, error=500) at
> src/http/ngx_http_special_response.c:569
> #17 ngx_http_special_response_handler (r=0x80de458, error=500) at
> src/http/ngx_http_special_response.c:415
> #18 0x0807779b in ngx_http_finalize_request (r=0x80de458, rc=500) at
> src/http/ngx_http_request.c:2003
> #19 0x080842b2 in ngx_http_upstream_finalize_request (r=0x80de458,
> u=0x80f56ac, rc=500) at src/http/ngx_http_upstream.c:3095
> #20 0x080856c4 in ngx_http_upstream_process_non_buffered_request
> (r=0x80de458, do_write=<value optimized out>) at
> src/http/ngx_http_upstream.c:2437

Here the request is finalized with rc=500 according to the 
backtrace, but the line it claims to contain the call clearly uses 
rc=0.  This is probably an optimization artifact, but 500 here 
suggest the problem in your code outlined above might be related.

[...]

> So ngx_chain_get_free_buf gets null pointer and I can't understand why it
> does. The situation is: there is upstream configured and my body_filter
> works with it, it should be "invisible" (do not modify contents) if it's
> not enabled in config or whatelse (you can see conditions in the code
> above).
> 
> Any ideas on what I'm doing wrong?
> 
> nginx-1.2.5
> Linux 2.6.18 i686

See above for a possible explanation.

-- 
Maxim Dounin
http://nginx.com/support.html



More information about the nginx-devel mailing list