C++ 正在查找堆栈损坏错误的解释

C++ 正在查找堆栈损坏错误的解释,c++,c++11,optimization,visual-studio-2017,stack-corruption,C++,C++11,Optimization,Visual Studio 2017,Stack Corruption,下面的问题是从一个巨大的项目中提炼出来的,也是我能想到的问题中最简单的例子 我知道,从std::string派生是不好的,它在我们的代码库中已经发生了更改,但我试图理解在这里发生了什么 >代码在Visual C++ 2017 上崩溃 Microsoft Visual Studio Community 2017 Version 15.2 (26430.14) Release Visual C++ 2017 00369-60000-00001-AA257 仅在释放模式下(速度优化)。在没有

下面的问题是从一个巨大的项目中提炼出来的,也是我能想到的问题中最简单的例子

我知道,从
std::string
派生是不好的,它在我们的代码库中已经发生了更改,但我试图理解在这里发生了什么

<> >代码在Visual C++ 2017

上崩溃
Microsoft Visual Studio Community 2017 
Version 15.2 (26430.14) Release
Visual C++ 2017   00369-60000-00001-AA257
仅在释放模式下(速度优化)。在没有速度优化的情况下,它不会在释放模式下崩溃

#include <string>
#include <string_view>
#include <vector>

struct my_string : public std::string
{
    __declspec(noinline)
        my_string::my_string( const std::string_view& str ) :
        std::string( str.data(), str.size() )
    {}

    template <typename T>
    my_string& arg( T )
    {
        return *this;
    }
};

struct my_string_view : public std::string_view
{
    my_string_view( const std::string_view::value_type* val ) :
        std::string_view( val ) {}

    template <typename... PARAMS>
    my_string arg( PARAMS&&... prms ) {
        return my_string( *this ).arg( std::forward<PARAMS>( prms )... );
    }
};

template <typename T>
struct basic_color
{
    T r, g, b, a;

    basic_color() : r( 0 ), g( 0 ), b( 0 ), a( 255 ) {}

    template <typename U>
    explicit basic_color( const basic_color<U>& c ) :
        r( c.r ), g( c.g ), b( c.b ), a( c.a )
    {}
};

using color = basic_color<std::uint8_t>;
using float_color = basic_color<float>;

__declspec(noinline)
void change_float_color( float_color& color )
{
    color.r = 0.1f;
}

int main()
{
    std::vector<float_color> colors = { {} };
    float sum = 0;
    for ( std::uint32_t i = 0; i < 1; ++i )
    {
        float_color fc;
        change_float_color( fc );
        color c( fc );
        std::vector<std::string> msgs;
        msgs.push_back( my_string_view( "" ).arg( c.r ) );
        msgs.push_back( my_string_view( "" ).arg( c.g ) );
        sum += fc.b - colors[i].b;
    }
    return static_cast<int>(sqrt( sum ));
}
#包括
#包括
#包括
struct my_string:public std::string
{
__declspec(noinline)
我的字符串::我的字符串(常量std::字符串视图和str):
字符串(str.data(),str.size())
{}
模板
my_字符串和参数(T)
{
归还*这个;
}
};
结构我的字符串视图:公共标准::字符串视图
{
我的字符串视图(const std::string\u view::value\u type*val):
std::string_视图(val){}
模板
我的字符串参数(参数和…prms){
返回my_字符串(*this).arg(std::forward(prms)…);
}
};
模板
结构基本颜色
{
tr,g,b,a;
基本颜色():r(0),g(0),b(0),a(255){
模板
显式基本颜色(常量基本颜色和c):
r(c.r)、g(c.g)、b(c.b)、a(c.a)
{}
};
使用颜色=基本颜色;
使用浮动颜色=基本颜色;
__declspec(noinline)
无效更改\u浮动\u颜色(浮动\u颜色和颜色)
{
颜色r=0.1f;
}
int main()
{
std::vector colors={{};
浮点数和=0;
对于(标准::uint32_t i=0;i<1;++i)
{
浮色fc;
更改浮动颜色(fc);
颜色c(fc);
std::载体msgs;
msgs.push_back(我的字符串视图(“”.arg(c.r));
msgs.push_back(我的字符串视图(“”.arg(c.g));
sum+=fc.b-颜色[i].b;
}
返回静态_cast(sqrt(sum));
}
Visual Studio中的错误是这样的(请查看底部的
msgs
colors
的断开大小):

我的猜测是,用
myu字符串调用
std::vector::push_back(std::string&)
是有问题的(类似于切片的行为)。但这怎么会损坏堆栈(或堆栈指针)

有人知道这里会发生什么事吗?或者我怎么知道


是我的项目,以防有人对重现问题感兴趣。

我认为这是一个编译器错误

下面是我从反汇编中看到的:在
main()
条目中,
esp
被保存到
ebx
中。最后,
esp
ebx
还原。但是,在中间(调用<代码> STD::yDebug SangeE1)<代码> EBX值被其他东西覆盖。因此,在最后,
ret
指令使用了一个虚假的
esp
值,并跳转到一个无效的位置


因此,实际上,堆栈没有损坏(按照Hans的建议,无法用数据断点捕获此错误),但堆栈指针是损坏的。

使用调试器,数据断点是这里的首选武器。“由于std::string没有虚拟析构函数,因此为push_back指定的r值被切片。”切片与虚拟析构函数无关。不管怎样,这些值都将被切片。“因此派生类(my_字符串)的析构函数永远不会被调用,堆栈上仍有一些垃圾”这毫无意义
sizeof(my_string)==sizeof(std::string)
。“看看这些破尺寸”编译器可以随意处理这些对象,因为它们再也不会被使用了。如果确实是这样,那么你在VC++中发现了一个非常愚蠢的错误。我觉得很难相信,因为在预处理之后,没有更多的头文件或源文件,编译器甚至不应该能够分辨出来。@n.m.在预处理之后,源文件仍然是不同的编译单元,只能由链接器合并。但是现在我可以在一个源文件中通过禁止内联来复制更多的函数。我相应地编辑了我的问题。所以这取决于你到底允许内联什么。在我看来像是一个编译器错误。我在这里找不到任何UB的痕迹。谢谢你重现这个问题。我希望是MSDN上发布问题的正确位置。无论如何,我会在下一次编译器更新的官方版本中检查问题是否消失。@Tobias:建议使用网站报告错误。我同意你的评论:这个bug是脆弱的,只有当VS开发人员说“是的,我已经分析了问题,并修复了它”时,我们才能确定它是修复的。再次感谢。