есть.Ошибка диспетчера памяти C++ при удалении объектов
Я разрабатываю пользовательскую виртуальную машину, и я использую пользовательские классы, управляемые памятью (каждый объект будет находиться в одном большом блоке памяти, который будет управлять виртуальной машиной).
Проблема: valgrind дает мне ошибку «Перейти к ошибке, указанному на следующей строке» при попытке удалить один из этих объектов, и я не могу понять, как его исправить.
У кого-нибудь есть ключ? Заранее спасибо.
Ошибка Valgrind:
[Stub] static void CeliVM::MemoryManagedClass::operator delete(pointer) in /home/patrick/Projects/CeliVM/Source/Memory.cxx @ 507
==4812== Jump to the invalid address stated on the next line
==4812== at 0x310040529CBA0040: ???
==4812== by 0x401CA2: main (Main.cxx:89)
==4812== Address 0x310040529cba0040 is not stack'd, malloc'd or (recently) free'd
==4812==
Функция удаления Оператор:
void MemoryManagedClass::operator delete (pointer objectPointer) noexcept
{
MemoryAllocator* memoryAllocator = static_cast<MemoryManagedClass*>(objectPointer)->memoryAllocator;
memoryAllocator->Free(DATA(objectPointer));
}
распределителем памяти "Свободный" метод:
void BasicMemoryAllocator::Free(data dataBlock)
{
// Find the allocated block on the list.
u64 allocatedBlockIndex = Kernel.Any;
for (u64 blockIndex = 0; blockIndex < this->numberOfAllocatedBlocks; blockIndex++)
if (this->allocatedBlocks[ blockIndex ].block == dataBlock)
{
allocatedBlockIndex = blockIndex;
break;
}
if (allocatedBlockIndex == Kernel.Any)
{
ERROR(Txt::CouldNotFindRequestedAllocatedBlock, intpointer(dataBlock));
return;
}
// Check if we have an adjacent free block we can expand or we need to create a new one.
u64 freeBlockIndex = Kernel.Any;
for (u64 blockIndex = 0; blockIndex < this->numberOfFreeBlocks; blockIndex++)
if ((this->freeBlocks[ blockIndex ].start == this->allocatedBlocks[ allocatedBlockIndex ].end + 1) ||
(this->freeBlocks[ blockIndex ].end == this->allocatedBlocks[ allocatedBlockIndex ].start - 1))
{
freeBlockIndex = blockIndex;
break;
}
if (freeBlockIndex == Kernel.Any)
{
// If we do not have more "free blocks" to use, we must expand the free blocks list.
if (this->numberOfFreeBlocks == this->freeBlocksCapacity)
{
BlockInfo* newFreeBlocks = new (std::nothrow) BlockInfo[ this->freeBlocksCapacity + BasicMemoryAllocator::BlocksCapacityIncrement ];
if (!newFreeBlocks)
{
ERROR(Txt::CouldNotExpandFreeBlocksList);
return;
}
memcpy(newFreeBlocks, this->freeBlocks, this->freeBlocksCapacity * sizeof(BlockInfo));
delete [] this->freeBlocks;
this->freeBlocks = newFreeBlocks;
this->freeBlocksCapacity += BasicMemoryAllocator::BlocksCapacityIncrement;
DEBUG(Dbg::FreeBlocksListExpanded, this->freeBlocksCapacity);
}
memcpy(&this->freeBlocks[ this->numberOfFreeBlocks++ ], &this->allocatedBlocks[ allocatedBlockIndex ], sizeof(BlockInfo));
}
else
{
// Join the freed block to the adjacent free block.
this->freeBlocks[ freeBlockIndex ].size += this->allocatedBlocks[ allocatedBlockIndex ].size;
if (this->freeBlocks[ freeBlockIndex ].start == this->allocatedBlocks[ allocatedBlockIndex ].end + 1)
this->freeBlocks[ freeBlockIndex ].start = this->allocatedBlocks[ allocatedBlockIndex ].start;
else
this->freeBlocks[ freeBlockIndex ].end = this->allocatedBlocks[ allocatedBlockIndex ].end;
}
// Remove the allocated block from the allocated blocks list.
u64 blockStart = this->allocatedBlocks[ allocatedBlockIndex ].start;
u64 blockEnd = this->allocatedBlocks[ allocatedBlockIndex ].end;
this->numberOfAllocatedBlocks--;
if (allocatedBlockIndex < this->numberOfAllocatedBlocks)
memcpy(&this->allocatedBlocks[ allocatedBlockIndex ], &this->allocatedBlocks[ this->numberOfAllocatedBlocks ], sizeof(BlockInfo));
DEBUG(Dbg::BlockFreed, blockStart, blockEnd);
}
Ваша программа имеет неопределенное поведение, путем доступа к объекту после того, как его срок службы закончился. 'operator delete' запускается после деструктора; переменные участника теперь мертвого объекта исчезли, в том числе один с именем 'memoryAllocator'. –
Интересно, но это единственный потомок MemoryManagedClass, который ведет себя так, другие классы работают нормально. В моем понимании, поскольку memoryAllocator не уничтожается, когда класс уничтожен, он все еще находится в том же месте памяти, что и всегда, и поскольку я управляю блоком памяти, у меня не должно быть причин не иметь доступа к нему. Но во всяком случае, спасибо, возможно, я буду использовать глобальные распределители. – patrickMelo
Имеет ли этот проблемный потомок (назовем его 'D') другими базовыми классами? Возможно, виртуальный базовый класс? Я предполагаю, что у вас проблемы с этим, потому что под-объект 'MemoryManagedClass' не находится в смещении 0 в экземпляре' D', и поэтому 'static_cast (objectPointer)' дает неверный адрес. Фактически вы делаете 'reinterpret_cast (static_cast (objectPointer))', который показывает неопределенное поведение (по другой причине), но, похоже, будет работать до тех пор, пока 'MemoryManagedClass' просто окажется расположенным со смещением 0 внутри 'D'. –