Re: Fwd: SIGABRT в самописном модуле
Maxim Dounin
mdounin на mdounin.ru
Ср Фев 24 12:48:41 UTC 2016
Hello!
On Mon, Feb 22, 2016 at 12:25:42PM +0600, Alexander Uskov wrote:
[...]
> Есть самописный модуль со следующей задачей:
> Поймать обращение у url, если есть определенный GET параметр, то отдать файл с диска, поменяв в нем %V на значение параметра,
> если нет, то попытаться прочесть значение куки, если нет и его, то сгенерить этот параметр и сделать постоянный редирект на
> ?параметр=значение.
>
> Модуль писал года 2 назад, сам в C сильно плаваю.
> Скомпилинное решение сейчас работает в продакшине.
> Попытался пересобрать всё на новой машине (пересборка того, что сейчас работает дала такие-же результаты),
> появилась проблемма:
[...]
> Вылазит не на все запросы, а только под нагрузкой :( Поэтому дианностировать сильно сложно.
>
> Насколько смог отдиагностировать, проблема появляется именно в части, когда идет запрос без параметра.
> Т-е проблема где-то в следующем участке кода:
>
> // Проверяю, передано ли что в GET, передано ли GET['c'] и его длинну, если да, ни чего не делаю, иначе - редирект.
> if (r->args.len &&
> ngx_http_arg(r, (u_char *) zero_js_config->get_parm.data, zero_js_config->get_parm.len, &get_c) == NGX_OK &&
> get_c.len <=14 &&
> get_c.len>10) {
> /* void() */
> } else {
> // Отдаем редирект с кукой в GET
>
> // Пытаемся найти COOKIE['client_cc']
> n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &zero_js_config->cookie_name, &cookie);
>
> // Если кука есть и ее длинна <=14 заносим значение в uniqid иначе генерим php_uniqid()
> if (n != NGX_DECLINED && cookie.len<=14) {
> ngx_sprintf(uniqid, "%V", &cookie);
При этом переменная uniqid как инициализируется?
Потому что ngx_sprintf() в общем случае строку не терминирует
нулём, и если uniqid просто объявлен как массив символов на стеке -
\0 в конце никто не обещал.
> } else {
> ngx_gettimeofday(&tv);
> sec = (int) tv.tv_sec;
> usec = (int) (tv.tv_usec % 0x100000);
> ngx_sprintf(uniqid, "%i%08xi%05xi", ngx_random() % 10, sec, usec);
И то же самое тут.
> }
>
> // создаем url для редиректа
> turl = ngx_pcalloc(r->pool, sizeof("?=") - 1 + zero_js_config->get_parm.len + sizeof(uniqid));
> if (turl == NULL) {
> return NGX_HTTP_INTERNAL_SERVER_ERROR;
> }
> ngx_sprintf(turl, "?%V=%s", &zero_js_config->get_parm, uniqid);
А вот тут вы печатаете uniqid как %s, т.е. как null-terminated
строку. Соответственно если \0 в конце не будет - будут проблемы.
> // Вставляем Location
> r->headers_out.location = ngx_list_push(&r->headers_out.headers);
> if (r->headers_out.location == NULL) {
> return NGX_ERROR;
> }
> r->headers_out.location->hash = 1;
> r->headers_out.location->key.len = sizeof("Location") - 1;
> r->headers_out.location->key.data = (u_char *) "Location";
> r->headers_out.location->value.len = sizeof("?=") - 1 + zero_js_config->get_parm.len + sizeof(uniqid);
> r->headers_out.location->value.data = turl;
Кроме того, вот тут используется sizeof(uniqid) вместо реальной
длины содержимого uniqid. Соответственно в выводе может быть не
всё либо дополнительный мусор.
Совет: используйте для строк ngx_str_t, с явным указанием длины
содержимого. Обе проблемы должны исчезнуть сами по себе.
[...]
--
Maxim Dounin
http://nginx.org/
Подробная информация о списке рассылки nginx-ru