首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >向全局操作员添加std::cout新的掩码SIGSEGV

向全局操作员添加std::cout新的掩码SIGSEGV
EN

Stack Overflow用户
提问于 2016-09-06 04:48:44
回答 3查看 221关注 0票数 1

这个问题是我学习覆盖全球运营商新知识的一部分。我需要向社区寻求帮助,帮助理解运行时行为,因为我无法理解这一点。

这段代码故意产生内存泄漏和SIGSEGV

代码

main.cpp

代码语言:javascript
运行
复制
#include <iostream>
#include <functional>
#include <new>
#include <set>
#include <string>
#include <memory>

namespace ns
{

class Foo
{
    public:
        Foo()
        {
            std::cout << __PRETTY_FUNCTION__ << std::endl;
        }

        virtual ~Foo()
        {
            if (!mSet.empty()) { std::cout << "You have unfreed heap allocations!" << std::endl; }
            else { std::cout << "Good job! No unfreed heap allocations!" << std::endl; }
        }

        void Add(void* p) { mSet.insert(p); }

        void Delete(void* p) { mSet.erase(p); }

    protected:
        std::set< void*, std::less<void*> > mSet;
};

Foo gFoo;

}

void* operator new(size_t size)
{
//    std::cout << "In overridden operator new!" << std::endl;
    void* p = malloc(size);
    ns::gFoo.Add(p);
    return p;
}


int main(int argc, char* argv[])
{
    int* p1 = new int(5);
    int* p2 = new int(6);

    return 0;
}

编译与错误

注意:环境是Cywin,因此下面是a.exe而不是a.out

代码语言:javascript
运行
复制
>g++ --version
g++ (GCC) 5.4.0
Copyright (C) 2015 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.
>g++ -std=c++14 -g main.cpp
>
>./a.exe
ns::Foo::Foo()
Segmentation fault (core dumped)
>

预期会出现此错误:请注意,重写的operator new最终调用std::set::insert(.),它本身使用了导致无限递归的new

‘Fix’

取消对std::cout行在operator new(size_t)中的注释。

使用此更改编译和运行将产生一个cout流,如预期的那样,但是没有“分段错误(核心转储)”消息,也没有.stackdump文件。

这对我来说毫无意义。

我不认为引入std::cout可以解决这个问题,但我也无法解释为什么它似乎掩盖了问题。

急切地想了解这里发生了什么。谢谢你的洞察力。

(重申一下,内存泄漏和无限递归是为了这个问题而故意的。这个问题偶然出现在我正在处理的更合适的代码中,代码只是一个MCV示例来演示这个问题。)

更新

在真正的Linux上,程序SIGSEGVs包含两个版本的代码,即有和没有std::cout。这至少帮助我恢复了一些理智,因为这符合预期。

更新

我将停止积极研究这个话题,因为它首先是我在做其他事情时偶然发现的,也是因为代码在一个真正的Linux盒上的行为和预期一样--即带有和不带std::cout的SIGSEGV。不过,如果有人最终能给出一个明确的答案,我会把这个问题留到一边。这个问题完全表现出来,这还有点令人担忧,因为它意味着Cygwin“掩盖”了在某些情况下错误的可靠表示。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-09-06 09:37:41

有一个合理的猜测,为什么std::cout会影响观察到的结果:它是迄今为止最复杂的调用。如果可能与printf同步,替换streambufs等,则可以阻止内联。

当然,内联对于递归函数来说是个问题,因为它会导致简单编译器中的堆栈溢出。但是,一个体面的编译器可以将递归函数转换为迭代函数,这可能会影响堆栈溢出的可见症状。显然,您的示例仍然会耗尽内存,但现在可能是堆内存而不是堆栈内存。

票数 2
EN

Stack Overflow用户

发布于 2016-09-06 06:15:49

代码无论如何都应该在std::cout行中获得段故障,因为它应该得到std::set::insert()operator new()的递归调用,并最终得到堆栈溢出。

  1. 您的operator new调用ns::gFoo.Add(p)
  2. Foo::Add()调用std::set::insert()
  3. insert()将分配新内存并调用operator new()
  4. 现在它得到了递归。

但是,您表示删除std::cout可以解决问题。

因此,我猜想在您的环境中,std::std::insert()不会为小对象或小大小动态分配内存,因此它不会调用operator new(),从而避免递归。

std::cout << "In overridden operator new!"将分配内存,因此它调用operator new()并获得递归。

无论如何,您可以使用gdb调试段故障,查看调用堆栈,并找到递归作为根本原因。

票数 3
EN

Stack Overflow用户

发布于 2016-09-06 08:27:34

我有赛根。我创建了一个最小化的测试并确认了OP的结果。

代码语言:javascript
运行
复制
#include <iostream>
#include <new>
#include <set>
#include <memory>
#include <cstdlib>
#include <cstdio>

std::set< void*, std::less<void*> > mSet;
unsigned long long counter=0;

void* operator new(size_t size)
{
    counter++;
    printf("counter: %d\n",counter);
    void* p = malloc(size);
    mSet.insert(p);
    return p;
}

int main(int argc, char* argv[])
{
    int* p1 = new int(5);
    std::cerr << "Exiting=" << counter << std::endl;
}

在printf注释掉之后,它在几秒钟内给出了SIGSEGV,如下所示:

代码语言:javascript
运行
复制
~> ./a.exe
zsh: segmentation fault (core dumped)  ./a.exe

在printf存在的情况下,计数器上升到4811,没有得到SIGSEGV,但没有到达main的末尾就安静地退出,如下所示。当我使用-O3优化它时,也会发生同样的事情(但现在的计数器值是64936)。在-O0的帮助下,柜台达到4811。

代码语言:javascript
运行
复制
zsh-user> ./a.exe
....

在printf存在和输出重定向的情况下,给出了SIGSEGV如下所示。优化级别没有改变此测试的行为。

代码语言:javascript
运行
复制
~> ./a.exe > out
zsh: segmentation fault (core dumped)  ./a.exe > out

我没有任何解释(我计划下一次调试它)。我有a simillar strange problem,两年前(在其他平台上没有其他人能够复制它;只有另一个cygwin用户能够复制它;这个问题随着cygwin的完全重新安装而消失了)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39340841

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档