ms vc ++编译器优化了错误的代码

时间:2016-06-29 22:35:56

标签: visual-c++ compilation

我知道它与编译器优化有关,但我正在深入研究如何/为什么以及如何确保我在实际代码中收到此行为的通知。

我有这段代码

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" 

1 个答案:

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