ms vc ++编译器优化掉错误的代码 [英] ms vc++ compiler optimizating away erroneous code

查看:242
本文介绍了ms vc ++编译器优化掉错误的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道它与编译器优化有关,但我正在寻找一个真正的深入了解如何/为什么,如何确保我在实际代码中通知这种行为。



我有这个代码

  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) before swap 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆