strlcpy还是memcpy?

时间:2012-09-27 03:25:59

标签: c

我知道在处理缓冲区时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?

3 个答案:

答案 0 :(得分: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()始终为null - 终止结果字符串)。

答案 1 :(得分: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.1这是我的测试缓冲区!“作为输出)

请注意,所有str函数(无论是strcpy,strcat,strncpy还是strlcpy)都会将null终止符拖放到它们创建的任何字符串的末尾。你需要手动设置一个空终止符的唯一一次是当你开始一个全新的字符串时,就像我使用语句“out [0] ='\ 0'”那样。

另外,请注意我使用的是strnlen和strncat,而不是strlcat。我无法从文档中看出strlcat和strncat之间的区别,除了函数返回的内容。

无论如何,你应该能够避免缓冲区溢出安全漏洞,只是明确地绑定所有函数调用。 strncpy和strncat绑定了要复制的数据量。 strnlen限制系统搜索'\ 0'的时间。


编辑:我的原始解决方案实际上有一个valgrind透露的错误。我没有初始化buf或servername。虽然其他东西似乎神奇地初始化了buf,但是valgrind报告说,使用servername作为目标调用strcat会导致基于未初始化数据的决策。 DOH

因为我不确定为什么我用字符串文字调用strcat来初始化我的变量,所以我切换到了strcpy。当然,这在这里是非常安全的,因为我已经将应用程序硬编码到我正在复制到变量中的字符串。

答案 2 :(得分:0)

我认为你必须输出乱码的原因是因为你可能正在使用sizeof out。但是,out不是一个缓冲区而且是一个指针,所以你可能只是有效地传递4(或指针的大小)作为第三个参数的大小,通过不复制超过3个字符和休息是显示垃圾的非真实记忆

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