2016-11-15 14 views
0

があります。オブジェクトを削除するときにC++カスタムメモリマネージャエラーが発生しました

私はカスタム仮想マシンを開発しています。カスタムメモリ管理クラスを使用しています(すべてのオブジェクトは、仮想マシンが管理する1つの大きなメモリブロックにあります)。

問題は次のとおりです。これらのオブジェクトの1つを削除しようとすると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== 

delete演算子:

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); 
} 
+0

あなたのプログラムは、その寿命が終了した後のオブジェクトにアクセスする方法によって、未定義の挙動を示します。 'operator delete'はデストラクタの後に実行されます。死んだオブジェクトのメンバ変数はなくなりました。これには 'memoryAllocator'という名前のものも含まれます。 –

+0

面白いですが、これはこのように動作する唯一のMemoryManagedClassの子孫です。他のクラスも正常に動作します。私の理解では、クラスが破壊されたときにmemoryAllocatorが破壊されないので、それは常に同じメモリ位置にあります。メモリブロックを管理しているので、アクセスできない理由がありません。しかし、とにかく、ありがとう、おそらく私は代わりにグローバルアロケータを使用します。 – patrickMelo

+0

問題のある子孫( 'D 'と呼ぶ)は他の基本クラスを持っていますか?おそらく仮想基本クラス?私の推測では、 'MemoryManagedClass'サブオブジェクトは' D'インスタンス内のオフセット0にないので、 'static_cast (objectPointer)'はあなたに間違ったアドレスを与えるので、あなたはそれに問題があります。効果的には、 'reinterpret_cast (static_cast (objectPointer))'を実行していますが、別の理由で未定義の動作をしますが、 'MemoryManagedClass'がちょうどオフセット0に位置する限り動作するようです「D」の内側にある。 –

答えて

0

EDIT:

問題のクラスには仮想デストラクタがありますが、基本クラスには含まれていません。基本クラスに仮想デストラクタを追加することは、この問題を解決するようです。オブジェクトにオブジェクトを割り当てるために使用されるメモリアロケータのアドレスを削除するときにはその前に見つけることができます:


まあ、オブジェクトの前に余分のint64を割り当て、そこにメモリアロケータアドレスを保存すると、問題を解決するように見えましたメモリ。新しい

pointer MemoryManagedClass::operator new (size_t dataSize, MemoryAllocator* memoryAllocator) noexcept 
{ 
    pointer objectAddress = memoryAllocator->Get(dataSize + sizeof(i64)); 

    if (!objectAddress) 
     return NULL; 

    static_cast<MemoryManagedClass*>(objectAddress)->memoryAllocator = memoryAllocator; 

    i64 allocatorAddress = intpointer(memoryAllocator); 
    memcpy(objectAddress, &allocatorAddress, sizeof(i64)); 

    return DATA(objectAddress) + sizeof(i64); 
} 

削除:

void MemoryManagedClass::operator delete (pointer objectPointer) noexcept 
{ 
    i64 allocatorAddress = *reinterpret_cast<i64*>(DATA(objectPointer) - sizeof(i64)); 
    MemoryAllocator* memoryAllocator = reinterpret_cast<MemoryAllocator*>(allocatorAddress); 

    memoryAllocator->Free(DATA(objectPointer) - sizeof(i64)); 
} 
関連する問題