为什么C11标准不会丢弃不安全的strcat(),strcpy()函数?

时间:2015-06-17 05:36:49

标签: c strcpy c11 strcat

C11& C++14标准降低了gets()功能本身就不安全的功能导致安全问题,因为它不会在缓冲区溢出中执行边界检查结果。那么为什么C11标准不会放弃strcat()& strcpy()功能? strcat()函数不检查第二个字符串是否适合第一个数组。 strcpy()函数也不包含检查目标数组边界的规定。如果源数组有多于目标数组可以容纳的字符怎么办?程序很可能会在运行时崩溃。

那么,如果将这两个不安全的函数从语言中完全删除,那会不会很好?为什么他们仍然存在?是什么原因?没有像strncat(),strncpy()这样的函数可以吗?如果我没错,Microsoft C& C ++编译器提供了这些函数strcpy_s(),strcat_s()的安全版本。那么为什么他们没有被其他C编译器正式实施以提供安全性呢?

5 个答案:

答案 0 :(得分:11)

gets()本质上是不安全的,因为如果在stdin上收到太多数据,它通常会溢出目标。这样:

char s[MANY];
gets(s);
如果输入的字符数超过MANY

将导致未定义的行为,并且程序通常无法阻止它。

strcpy()strcat()可以完全安全地使用 ,因为只有当源字符串太长而无法包含在目标数组中时,它们才会溢出目标。源字符串包含在程序本身控制的数组对象中,而不是任何外部输入。例如,这个:

char s[100];
strcpy(s, "hello");
strcat(s, ", ");
strcat(s, "world");
除非程序本身被修改,否则

不可能溢出。

strncat()可以用作strcat()的更安全版本 - 只要您正确指定第三个参数即可。 strncat()的一个问题是它只给你一种方法来处理目标数组中没有足够空间的情况:它以静默方式截断字符串。有时这可能是你想要的,但有时候你可能想要检测溢出并做些什么。

对于strncpy()只是strcpy()的更安全版本。它本身并不危险,但是如果你不是很小心,你可以很容易地离开目标数组而没有终止'\0'空字符,导致下次将它传递给期望指向字符串的指针的函数时出现未定义的行为。碰巧,I've written about this

答案 1 :(得分:5)

strcpystrcatgets不相似。 gets的问题是,它用于从输入读取,所以它不受程序员控制是否会有缓冲区溢出。

C99 Rational将strncpy解释为:

  

Rationale for International Standard — Programming Languages — C§7.21.2.4strncpy函数

     最初将

strncpy引入C库以处理目录条目等结构中的固定长度名称字段。这些字段的使用方式与字符串不同:对于最大长度字段,尾部空值不是必需的,而将较短的5个字符的尾随字节设置为空可确保有效的字段比较。 strncpy不是来源于“有界strcpy”,,委员会倾向于认识到现有做法,而不是改变功能以更好地适应此类用途。

答案 2 :(得分:3)

  • 神话1:strcpy()不安全,它如何运作对于资深C程序员来说是一个惊喜。
  • 神话2:strncpy()是安全的。
  • 神话3:strncpy()是strcpy()的更安全版本。
  • 神话4:微软是使用C语言的某种权威,知道他们在谈论什么。

strcat()strcpy()perfectly safe functions

另请注意strncpy was never intended to be a safe version of strcpy。它用于古老版Unix中使用的模糊,过时的字符串格式。 strncpy实际上是very unsafeone of many blog post about it here),与strcpy不同,因为很少有程序员似乎能够使用前者而不会产生致命错误(无空终止)。

更好的问题是为什么本身不安全strncpy()没有从语言中删除。是否有人使用20世纪70年代的晦涩的Unix字符串?

答案 3 :(得分:1)

当删除函数完全时,标准必须主要考虑的一个主要问题是它可能会破坏多少代码以及有多少人(程序员,库编写者,编译器供应商等)会对这一改变感到恼火(或反对)。

gets()已被LSB(Linux Standard Base)弃用。 POSIX-2008使其过时,gets()历来被认为是严重坏函数,并且一直强烈建议不要在任何代码中使用。几乎每个C程序员都知道使用gets()会非常危险。因此,删除任何生产代码的可能性非常小,不存在,不存在。因此,委员会很容易从C11中删除gets()

strcpystrcat等情况并非如此。它们可以安全使用,许多程序员仍然会在新代码中使用它们。虽然它们可能会受到缓冲区溢出的影响,但它主要是程序员控制的,gets()不是。{1}}。

可以使用snprintf代替strcpystrcat进行论证。但在简单的情况下似乎毫无意义:

char buf[256];
strcpy(buf, "hello");

(如果buf是指针,那么需要跟踪分配大小以便在snprintf中使用)

因为作为程序员,我知道,以上是非常安全的。更重要的是,遗留代码的很多会破坏。基本上,没有强有力的论据可以删除strcpy等功能,因为它们可以安全使用。

答案 4 :(得分:0)

您所谈论的是会导致未定义行为的情景。

让我们说

char a[3] = "string";
for(i=0;i<5;i++)
printf("%c\n",a[i]);

你有数组越界访问权限,标准没有删除它,因为你正在分配值并且它在你的控制之下。

strcpy()strcat()相同。

因此标准不能删除导致UB的所有场景。

虽然我们知道gets()不是程序员控制的,而是从某些流中获取数据而你永远不知道输入可能是什么,并且很可能最终会出现缓冲区溢出,所以它有已删除,并添加了更安全的功能fgets()