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