Является ли sprintf(buffer, "%s [...]", buffer, [...]) безопасным?
Я видел использование этого шаблона для конкатенации на строку в некотором коде, над которым я работал:
sprintf(buffer, "%s <input type='file' name='%s' />rn", buffer, id);
sprintf(buffer, "%s</td>", buffer);
и я совершенно уверен, что это небезопасно C. Вы заметите, что buffer
- это и выход и первый вход.
помимо очевидной возможности переполнения буфера, Я считаю, что нет никакой гарантии, что буфер не будет изменен между началом и концом функции (т. е. нет никакой гарантии относительно того, что состояние буфера будет во время выполнения функции). Подпись sprintf дополнительно указывает, что целевой строкой является restrict
ed.
Я также вспоминаю отчет спекулятивное письмо в memcpy, и я не вижу причин, почему какая-то библиотека C может сделать то же самое в sprintf. В этом случае, конечно, он будет писать своему источнику. Так что это поведение безопасным?
к вашему сведению, я предложил:
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' />rn", id);
чтобы заменить это.
3 ответов
с документация по glibc sprintf ():
поведение этой функции не определено, выполняется ли копирование между объектами, которые накладываются на пример, если s также задается как аргумент для печати под контролем преобразования "%s".
Это может быть безопасным в конкретной реализации, но вы не могли рассчитывать на его портативный.
Я не уверен, что ваше предложение будет безопасно во всех случаях любой. Вы все еще можете быть перекрывающимися буферами. Это поздно, и моя жена меня достает, но я думаю, что у вас все еще может быть случай, когда вы хотите снова использовать исходную строку в конкатенированной строке и перезаписываете нулевой символ, и поэтому реализация sprintf может не знать, где заканчивается повторно используемая строка.
вы можете просто придерживаться snprint () в временном буфере, а затем strncat () его в исходный буфер.
в этом конкретном случае он будет работать, потому что строка в buffer
будет первое, что войдет в buffer
(опять же, бесполезно), поэтому вы должны использовать чтобы получить [почти] тот же эффект.
но, если вы пытаетесь объединить strcat()
С формирующими возможностями sprintf()
, вы можете попробовать это:
sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
Если вы хотите объединить форматированный текст в конец буфера с помощью 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>");
и прежде чем люди пойдут Берсерк downvoting это ("это не безопасно! Вы можете захватить буфер!"), Я просто обращаюсь к разумному способу создания форматированной строки на C / C++.