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:
parent
db2f149828
commit
7c47a3d647
@ -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;
|
||||||
|
@ -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 ---------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user