怎样才能更安全地编写这个C片段?

时间:2009-05-26 16:49:51

标签: c memory-management cstring null-terminated strdup

我有以下C代码片段,必须识别错误并建议更安全地编写它的方法:

char somestring[] = "Send money!\n";
char *copy;

copy = (char *) malloc(strlen(somestring));

strcpy(copy, somestring);
printf(copy);

所以错误是strlen忽略了字符串的尾随'\0',因此不会为副本分配足够的内存但是我不确定他们在编写更多内容安全

我可以使用malloc(strlen(somestring)+1))我假设但我认为必须有比这更好的方法吗?


编辑:好的,我已经接受了答案,我怀疑我们不会期待strdup解决方案,因为它不是ANSI C的一部分。这似乎是一个非常主观的问题所以我不确定我接受的是否真的是最好的。无论如何,谢谢你的所有答案。

10 个答案:

答案 0 :(得分:7)

我不能对上面的回答发表评论,但除了检查之外 返回代码并使用strncpy,你永远不应该这样做:

printf(string)

但请使用:

printf("%s", string);

参考:http://en.wikipedia.org/wiki/Format_string_attack

答案 1 :(得分:6)

char somestring[] = "Send money!\n";
char *copy = strdup(something);

if (copy == NULL) {
    // error
}

或者只是将此逻辑放在单独的函数 xstrdup

char * xstrdup(const char *src) 
{
    char *copy = strdup(src);

    if (copy == NULL) {
       abort();
    }

    return copy;
}

答案 2 :(得分:4)

char   somestring[] = "Send money!\n";
char   *copy;
size_t copysize;

copysize = strlen(somestring)+1;
copy = (char *) malloc(copysize);
if (copy == NULL)
    bail("Oh noes!\n");

strncpy(copy, somestring, copysize);
printf("%s", copy);

注意上述差异:

  • 必须检查malloc()的结果!
  • 计算并存储内存大小!
  • 使用strncpy()因为strcpy()很顽皮。在这个人为的例子中,它不会受到伤害,但不会养成使用它的习惯。

修改

对于那些认为我应该使用strdup()的人...只有在你对问题采取最狭隘的观点时才有效。这不仅是愚蠢的,而是忽略了一个更好的答案:

char somestring[] = "Send money!\n";
char *copy = somestring;
printf(copy);

如果你会变得迟钝,至少要擅长它。

答案 3 :(得分:3)

  1. strlen + 1,用于\ 0终止符
  2. malloc可能会失败;总是检查malloc返回值

答案 4 :(得分:3)

Ick ...像其他人一样使用strdup()并自己写,如果必须的话。由于您现在有时间考虑这个问题...请查看25 Most Dangerous Programming Errors at Mitre,然后考虑为什么短语printf(copy) 从不出现在代码中。那就是malloc(strlen(str))就完全不好而言,更不用说在复制类似于"%s%n"的时候追踪它为什么会引起很多悲伤的头痛......

答案 5 :(得分:1)

我会评论以前的解决方案,但我没有足够的代表。 在这里使用 strncpy 与使用 strcpy 一样错误(因为绝对没有溢出的风险)。 < 中有一个名为 memcpy 的函数string.h> ,它正是为了这个。它不仅显着更快,而且还可以用于在标准C中复制已知长度的字符串的正确函数。

从接受的答案:

char   somestring[] = "Send money!\n";
char   *copy;
size_t copysize;

copysize = strlen(somestring)+1;
copy = (char *) malloc(copysize);
if (copy == NULL)
    bail("Oh noes!\n");

memcpy(copy, somestring, copysize); /* You don't use str* functions for this! */
printf("%s", copy);

答案 6 :(得分:1)

使代码更安全(更正确)的方法。

  1. 不要制作不必要的副本。从示例中,没有明显要求您确实需要复制somestring。您可以直接输出。
  2. 如果你必须复制一个字符串,写一个函数来做(或者如果你有它就使用strdup)。然后你只需要在一个地方把它弄好。
  3. 尽可能在声明时立即初始化指向副本的指针。
  4. 请记住为null终止符分配空间。
  5. 请务必检查malloc
  6. 的返回值
  7. 请记得释放malloc'ed memory。
  8. 不要使用不受信任的格式字符串调用printf。使用printf("%s", copy)puts(copy)
  9. 使用带有字符串类或任何内置字符串支持语言的面向对象语言来避免大多数这些问题。

答案 7 :(得分:1)

为Adrian McCarthy提供更多更安全代码的方法,

使用静态代码分析器,他们非常善于发现这种错误

答案 8 :(得分:0)

如果一个人真的对这样的事情感兴趣的话,更安全地写它的最好方法就是在Ada中写它。

somestring : constant string := "Send money!";
declare
   copy : constant string := somestring;
begin
   put_line (somestring);
end;

结果相同,那么有什么区别?

  • 整个事情都是在堆栈上完成的 (没有指针)。解除分配是 自动安全。
  • 所有内容都经过自动范围检查 没有缓冲区溢出的可能性 利用
  • 两个字符串都是常量, 所以没有机会搞砸了 并修改它们。
  • 它可能比C语言更快,这不仅是因为缺乏动态分配,还因为没有通过strlen()所需的字符串进行额外扫描。

请注意,在Ada中,“string”不是一些特殊的动态构造。它是内置的字符数组。但是,Ada数组的大小可以通过您指定的数组进行声明。

答案 9 :(得分:-2)

更安全的方法是使用strncpy代替strcpy。该函数采用第三个参数:要复制的字符串的长度。此解决方案不会超出ANSI C,因此这将适用于所有环境(而其他方法可能只适用于POSIX兼容系统)。

char somestring[] = "Send money!\n";
char *copy;

copy = (char *) malloc(strlen(somestring));

strncpy(copy, somestring, strlen(somestring));
printf(copy);