0

我知道 strcpy 在处理缓冲区时不安全,但是在我的代码中我有这个

static char    buf[HUGE_BUFFER_SIZE + 1];
char servername[200];
int length = 0;
char *out = NULL;
        length = strlen(buf);
        out = alloca(strlen(servername) + length + 5);
        length = strlen(servername);
        strcpy(out, servername);
        out[length] = ' ';
        out[length + 1] = 0;
        strcat(out, buf);

如果我将 strcpy 更改为 strlcpy 并将 sizeof 用于 arg3,则输出会出现乱码。有没有比使用 memcpy 更简单的方法(看起来我可能不得不这样做?)我试图避免使用像 strcpy 和朋友这样的不安全函数。有没有更简单的方法来完成上述功能的复制更少,以及 strnlens/alloca?

4

3 回答 3

2

使用它可能更简单snprintf()

char out[1000];  // Or however large you need.
int len = snprintf(out, sizeof(out), "%s %s", servername, buf);
if (len >= sizeof(out)) {
    // Result would have overflowed the buffer and has been truncated.
}

注意>=而不是>在条件中。

snprintf()返回写入文本的长度,不包括终止的空字节。因此,如果返回值等于缓冲区大小,则意味着最后一个字符被截断(因为snprintf()总是以空值结尾的结果字符串)。

于 2012-09-27T03:39:51.173 回答
1

我会这样做:

#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。当然,这在这里是完全安全的,因为我已经将复制到变量中的字符串完全硬编码到应用程序中。

于 2012-09-27T04:00:53.983 回答
0

我认为你必须得到乱码输出的原因是因为你可能正在使用 sizeof out。但是,out它不是缓冲区,而是指针,因此您可能仅将 4(或指针的大小)作为第三个参数的大小传递给第三个参数,因此不复制超过 3 个字符,其余字符是未初始化的向你展示垃圾的内存

您可以尝试使用 strncpy 并将要复制的长度作为第三个参数传递。

于 2012-09-27T03:34:12.953 回答