我知道它与编译器优化有关,但我正在深入研究如何/为什么以及如何确保我在实际代码中收到此行为的通知。
我有这段代码
void swap(char *s)
{
strcpy(s, "nope!");
printf("Result: %s\n", s);
};
void main(){
...
swap("this should segfault");
...
}
显然,它应该是段错误,但是在发布模式下,visual studio会将其缩小为仅仅内联printf。
这似乎可以让我后来真的咬我,所以如果你能为我发光,我会很喜欢它。
为了完整起见,这里是预期的汇编
push offset s ; "this should segfault"
call j_?swap@@YAXPAD@Z ; swap(char *)
这是生成的程序集
push offset s ; "this should segfault"
push offset Format ; "Result: %s\n"
call ds:__imp__printf
以下是注释中所需的编译器选项
/GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Fd"Release\vc120.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_LIB" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Fp"Release\scratchpad2.pch"
答案 0 :(得分:1)
此行为已在VC ++ 2013和2015中得到确认。@ IgorTandetnik的评论是正确的。代码展示了UB(未定义的行为),而不崩溃就是这样一种行为。
也就是说,VC ++也因为在允许字符串文字到非const-char-pointer转换时没有发出(至少)警告的错误,因为(我认为)C ++ 0x已经弃用了 - 请参阅Why can a string literal be implicitly converted to char* only in certain case?和Why is passing a string literal into a char* argument only sometimes a compiler error?。您可以考虑在https://connect.microsoft.com/visualstudio处提交错误报告。
我知道它与编译器优化有关,但我正在深入研究如何/为什么以及如何确保我在实际代码中收到此行为的通知。
我对问题的后半部分没有答案。
关于如何/为什么,当优化为具有只读目标的strcpy
时,似乎是intrinsic
行为的问题。确实是一个相当奇怪的行为,因为它最终导致整个strcpy
被无声地跳过。
在#pragma function(strcpy)
之前添加swap
会导致它始终崩溃。
将调用代码更改为char z[] = "this should segfault"; swap(z);
将删除UB因子并使其始终有效。
<小时/> [编辑] 回到
how to ensure i am notified of this behaviour in real code
部分,直到VC ++要求编译警告或错误,以下内容可以通过明确提供const char *
重载来解决问题。使用VC ++ 2013和2015再次确认。
#include <string.h>
#include <stdio.h>
#pragma intrinsic(strcpy)
static void swap(char *s)
{
strcpy(s, "nope!");
printf("OK: %s\n", s);
};
static void swap(const char *s)
{
printf("No: %s?\n", s);
};
void main()
{
char z[] = "this should segfault";
swap(z); // prints 'OK: nope!'
swap("this should segfault"); // prints 'No: this should segfault?'
}