ms vc++ compiler optimizating away erroneous code

烈酒焚心 提交于 2019-12-25 19:35:16

问题


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" 

回答1:


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?'
}


来源:https://stackoverflow.com/questions/38111158/ms-vc-compiler-optimizating-away-erroneous-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!