strcat vs strncat - 什么时候应该使用哪个函数?

Jay*_*Jay 8 c string

一些静态代码分析器工具建议为了安全起见,所有strcat用法应该替换为strncat?

在程序中,如果我们清楚地知道目标缓冲区和源缓冲区的大小,是否仍然建议使用strncat?

另外,根据静态工具的建议,是否应该使用strcat?

Pan*_*mar 13

将两个字符串连接成一个字符串.

原型

#include <string.h>

char * strcat(char *restrict s1, const char *restrict s2);

char * strncat(char *restrict s1, const char *restrict s2, size_t n);
Run Code Online (Sandbox Code Playgroud)

描述

strcat()strncat()功能追加空终止字符串的副本S2至空终止字符串S1的结尾,然后添加终止\ 0' .字符串s1必须有足够的空间来保存结果.

strncat()函数从s2追加不超过n个字符,然后添加一个终止\ 0'.

源字符串和目标字符串不应重叠,因为行为未定义.

返回值

 The `strcat()` and `strncat()` functions return the pointer s1.
Run Code Online (Sandbox Code Playgroud)

安全考虑

strcat()功能很容易被滥用,使恶意用户能够通过缓冲区溢出攻击任意改变正在运行的程序的功能.

避免使用strcat().相反,使用strncat()strlcat()确保不再将任何字符复制到目标缓冲区而不是它可以容纳.

请注意,这strncat()也可能有问题.根本要截断字符串可能是一个安全问题.由于截断的字符串不会与原始字符串一样长,因此它可能指的是完全不同的资源,截断资源的使用可能导致非常不正确的行为.例:

void
 foo(const char *arbitrary_string)
 {
         char onstack[8] = "";

 #if defined(BAD)
         /*
          * This first strcat is bad behavior.  Do not use strcat!
          */
         (void)strcat(onstack, arbitrary_string);        /* BAD! */
 #elif defined(BETTER)
         /*
          * The following two lines demonstrate better use of
          * strncat().
          */
         (void)strncat(onstack, arbitrary_string,
             sizeof(onstack) - strlen(onstack) - 1);
 #elif defined(BEST)
         /*
          * These lines are even more robust due to testing for
          * truncation.
          */
         if (strlen(arbitrary_string) + 1 >
             sizeof(onstack) - strlen(onstack))
                 err(1, "onstack would be truncated");
         (void)strncat(onstack, arbitrary_string,
             sizeof(onstack) - strlen(onstack) - 1);
 #endif
 }
Run Code Online (Sandbox Code Playgroud)

char dest[20] = "Hello";
char *src = ", World!";
char numbers[] = "12345678";

printf("dest before strcat: \"%s\"\n", dest); // "Hello"

strcat(dest, src);
printf("dest after strcat:  \"%s\"\n", dest); // "Hello, World!"

strncat(dest, numbers, 3); // strcat first 3 chars of numbers
printf("dest after strncat: \"%s\"\n", dest); // "Hello, World!123"
Run Code Online (Sandbox Code Playgroud)


Juh*_*uho 11

如果您完全确定源缓冲区的大小并且源缓冲区包含终止字符串的NULL字符,那么当目标缓冲区足够大时,您可以安全地使用strcat.

我仍然建议使用strncat并给它目标缓冲区大小 - 目标字符串的长度 - 1

注意:我编辑了这个,因为评论指出我之前的回答是非常错误的.

  • 这个答案是危险的错误.@Nemo让它更接近,但我认为仍然是一个人.[Pankaj的回答](http://stackoverflow.com/a/6502352/228539)看似准确,而且非常详细.它必须是'目标缓冲区的大小 - 目标字符串的长度 - 1'以适当地避免缓冲区溢出.虽然这在设计这个函数时似乎是一个愚蠢的选择,因为它必须在开始复制之前固有地寻找null终止符,并且可以计算沿途的长度,所以我们不必两次这样做. (5认同)