将POD推送到队列

时间:2017-05-03 20:17:25

标签: c++ c++11 segmentation-fault queue valgrind

我遇到了一些非常奇怪的问题,我写过一些代码;推送结构时,std::deque::emplace_back中发生了分段错误:

struct ChunkMeshTask {
    union {
        ChunkID                       id;  //< ui64
        ChunkRectilinearWorldPosition pos; //< i24, i16, i24
    };
    Chunk*  chunk;
};

到存储为与执行推送的方法相同的类的成员的队列:

namespace h {
    using Sender = const void*;
}

namespace hvox {
    class ChunkGrid {
        ...
    public:
        void handleBlockChange(Sender sender, BlockChangeEvent event);
        ...
    protected:
        std::queue<ChunkMeshTask> m_meshTasks; // = std::queue<ChunkMeshTask>(); was tried as a sanity check.
        ...
    };
}

void hvox::ChunkGrid::handleBlockChange(h::Sender sender, BlockChangeEvent event) {
    // TODO(Matthew): We really shouldn't be submitting a mesh task for each block change...
    //                We want AT MOST one mesh task per chunk on the queue at any given time regardless of number of blocks changed.
    m_meshTasks.push(ChunkMeshTask{
        { event.chunkPos },
        (Chunk*)sender
    });
}

在MSVC中不会发生此分段错误,但在GCC和Clang中,使用GDB进行调试表明所有值(包括指针sender)在调用hvox::ChunkGrid::handleBlockChange时都有效。 / p> 从事件系统调用

hvox::ChunkGrid::handleBlockChange,在这种特殊情况下,调用包装函数的委托。我提到这是为了试图深入挖掘我通过valgrind运行我的程序。除了修复各种不相关的错误之外,它还产生了两个看似相关的错误,但是我无法理解我面临的问题:

==7788== Use of uninitialised value of size 8
==7788==    at 0x4249F9: void std::deque<hemlock::voxel::ChunkMeshTask, std::allocator<hemlock::voxel::ChunkMeshTask> >::emplace_back<hemlock::voxel::ChunkMeshTask>(hemlock::voxel::ChunkMeshTask&&) (deque.tcc:158)
==7788==    by 0x423FB5: std::deque<hemlock::voxel::ChunkMeshTask, std::allocator<hemlock::voxel::ChunkMeshTask> >::push_back(hemlock::voxel::ChunkMeshTask&&) (stl_deque.h:1533)
==7788==    by 0x4236DD: std::queue<hemlock::voxel::ChunkMeshTask, std::deque<hemlock::voxel::ChunkMeshTask, std::allocator<hemlock::voxel::ChunkMeshTask> > >::push(hemlock::voxel::ChunkMeshTask&&) (stl_queue.h:248)
==7788==    by 0x422BB2: hemlock::voxel::ChunkGrid::handleBlockChange(void const*, hemlock::voxel::BlockChangeEvent) (ChunkGrid.cpp:52)
==7788==    by 0x424E3C: void hemlock::Delegate<void, void const*, hemlock::voxel::BlockChangeEvent>::executeWithObject<hemlock::voxel::ChunkGrid, void>(void const*, void (hemlock::TypelessMember::*)(), void const*, hemlock::voxel::BlockChangeEvent) (Delegate.hpp:167)
==7788==    by 0x425C09: hemlock::Delegate<void, void const*, hemlock::voxel::BlockChangeEvent>::operator()(void const*, hemlock::voxel::BlockChangeEvent) const (Delegate.hpp:112)
==7788==    by 0x424F02: void hemlock::executeDelegate<void, hemlock::voxel::BlockChangeEvent>(stx::basic_any<5ul>, void const*, hemlock::voxel::BlockChangeEvent) (Event.hpp:303)
==7788==    by 0x4222C4: hemlock::Event<hemlock::voxel::BlockChangeEvent>::trigger(hemlock::voxel::BlockChangeEvent) (Event.hpp:130)
==7788==    by 0x42218D: hemlock::Event<hemlock::voxel::BlockChangeEvent>::operator()(hemlock::voxel::BlockChangeEvent) (Event.hpp:135)
==7788==    by 0x422020: hemlock::voxel::Chunk::setBlock(hemlock::voxel::BlockChunkPosition, hemlock::voxel::Block) (Chunk.cpp:25)
==7788==    by 0x40B138: ChunkGenerator::runGenTask(hemlock::voxel::ChunkGenTask, unsigned short) (ChunkGenerator.cpp:51)
==7788==    by 0x422A49: hemlock::voxel::ChunkGrid::update() (ChunkGrid.cpp:35)
==7788==  Uninitialised value was created by a stack allocation
==7788==    at 0x424EB8: void hemlock::executeDelegate<void, hemlock::voxel::BlockChangeEvent>(stx::basic_any<5ul>, void const*, hemlock::voxel::BlockChangeEvent) (Event.hpp:299)

这个错误意味着hemlock::executeDelegate<void, hemlock::voxel::BlockChangeEvent>中有一些未初始化的内容,但是再次使用GDB我已经验证了delegate(存储在5字节宽std::any中),指针{{1 sender中的结构在这里都是有效的。该函数如下所示:

parameters

再次使用GDB,代理中的所有内容都是有效的,并且使用预期的参数调用包装函数。

在seg故障之前的最后一个错误valgrind产生:

template<typename ReturnType, typename ...Parameters>
ReturnType executeDelegate(DelegateAny callback, Sender sender, Parameters... parameters) {
    using MyDelegate = Delegate<ReturnType, Sender, Parameters...>;
    MyDelegate delegate = delegateAnyCast<MyDelegate>(callback); // delegateAnyCast is just a wrapper of std::any_cast specifically for an internal 5-byte wide stack storage in std::any.

    return delegate(sender, parameters...);
}

在这种情况下我根本无法解析,它与无效指针有关,但除了==7788== Invalid write of size 8 ==7788== at 0x4260C5: void __gnu_cxx::new_allocator<hemlock::voxel::ChunkMeshTask>::construct<hemlock::voxel::ChunkMeshTask, hemlock::voxel::ChunkMeshTask>(hemlock::voxel::ChunkMeshTask*, hemlock::voxel::ChunkMeshTask&&) (new_allocator.h:120) ==7788== by 0x4257EC: void std::allocator_traits<std::allocator<hemlock::voxel::ChunkMeshTask> >::construct<hemlock::voxel::ChunkMeshTask, hemlock::voxel::ChunkMeshTask>(std::allocator<hemlock::voxel::ChunkMeshTask>&, hemlock::voxel::ChunkMeshTask*, hemlock::voxel::ChunkMeshTask&&) (alloc_traits.h:475) ==7788== by 0x4249E8: void std::deque<hemlock::voxel::ChunkMeshTask, std::allocator<hemlock::voxel::ChunkMeshTask> >::emplace_back<hemlock::voxel::ChunkMeshTask>(hemlock::voxel::ChunkMeshTask&&) (deque.tcc:155) ==7788== by 0x423FB5: std::deque<hemlock::voxel::ChunkMeshTask, std::allocator<hemlock::voxel::ChunkMeshTask> >::push_back(hemlock::voxel::ChunkMeshTask&&) (stl_deque.h:1533) ==7788== by 0x4236DD: std::queue<hemlock::voxel::ChunkMeshTask, std::deque<hemlock::voxel::ChunkMeshTask, std::allocator<hemlock::voxel::ChunkMeshTask> > >::push(hemlock::voxel::ChunkMeshTask&&) (stl_queue.h:248) ==7788== by 0x422BB2: hemlock::voxel::ChunkGrid::handleBlockChange(void const*, hemlock::voxel::BlockChangeEvent) (ChunkGrid.cpp:52) ==7788== by 0x424E3C: void hemlock::Delegate<void, void const*, hemlock::voxel::BlockChangeEvent>::executeWithObject<hemlock::voxel::ChunkGrid, void>(void const*, void (hemlock::TypelessMember::*)(), void const*, hemlock::voxel::BlockChangeEvent) (Delegate.hpp:167) ==7788== by 0x425C09: hemlock::Delegate<void, void const*, hemlock::voxel::BlockChangeEvent>::operator()(void const*, hemlock::voxel::BlockChangeEvent) const (Delegate.hpp:112) ==7788== by 0x424F02: void hemlock::executeDelegate<void, hemlock::voxel::BlockChangeEvent>(stx::basic_any<5ul>, void const*, hemlock::voxel::BlockChangeEvent) (Event.hpp:303) ==7788== by 0x4222C4: hemlock::Event<hemlock::voxel::BlockChangeEvent>::trigger(hemlock::voxel::BlockChangeEvent) (Event.hpp:130) ==7788== by 0x42218D: hemlock::Event<hemlock::voxel::BlockChangeEvent>::operator()(hemlock::voxel::BlockChangeEvent) (Event.hpp:135) ==7788== by 0x422020: hemlock::voxel::Chunk::setBlock(hemlock::voxel::BlockChunkPosition, hemlock::voxel::Block) (Chunk.cpp:25) ==7788== Address 0x18 is not stack'd, malloc'd or (recently) free'd 指针之外,我没有涉及指针,我已经使用GDB确认它是有效的在推。

seg错误发生在hvox::Chunk第一行的deque.tcc内:

std::deque::emplace_back

特别是迭代器if (this->_M_impl._M_finish._M_cur != this->_M_impl._M_finish._M_last - 1) { ... } 似乎无效。

这都是单线程的,所以队列中没有其他任何事情导致迭代器失效(虽然我假设内部迭代器总是有效的?)。

进度报告#1

有人指出,this->_M_impl._M_finish this指针在经过事件系统后可能无效,事实证明是这种情况。这就是说,在离开委托并进入委托的包装函数之前,对象指针是有效的。退出点是:

hvox::ChunkGrid::handleBlockChange

进度报告#2

在尽可能多地挖掘之后,似乎应该有效,并且在其他类似的场景中,事件/委托系统确实正确执行。我甚至尝试将 // Execution routine for member functions (const or not). template<typename SpecificClass, typename = typename std::enable_if<std::is_class<SpecificClass>::value>::type> static ReturnType executeWithObject(GenericObject object, GenericMemberFunction function, Parameters... parameters) { MemberFunction<SpecificClass> operation = (MemberFunction<SpecificClass>)function; SpecificClass* target = (SpecificClass*)object; return (target->*operation)(parameters...); } 对象分配给堆以查看它是否确实是一个范围问题,无济于事 - 该对象肯定仍然存在,它只是没有被分配给hvox::ChunkGrid指针。 / p>

0 个答案:

没有答案