我会这样做:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define HUGE_BUFFER_SIZE 4096
int main (int argc, char **argv) {
static char buf[HUGE_BUFFER_SIZE + 1];
char servername[200];
int target_len, servername_len, buf_len = 0;
char *out = NULL;
strcpy(buf, "this is my test buffer!");
strcpy(servername, "127.0.0.1");
/* Notice the uses of strnlen. Each of these fixes the maximum number of characters that will be scanned. */
servername_len = strnlen(servername, HUGE_BUFFER_SIZE+1) + 1;
buf_len = strnlen(buf, 200) + 4;
target_len = servername_len, buf_len;
if ((out = alloca(target_len)) == NULL)
return EXIT_FAILURE; /* alloc failed, die quickly! */
/* At this point, you've measured the length of servername and buf using strlen, so it should really be impossible to run beyond the length of your buffer, but we're going to be careful, anyway */
out[0] = '\0';
strncat(out, servername, servername_len);
strncat(out, buf, buf_len);
printf("%s\n", out);
return EXIT_SUCCESS;
}
(除非出现复制/粘贴错误,或者系统上的不同库以及我的跨平台错误,您应该能够将其粘贴到文件中,编译并运行它,然后查看“127.0.0.1this is我的测试缓冲区!”作为输出)
请注意,所有 str 函数,无论是 strcpy、strcat、strncpy 还是 strlcpy,都会将空终止符放在它们创建的任何字符串的末尾。唯一需要手动放置空终止符的时候是在开始一个全新的字符串时,就像我对语句“out[0] = '\0'”所做的那样。
另外,请注意我使用的是 strnlen 和 strncat,而不是 strlcat。除了函数返回的内容外,我无法从文档中看出 strlcat 和 strncat 之间的区别。
无论如何,您应该能够避免缓冲区溢出安全漏洞,只是清楚地限制所有函数调用。strncpy 和 strncat 绑定了您将复制多少数据。strnlen 限制系统搜索“\0”的时间。
编辑:我原来的解决方案实际上有一个 valgrind 揭示的错误。我没有初始化 buf 或 servername。虽然其他东西似乎在神奇地初始化 buf,但 valgrind 报告说,以 servername 作为目标调用 strcat 会导致根据未初始化的数据做出决策。 多哈_
由于我不确定为什么要调用 strcat 来用字符串文字初始化我的变量,所以我切换到 strcpy。当然,这在这里是完全安全的,因为我已经将复制到变量中的字符串完全硬编码到应用程序中。