【问题标题】:"address not from malloc()" error using electric fence使用电子围栏的“地址不是来自 malloc()”的错误
【发布时间】:2010-07-25 19:12:39
【问题描述】:

我一直在编写一个测试用例程序来演示我的一个更大程序的问题, 并且测试用例存在原程序没有的bug。

这是头文件:

// compiled with g++ -I/usr/local/bin/boost_1_43_0 -Wall -std=c++0x -g test.cpp

#include <bitset>
#include <boost/shared_ptr.hpp>
#include <vector>

typedef std::vector< std::vector< std::bitset<11> > > FlagsVector;

namespace yarl
{
    namespace path
    {
        class Pathfinder;
    }

    namespace level
    {
        class LevelMap
        {
        // Member Variables
            private:
                int width, height;
                FlagsVector flags;

            public:
                boost::shared_ptr<path::Pathfinder> pathfinder;

        // Member Functions
            LevelMap(const int, const int);

            int getWidth() const {return width;}
            int getHeight() const {return height;}

            bool getFifthBit(const int x, const int y) const
            {
                return flags.at(x).at(y).test(5);
            }
        };



        class Level
        {
        // Member Variables
            public:
                LevelMap map;

        // Member Functions
            public:
                Level(const int w=50, const int h=50);
        };
    }


    namespace path
    {
        class Pathfinder
        {
        // Member Variables
            private:
                boost::shared_ptr<level::LevelMap> clientMap;

        // Member Functions
            public:
                Pathfinder() {}
                Pathfinder(level::LevelMap* cm)
                : clientMap(cm) {}

                void test() const;
        };
    }
}

这是实现文件:

#include <iostream>
#include "test.hpp"
using namespace std;

namespace yarl
{
    namespace level
    {
        LevelMap::LevelMap(const int w, const int h)
        : width(w), height(h), flags(w, vector< bitset<11> >(h, bitset<11>())),
          pathfinder(new path::Pathfinder(this)) 
        {}



        Level::Level(const int w, const int h)
        : map(w,h)
        {
            map.pathfinder->test();
        }
    }



    namespace path
    {
        void Pathfinder::test() const
        {
            int width = clientMap->getWidth();
            int height = clientMap->getHeight();
            cerr << endl;
            cerr << "clientMap->width: " << width << endl; 
            cerr << "clientMap->height: " << height << endl; 
            cerr << endl;
            for(int x=0; x<width; ++x)
            {
                for(int y=0; y<height; ++y)
                {
                    cerr << clientMap->getFifthBit(x,y);
                }
                cerr << "***" << endl; // marker for the end of a line in the output
            }
        }
    }
}

int main()
{
    yarl::level::Level l;
    l.map.pathfinder->test();
}

我将此程序与电子围栏链接,当我运行它时,它会因以下错误而中止:

ElectricFence Aborting: free(bffff434): address not from malloc().

Program received signal SIGILL, Illegal instruction.
0x0012d422 in __kernel_vsyscall ()

gdb 的回溯显示非法指令位于编译器生成的 Pathfinder 析构函数中,该析构函数在析构其 shared_ptr 时遇到问题。有人知道这是为什么吗?

【问题讨论】:

    标签: c++ shared-ptr electric-fence


    【解决方案1】:
    yarl::level::Level l;
    

    您实例化一个自动的Level 变量,它在其构造函数中构造其成员pathfinder,如下所示:

    pathfinder(new path::Pathfinder(this))
    

    然后在Pathfinder 构造函数中,它采用您传入的Level 指针并将其分配给shared_ptr。然后shared_ptr 获得此指针的所有权。

    这是不正确的,有几个原因:

    1. shared_ptr 应该用于管理动态分配的对象,而不是自动分配的对象
    2. 如果你想使用shared_ptr,那么你应该在任何地方使用它:就像现在一样,你传递原始指针(例如,传递给Pathfinder的构造函数,然后将它们存储为shared_ptrs。这只是打开一大堆所有权蠕虫。
    3. this 分配给shared_ptr 的正确方法是从enable_shared_from_this 派生;但请注意,您无法在构造函数中从 this 获取 shared_ptr

    shared_ptr被销毁时,它会尝试删除它管理的指针。然而,在这种情况下,该指针不是指向动态分配的对象(即,使用new 分配的),而是指向自动分配的对象(即,在堆栈上)。因此,错误。

    如果您不需要某些东西来获得资源的所有权,那么使用原始指针(或引用,如果您有该选项)没有任何问题。

    【讨论】:

    • 将 LevelMap 的路径查找器从 shared_ptr 更改为原始指针解决了问题,感谢您的帮助。作为第二个问题,我在我的原始程序中经常使用 shared_ptr,实际上这个例子中的原始指针是我唯一使用的 non-shared_ptr。您是否建议将所有其他 shared_ptr 更改为引用或原始指针?
    • @Max:您应该使用shared_ptrweak_ptr 来管理动态分配的 对象。只是不要使用它们来管理自动分配的对象。
    【解决方案2】:

    您正在从不应由 shared_ptr 管理的指针构造shared_ptr。 (this 指针)

    当最后一个 shared_ptr 的副本被销毁时,该内存被释放 - 实际上它不应该 - 在这种情况下,this 位于堆栈上。

    shared_ptr 的构造函数是显式的,这是有原因的 - 正是为了避免从不由 shared_ptr 管理的常规指针到 shared_ptr 的这种被忽视的转换 - 一旦你将这样的指针传递给 shared_ptr ,你的程序注定要失败——唯一的出路是删除你不打算删除的指针。

    通常建议直接使用 new 构造共享指针 - 例如 ptr(new Somethings(x,y,z) - 这样您就不会冒异常泄漏已分配但未分配给 shared_ptr 内存的风险。

    【讨论】:

      【解决方案3】:

      Level 包含一个 LevelMap 成员变量。当Level 被销毁时,它也会销毁它的LevelMap

      另一方面,指向此LevelMap 成员的指针被传递给Pathfinder,它从传递的指针创建一个shared_ptr&lt;&gt;。这个新创建的shared_ptr&lt;&gt; 认为它拥有它指向的对象,并会在Pathfinder 被销毁后尝试销毁它。

      所以LevelMap被破坏了好几次。

      在示例中,LevelMap 是在堆栈上创建的。因此,shared_ptr&lt;&gt; 调用的delete 可以看到地址不是来自堆,并且您会收到错误。如果你的真实程序也有这个问题,但所有这些对象都是动态分配的,那么可能不会检测到错误。稍后您只会遇到无声的内存损坏和奇怪的崩溃。

      【讨论】:

      • +1。最初的问题是我遇到了内存损坏和类似的事情,所以这可能会帮助我解决这个问题。谢谢。
      猜你喜欢
      • 1970-01-01
      • 2013-11-30
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-09
      相关资源
      最近更新 更多