ms vc ++编译器优化掉错误的代码 [英] ms vc++ compiler optimizating away erroneous code
问题描述
我知道它与编译器优化有关,但我正在寻找一个真正的深入了解如何/为什么,如何确保我在实际代码中通知这种行为。
我有这个代码
void swap(char * s)
{
strcpy s,nope!);
printf(Result:%s\\\
,s);
};
void main(){
...
swap(this should segfault);
...
}
显然,它应该segfault,在释放模式下减少到只是内联printf。
这似乎是一种可以真正咬我屁股的东西,所以我会喜欢它,如果你能为我照亮这一点。 p>
为了完整起见,这里是预期的程序集
this should segfault
call j_?swap @@ YAXPAD @ Z; swap(char *)
这里是生成的程序集
push offset s; 这应该segfault
push offset格式; 结果:%s\\\
调用ds:__ imp__printf
编译器选项
/ GS / GL / analyze- / W3 / Gy / Zc:wchar_t / Zi / / O2 /Fd\"Release\vc120.pdb/ fp:precise / DWIN32/ DNDEBUG/ D_CONSOLE/ D_LIB/ D_UNICODE/ DUNICODE/ errorReport:prompt / WX- / Zc:forScope / Gd / Oy- / Oi / MD / FaRelease\/ EHsc / nologo / FoRelease\/Fp\"Release\scratchpad2.pch
VC ++ 2013和2015确认的行为。@ IgorTandetnik的意见是正确的。代码显示UB(未定义的行为),并且不是崩溃是一种可能的行为。
也就是说,VC ++也是发出(至少)一个警告,当允许字符串到非const字符指针转换,已被弃用自(我认为)C ++ 0x - 见为什么只有在某种情况下字符串文字才能隐式转换为char * ?和为什么将字符串文字传递给char *参数只是有时会出现编译错误?您可以考虑在 https://connect.microsoft.com/visualstudio 上提交错误报告。
我知道它与编译器优化有关,但我正在寻找一个真正的深入了解如何/为什么,如何确保通知
我对问题的后半部分没有答案。
关于如何/为什么,当优化为 intrinsic c时,它似乎是
strcpy
/ code>与只读目标。一个相当奇怪的行为,确实,因为它最终导致整个 strcpy
被默默跳过。
-
在
swap
之前添加#pragma函数(strcpy)
会导致它总是崩溃。 / p> -
将呼叫代码更改为
char z [] =this should segfault;
回到
如何确保我在实际代码
部分中通知这种行为,直到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\\\
,s);
};
static void swap(const char * s)
{
printf(No:%s?\\\
,s);
};
void main()
{
char z [] =this should segfault;
swap(z); // prints'OK:nope!'
swap(this should segfault); // prints'No:this should segfault?'
}
I know its to do with compiler optimization, but I am looking for a real deep dive into how/why and how to ensure i am notified of this behaviour in real code.
I have this code
void swap(char *s)
{
strcpy(s, "nope!");
printf("Result: %s\n", s);
};
void main(){
...
swap("this should segfault");
...
}
obviously, it should segfault, but visual studio in release mode reduces it down to just inlining the printf.
This seems like the kind of thing that could really bite me in the ass later, so i would love it if you could shine some light on this for me.
for completeness sake here is the expected assembly
push offset s ; "this should segfault"
call j_?swap@@YAXPAD@Z ; swap(char *)
and here is the generated assembly
push offset s ; "this should segfault"
push offset Format ; "Result: %s\n"
call ds:__imp__printf
and here are the compiler options as requested in comments
/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"
Behavior confirmed here with VC++ 2013 and 2015. @IgorTandetnik's comment is correct. The code exhibits UB (undefined behavior), and not crashing is one such possible behavior.
That said, VC++ is also at fault for not issuing (at least) a warning when allowing the string-literal-to-non-const-char-pointer conversion which has been deprecated since (I think) C++0x - see Why can a string literal be implicitly converted to char* only in certain case? and Why is passing a string literal into a char* argument only sometimes a compiler error?. You may consider filing a bug report at https://connect.microsoft.com/visualstudio about that.
I know its to do with compiler optimization, but I am looking for a real deep dive into how/why and how to ensure i am notified of this behaviour in real code.
I don't have an answer to the latter part of the question.
As to how/why, it appears to be a matter of strcpy
behavior when optimized as an intrinsic
with a read-only destination. A rather odd behavior, indeed, since it ultimately results in the entire strcpy
being silently skipped.
Adding
#pragma function(strcpy)
beforeswap
will cause it to always crash.Changing the calling code to
char z[] = "this should segfault"; swap(z);
will remove the UB factor and make it always work.
[EDIT] Going back to the
how to ensure i am notified of this behaviour in real code
part, and until VC++ obliges with a compilation warning or error, the following could work around it by explicitly providing a const char *
overload. Confirmed again with both VC++ 2013 and 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?'
}
这篇关于ms vc ++编译器优化掉错误的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!