我遇到了一些非常奇怪的问题,我写过一些代码;推送结构时,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) { ... }
似乎无效。
这都是单线程的,所以队列中没有其他任何事情导致迭代器失效(虽然我假设内部迭代器总是有效的?)。
有人指出,this->_M_impl._M_finish
this
指针在经过事件系统后可能无效,事实证明是这种情况。这就是说,在离开委托并进入委托的包装函数之前,对象指针是有效的。退出点是:
hvox::ChunkGrid::handleBlockChange
在尽可能多地挖掘之后,似乎应该有效,并且在其他类似的场景中,事件/委托系统确实正确执行。我甚至尝试将 // 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>