“纯虚函数被称为”在海湾合作委员会4.4,但不是在较新的版本或铿锵3.4 [英] "pure virtual function called" on gcc 4.4 but not on newer version or clang 3.4

查看:160
本文介绍了“纯虚函数被称为”在海湾合作委员会4.4,但不是在较新的版本或铿锵3.4的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个MCVE,在我的一些机器上,当用g ++版本4.4.7编译时崩溃,但可以与clang ++版本3.4.2和g ++版本6.3一起工作。



我想知道它是来自未定义的行为还是来自这个古老版本的gcc的实际错误。



代码



  #include< cstdlib> 
$ b class BaseType
{
public:
BaseType():_present(false){}
virtual〜BaseType(){}

virtual void clear(){}

virtual void setString(const char * value,const char * fieldName)
{
_present =(* value!=' \0' );
}

保护:
virtual void setStrNoCheck(const char * value)= 0;

保护:
bool _present;
};

// ---------------------------------------- ------------------------------------------

class TypeTextFix:public BaseType
{
public:
virtual void clear(){}
$ b $ virtual void setString(const char * value,const char * fieldName)
{
clear();
BaseType :: setString(value,fieldName);
if(_present == false){
return; //评论此返回修复崩溃。是的,它确实!
}
setStrNoCheck(value);
}

保护:
虚拟无效setStrNoCheck(常量字符*值){}
};

// ---------------------------------------- ------------------------------------------

struct Wrapper
{
TypeTextFix _text;
};

int main()
{
{
Wrapper wrapped;
wrapped._text.setString(123456789012,NULL);
}
//如果我在这里添加一个写入标准输出,它不会崩溃oO
{
包装器包装;
wrapped._text.setString(123456789012,NULL); //没有这行(或任何一个),程序运行得很好!
}
}



编译&运行



  g ++ -O1 -Wall -Werror thebug.cpp&& ./a.out 
被称为
的纯虚方法在没有活动异常的情况下终止调用
中止(核心转储)

这实际上是最小的,如果删除了这段代码的任何特性,它就会正常运行。

分析



使用 -O0 BUT 进行编译时,代码段工作正常,对于 -O1 的每个标记,定义在 code> -O0 + flag .org / onlinedocs / gcc-4.4.7 / gcc / Optimize-Options.htmlrel =noreferrer> GnuCC文档

核心转储从中可以提取回溯:

 (gdb)bt 
#0 0x0000003f93e32625 in raise()from /lib64/libc.so.6
#1 0x0000003f93e33e05 in /从/lib64/libc.so.6
#2中取消()0x0000003f98ebea7d在__gnu_cxx :: __ verbose_terminate_handler()()from / usr / lib64 / libstdc ++。so.6
#3 0x0000003f98ebcbd6在? ()from /usr/lib64/libstdc++.so.6
#4 0x0000003f98ebcc03 in std :: terminate()()from /usr/lib64/libstdc++.so.6
#5 0x0000003f98ebd55f in __cxa_pure_virtual( )from /usr/lib64/libstdc++.so.6
#6 0x00000000004007b6 in main()



< hr>

请随时在评论中要求测试或详细信息。
问:


  • 是实际的代码吗?是!它是!字节的字节。

  • 您使用的GnuCC的确切版本是什么?



    <$ p $ $ g ++ --version
    g ++(GCC)4.4.7 20120313(Red Hat 4.4.7-16)
    自由软件基金会版权所有(C)2010 b $ b这是免费软件;请参阅复制条件的来源。没有任何b $ b保修;甚至不适用于适销性或针对特定用途的适用性。


  • 我们可以看到生成的程序集吗?是的,此处位于pastebin.com



解决方案

这是FSF GCC中没有的特定于红帽的错误。在你的代码中这不是问题。



在一个同时具有CentOS 6的GCC和FSF GCC 4.4.7的系统上,它们都生成汇编列表并查看差异在两者之间,有一点跳出来:

CentOS 6的GCC产生

  movq $ _ZTV8BaseType + 16,(%rsp)



p>

  movq $ _ZTV11TypeTextFix + 16,(%rsp)



换句话说,Red Hat的一个GCC补丁使它无法正确设置vtable。这是你的 main 函数的一部分,你可以在 .L48:之后不久在自己的程序集列表中看到它。



红帽在其GCC版本中应用了许多补丁,其中一些是影响代码生成的补丁。不幸的是,其中一个似乎有意想不到的副作用。

I've got an MCVE which, on some of my machines crashes when compiled with g++ version 4.4.7 but does work with clang++ version 3.4.2 and g++ version 6.3.

I'd like some help to know if it comes from undefined behavior or from an actual bug of this ancient version of gcc.

Code

#include <cstdlib>

class BaseType
{
public:
    BaseType() : _present( false ) {}
    virtual ~BaseType() {}

    virtual void clear() {}

    virtual void setString(const char* value, const char* fieldName)
    {
        _present = (*value != '\0');
    }

protected:
    virtual void setStrNoCheck(const char* value) = 0;

protected:
    bool _present;
};

// ----------------------------------------------------------------------------------

class TypeTextFix : public BaseType
{
public:
    virtual void clear() {}

    virtual void setString(const char* value, const char* fieldName)
    {
        clear();
        BaseType::setString(value, fieldName);
        if( _present == false ) {
            return; // commenting this return fix the crash. Yes it does!
        }
        setStrNoCheck(value);
    }

protected:
    virtual void setStrNoCheck(const char* value) {}
};

// ----------------------------------------------------------------------------------

struct Wrapper
{
    TypeTextFix _text;
};

int main()
{
    {
        Wrapper wrapped;
        wrapped._text.setString("123456789012", NULL);
    }
    // if I add a write to stdout here, it does not crash oO
    {
        Wrapper wrapped;
        wrapped._text.setString("123456789012", NULL); // without this line (or any one), the program runs just fine!
    }
}

Compile & run

g++ -O1 -Wall -Werror thebug.cpp && ./a.out
pure virtual method called
terminate called without an active exception
Aborted (core dumped)

This is actually minimal, if one removes any feature of this code, it runs correctly.

Analyse

The code snippet works fine when compiled with -O0, BUT it still works fine when compiled with -O0 +flag for every flag of -O1 as defined on GnuCC documentation.

A core dump is generated from which one can extract the backtrace:

(gdb) bt
#0  0x0000003f93e32625 in raise () from /lib64/libc.so.6
#1  0x0000003f93e33e05 in abort () from /lib64/libc.so.6
#2  0x0000003f98ebea7d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib64/libstdc++.so.6
#3  0x0000003f98ebcbd6 in ?? () from /usr/lib64/libstdc++.so.6
#4  0x0000003f98ebcc03 in std::terminate() () from /usr/lib64/libstdc++.so.6
#5  0x0000003f98ebd55f in __cxa_pure_virtual () from /usr/lib64/libstdc++.so.6
#6  0x00000000004007b6 in main ()


Feel free to ask for tests or details in the comments. Asked:

  • Is it the actual code? Yes! it is! byte for byte. I've checked and rechecked.

  • What exact version of GnuCC du you use?

    $ g++ --version
    g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
    Copyright (C) 2010 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    

  • Can we see the generated assembly? Yes, here it is on pastebin.com

解决方案

This is a Red Hat-specific bug not present in FSF GCC. It is not a problem in your code.

On a system with both CentOS 6's GCC, and FSF GCC 4.4.7, having both generate an assembly listing and viewing the differences between the two, one bit jumps out:

CentOS 6's GCC generates

movq $_ZTV8BaseType+16, (%rsp)

whereas FSF GCC 4.4.7 generates

movq $_ZTV11TypeTextFix+16, (%rsp)

In other words, one of Red Hat's GCC patches makes it set up the vtable incorrectly. This is part of your main function, you can see it in your own assembly listing shortly after .L48:.

Red Hat applies many patches to its version of GCC, and some of them are patches that affect code generation. Unfortunately, one of them appears to have an unintended side effect.

这篇关于“纯虚函数被称为”在海湾合作委员会4.4,但不是在较新的版本或铿锵3.4的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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