为什么strcpy到文字编译?

Vin*_*ert 2 c strcpy visual-studio

在Visual Studio 2015中,以下编译:

strcpy("destination", "Source");
Run Code Online (Sandbox Code Playgroud)

编译器是否应该弄清楚"destination"是一个文字并且不能构成有效的非const char*参数?

作为旁注,它在运行时"正确"崩溃.

Pet*_*ica 6

上下文

字符串文字在C中一直是非常量的.目前的标准草案n1570在6.4.5/6中说:

然后使用多字节字符序列[由相邻字符串文字的串联产生,-ps]来初始化静态存储持续时间和长度的数组,数组足以包含该序列.对于字符串文字,数组元素的类型为char [而不是const char,-ps].

当然,原因是它们最初确实是可写的.该计划本身是可写的; 甚至还有自我修改代码.这是相关的,因为字符串文字是由编译器"与程序一起"生成和存储的.

它是现代内存管理 - 即高级机器架构的问题 - 这使得在访问程序的内存时可以生成硬件异常.使用这种可能性是一个安全问题.并非所有架构(都可以)都能做到这一点,即使在今天,编译器也可以选择控制字符串的位置(例如-fwritable-strings使用旧的gcc).

本准则

在语法上,代码是兼容的,在语义上它是n1570中的每6.4.5/7的UB:"如果程序试图修改这样的数组,则行为是未定义的."

当字符串文字的地址被分配给非常量变量时​​(或者用于在函数调用中初始化非常量参数),编译器可以发出警告,但我尝试过的常见问题并没有发出警告,这让我感到困惑 - 很多实现警告似乎不那么重要和吵闹.

的strcpy()

至于具体情况strcpy():有些评论说"编译器不知道是什么strcpy()".这往往是误导性的:

  • 标准库函数由标准明确定义.这些知识可以在编译器中使用.例如,像lint通常知道这种语义的工具.
  • 编译器和默认标准库通常是密切合作开发的,并且是捆绑在一起的; 因为在编译库本身,编译器引导等方面,编译器和库之间存在大量的交互,通常在两个项目之间定期进行交换.
  • 编译器可以自由地用内在函数替换库函数,这将给予他们非常熟悉的知识.

GCC

实际上,gcc碰巧strcpy用内置函数替换了许多其他函数,因此它确实具有第一个地址将被写入的第一手资料.它只是不使用它.

另一个gcc内在的是printf(),这里编译器使用其printf语义知识来警告格式错误.这清楚地表明也可能发出警告strcpy().

另外,gcc 确实警告过"abc"[1] = 0;.那是因为我曾认为是有趣的strcpy()内在会被内联(必须是短),以便用-O3,并可能-flto在某个时刻相当于"destination"[i] = "Source"[i];实际上是编译器可见光和触发同样的警告.

其他编译器

我测试了VC 2013,gcc 5.3.0,gcc 4.7.2和clang 3.7.1.它们都没有发出传递字符串文字的警告strcpy(),但是cremno指出VC提供了/analyze捕获错误的选项.