1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-06 18:26:22 +03:00

0026287: Bug in NCollection_AccAllocator::Free() sometimes causes crash in debug mode

This commit is contained in:
myn 2015-05-28 16:20:14 +03:00 committed by bugmaster
parent db2f149828
commit 7c47a3d647
2 changed files with 51 additions and 15 deletions

View File

@ -97,7 +97,7 @@ void NCollection_AccAllocator::Free(void* theAddress)
Block* aBlock = findBlock(theAddress, aKey); Block* aBlock = findBlock(theAddress, aKey);
#if !defined No_Exception && !defined No_Standard_ProgramError #if !defined No_Exception && !defined No_Standard_ProgramError
if (aBlock == 0L || aBlock->allocCount == 0) if (aBlock == 0L || aBlock->IsEmpty())
{ {
Standard_ProgramError::Raise("NCollection_AccAllocator::Free: \ Standard_ProgramError::Raise("NCollection_AccAllocator::Free: \
Trying to free an invalid address"); Trying to free an invalid address");
@ -105,7 +105,7 @@ void NCollection_AccAllocator::Free(void* theAddress)
#endif #endif
aBlock->Free(); aBlock->Free();
if (aBlock->allocCount == 0) if (aBlock->IsEmpty())
{ {
Standard_Address anAddress = aBlock->address; Standard_Address anAddress = aBlock->address;
@ -129,13 +129,38 @@ void NCollection_AccAllocator::Free(void* theAddress)
// If there are no more blocks, reallocate the block to the default size // If there are no more blocks, reallocate the block to the default size
else else
{ {
anAddress = Standard::Reallocate(anAddress, myBlockSize); Standard_Address aNewAddress = Standard::Reallocate(anAddress,
if (anAddress) myBlockSize);
if (aNewAddress == anAddress)
{ {
aBlock->address = anAddress; // Normally, the reallocation keeps the block at the same address
// (since no block can be smaller than the default size, and thus
// the allocated memory is just shrunk or untouched).
// In this case, just update the block's free size.
aBlock->SetFreeSize(myBlockSize);
}
else
{
// Reallocation still may return a different address even if the new
// size is equal to or smaller than the old one (this can happen in
// debug mode).
Key aNewKey = getKey(aNewAddress);
if (aNewKey.Value == aKey.Value)
{
// If the new address have the same key,
// just update the block's address and free size
aBlock->address = aNewAddress;
aBlock->SetFreeSize(myBlockSize);
}
else
{
// If the new address have different key,
// rebind the block to the map of blocks with the new key.
myBlocks.Clear(Standard_False);
mypLastBlock = myBlocks.Bound(aNewKey,
Block(aNewAddress, myBlockSize));
}
} }
aBlock->allocStart = (Standard_Byte*)anAddress
+ (Standard_Size)myBlockSize;
} }
} }
} }
@ -176,14 +201,12 @@ NCollection_AccAllocator::allocateNewBlock(const Standard_Size theSize)
Standard_Address anAddress = Standard::Allocate(theSize); Standard_Address anAddress = Standard::Allocate(theSize);
// we depend on the fact that Standard::Allocate always returns // we depend on the fact that Standard::Allocate always returns
// a pointer aligned to a 4 byte boundary // a pointer aligned to a 4 byte boundary
Block aBlock = {anAddress, mypLastBlock = myBlocks.Bound(getKey(anAddress),
AlignedPtr((Standard_Byte*)anAddress + theSize), Block(anAddress, theSize, mypLastBlock));
mypLastBlock,
0};
mypLastBlock = myBlocks.Bound(getKey(anAddress), aBlock);
#ifdef OCCT_DEBUG_FINDBLOCK #ifdef OCCT_DEBUG_FINDBLOCK
Key aKey; Key aKey;
Standard_ASSERT_VOID(mypLastBlock == findBlock((Standard_Byte*)aBlock.allocStart-1, aKey), Standard_ASSERT_VOID(
mypLastBlock == findBlock((Standard_Byte*)mypLastBlock->allocStart-1, aKey),
"improper work of NCollection_AccAllocator::findBlock"); "improper work of NCollection_AccAllocator::findBlock");
#endif #endif
return mypLastBlock; return mypLastBlock;

View File

@ -106,7 +106,8 @@ protected:
//! A key for the map of blocks //! A key for the map of blocks
struct Key {Standard_Size Value;}; struct Key {Standard_Size Value;};
//! AccAllocator hasher
//! Key hasher
class Hasher class Hasher
{ {
public: public:
@ -125,6 +126,15 @@ protected:
Block* prevBlock; Block* prevBlock;
Standard_Integer allocCount; Standard_Integer allocCount;
Block(const Standard_Address theAddress,
const Standard_Size theSize,
Block* thePrevBlock = 0L)
: address(theAddress), prevBlock(thePrevBlock), allocCount(0)
{SetFreeSize (theSize);}
void SetFreeSize(const Standard_Size theSize)
{allocStart = (Standard_Byte*)address + theSize;}
Standard_Size FreeSize() const Standard_Size FreeSize() const
{return (Standard_Byte*)allocStart - (Standard_Byte*)address;} {return (Standard_Byte*)allocStart - (Standard_Byte*)address;}
@ -133,6 +143,9 @@ protected:
void Free() void Free()
{allocCount--;} {allocCount--;}
Standard_Boolean IsEmpty() const
{return allocCount == 0;}
}; };
// --------- PROTECTED METHODS --------- // --------- PROTECTED METHODS ---------