Является ли sprintf (buffer, "% s [...]", buffer, [...]) безопасным?
Я видел использование этого шаблона для конкатенации строки в некотором коде, над которым я работал:
sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id);
sprintf(buffer, "%s</td>", buffer);
и я уверен, что это не безопасно C. Вы заметите, что buffer
- это как выход, так и первый вход.
Помимо очевидной возможности переполнения буфера, я считаю, что нет гарантии, что буфер не будет изменен между началом и концом функции (т.е. нет гарантии того, что состояние буфера будет во время выполнения функции). Подпись sprintf дополнительно указывает, что целевая строка restrict
ed.
Я также вспоминаю отчет о умозрительном письме в memcpy, и я не вижу причин, по которым некоторые библиотеки C могли бы делать то же самое в Sprintf. В этом случае, конечно, это будет писать его источник. Таким образом безопасно ли это поведение?
FYI, я предложил:
char *bufEnd = buffer + strlen(buffer);
/* sprintf returns the number of f'd and print'd into the s */
bufEnd += sprintf(bufEnd, " <input type='file' name='%s' />\r\n", id);
чтобы заменить это.
Ответы
Ответ 1
В документации glibc sprintf():
Поведение этой функции undefined, если происходит копирование между объектами, которые перекрываются - для Например, если s также задано как аргумент для печати под контролем преобразования% s.
Это может быть безопасно в конкретной реализации; но вы не могли рассчитывать на то, что он переносится.
Я не уверен, что ваше предложение будет безопасным и во всех случаях. Вы все еще можете быть перекрывающимися буферами. Это поздно, и моя жена беспокоит меня, но я думаю, что вы все еще можете иметь случай, когда вы хотите снова использовать исходную строку в конкатенированной строке и перезаписываете нулевой символ, и поэтому реализация sprintf может не знать, где повторно используется конец строки.
Вы можете просто привязать snprint() к временному буфере, а затем strncat() в исходный буфер.
Ответ 2
В этом конкретном случае он будет работать, потому что строка в buffer
будет первой вещью, которая войдет в buffer
(опять же, бесполезно), поэтому вы должны использовать strcat()
вместо этого, чтобы получить [почти] тот же эффект.
Но если вы пытаетесь объединить strcat()
с возможностями формирования sprintf()
, вы можете попробовать следующее:
sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
Ответ 3
Если вы хотите объединить форматированный текст в конец буфера с помощью printf(), я бы рекомендовал вам использовать целое число для отслеживания конечной позиции.
int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
i += sprintf(&buffer[i], "</td>");
или
int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
strcat(&buffer[i], "</td>");
И до того, как люди уйдут с ума, это будет ( "Это небезопасно! Вы можете перехватить буфер!" ), я просто рассматриваю разумный способ построения отформатированной строки в C/С++.