﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	resolution	keywords	cc	uname	nginx_version
2447	A segment error occurred in ngx_http_variable_headers_internal	bullerdu@…		" Nginx is compiled with lua-nginx-module(V0.10.23), and runs ngx_lua case `TEST 46: clear all and re-insert`(https://github.com/openresty/lua-nginx-module/blob/v0.10.23rc1/t/028-req-header.t) , then crashes in line `if (th->hash == 0) {`.


{{{
static ngx_int_t
ngx_http_variable_headers_internal(ngx_http_request_t *r,
    ngx_http_variable_value_t *v, uintptr_t data, u_char sep)
{
    size_t            len;
    u_char           *p;
    ngx_table_elt_t  *h, *th;

    h = *(ngx_table_elt_t **) ((char *) r + data);

    len = 0;

    for (th = h; th; th = th->next) {

        if (th->hash == 0) {
            continue;
        }

        len += th->value.len + 2;
    }

    if (len == 0) {
        v->not_found = 1;
        return NGX_OK;
    }

    len -= 2;

    v->valid = 1;
    v->no_cacheable = 0;
    v->not_found = 0;

    if (h->next == NULL) {
        v->len = h->value.len;
        v->data = h->value.data;

        return NGX_OK;
    }

    p = ngx_pnalloc(r->pool, len);
    if (p == NULL) {
        return NGX_ERROR;
    }

    v->len = len;
    v->data = p;

    for (th = h; th; th = th->next) {

        if (th->hash == 0) {
            continue;
        }

        p = ngx_copy(p, th->value.data, th->value.len);

        if (th->next == NULL) {
            break;
        }

        *p++ = sep; *p++ = ' ';
    }

    return NGX_OK;
}
}}}


The reason was that nginx modified `ngx_table_elt_t` data structure in commit(f8f6b9fee66a), and reworked multi headers to use linked lists in commit(ef6a3a99a81a), but lua-nginx-module was not set NULL in `ngx_table_elt_t ` next field.


So, Can `ngx_table_elt_t` be initialized, Since `r->headers_in.headers` 
 alloc in `ngx_list_init`, or one header alloc in `ngx_list_push`?

Replace ngx_palloc with ngx_pcalloc, so `ngx_table_elt_t` next field is NULL, and do not manually set next field in commit(ef6a3a99a81a).

This reduces the probability of forgetting to set the Next field.


{{{
static ngx_inline ngx_int_t
ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
{
    list->part.elts = ngx_palloc(pool, n * size);
    if (list->part.elts == NULL) {
        return NGX_ERROR;
    }

    list->part.nelts = 0;
    list->part.next = NULL;
    list->last = &list->part;
    list->size = size;
    list->nalloc = n;
    list->pool = pool;

    return NGX_OK;
}

void *
ngx_list_push(ngx_list_t *l)
{
    void             *elt;
    ngx_list_part_t  *last;

    last = l->last;

    if (last->nelts == l->nalloc) {

        /* the last part is full, allocate a new list part */

        last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
        if (last == NULL) {
            return NULL;
        }

        last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
        if (last->elts == NULL) {
            return NULL;
        }

        last->nelts = 0;
        last->next = NULL;

        l->last->next = last;
        l->last = last;
    }

    elt = (char *) last->elts + l->size * last->nelts;
    last->nelts++;

    return elt;
}
}}}


"	defect	closed	minor		documentation	1.23.x	duplicate	HTTP HEADER		Linux cdn-dev011164234021.na61 4.19.91-008.ali4000.alios7.x86_64 #1 SMP Fri Sep 4 17:33:26 CST 2020 x86_64 x86_64 x86_64 GNU/Linux	"nginx version: nginx/1.19.1
built by gcc 9.3.0 (GCC)
built with OpenSSL 1.1.0 (compatible; BoringSSL) (running with BoringSSL)
TLS SNI support enabled
configure arguments: --with-debug --with-http_v3_module --add-module=/home/yefei.dyf/third-modules/lua-nginx-module --prefix=/home/yefei.dyf/nginx --with-cc-opt=-I/home/yefei.dyf/boringssl/include --with-ld-opt='-L/home/yefei.dyf/boringssl/ssl -L/home/yefei.dyf/boringssl/crypto'"
