Среди этих вариантов я бы просто использовал strcpy
.По крайней мере, strcpy_s
и lstrcpy
- это пустышки, которые никогда не должны использоваться.Возможно, стоит исследовать эти независимо написанные библиотечные функции, но я бы не решался использовать нестандартный библиотечный код в качестве панацеи для обеспечения безопасности строк.
Если вы используете strcpy
, вам нужно быть увереннымваша строка помещается в буфер назначения.Если вы только что выделили его размером не менее strlen(source)+1
, все будет в порядке, если исходная строка не может быть одновременно изменена другим потоком.В противном случае вам нужно проверить, помещается ли он в буфер.Вы можете использовать такие интерфейсы, как snprintf
или strlcpy
(нестандартная функция BSD, но легко скопировать реализацию), которые будут обрезать строки, которые не помещаются в целевой буфер, но тогда вам действительно нужно оценить, может ли обрезание строки привести куязвимости в себе.Я думаю, что гораздо лучший подход при тестировании, подходит ли исходная строка, состоит в том, чтобы создать новое распределение или вернуть состояние ошибки, а не выполнять слепое усечение.
Если вы будете выполнять много операций конкатенации / сборки строк,Вы действительно должны написать весь свой код, чтобы управлять длиной и текущей позицией на ходу.Вместо:
strcpy(out, str1);
strcat(out, str2);
strcat(out, str3);
...
Вы должны сделать что-то вроде:
size_t l, n = outsize;
char *s = out;
l = strlen(str1);
if (l>=outsize) goto error;
strcpy(s, str1);
s += l;
n -= l;
l = strlen(str2);
if (l>=outsize) goto error;
strcpy(s, str2);
s += l;
n -= l;
...
В качестве альтернативы вы можете избежать изменения указателя, сохраняя текущий индекс i
типа size_t
и используяout+i
, или вы можете избежать использования переменных размера, сохраняя указатель на конец буфера и выполняя такие действия, как if (l>=end-s) goto error;
.
Обратите внимание, что при любом подходе избыточность может быть сокращенанаписание собственных (простых) функций, которые принимают указатели на переменную position / size и вызывают стандартную библиотеку, например что-то вроде:
if (!my_strcpy(&s, &n, str1)) goto error;
Избегание strcat
также имеет преимущества в производительности;см. Алгоритм Шлемеля-рисовальщика .
Наконец, вы должны заметить, что хорошие 75% людей, выполняющих копирование и сборку строк в C, совершенно бесполезны.Моя теория состоит в том, что люди, делающие это, происходят из языков сценариев, где сборка строк - это то, что вы делаете все время, но в Си это часто бывает бесполезно.Во многих случаях вы можете обойтись без копирования строк, используя вместо этого оригинальные копии, и в то же время получить гораздо лучшую производительность и более простой код.Мне вспоминается недавний вопрос SO, в котором OP использовал regexec
для сопоставления регулярному выражению, а затем копировал результат просто для его печати, что-то вроде:
char *tmp = malloc(match.end-match.start+1);
memcpy(tmp, src+match.start, match.end-match.start);
tmp[match.end-match.start] = 0;
printf("%s\n", tmp);
free(tmp);
То же самое можно сделатьс:
printf("%.*s\m", match.end-match.start, src+match.start);
Без выделения ресурсов, без очистки, без ошибок (исходный код вылетал при сбое malloc
).