Arithmetic overflow protections added.

This commit is contained in:
mlemanczyk committed 2023-04-09 00:50:12 +02:00
1 parent b7af797dd7
commit 298af4e718
1 file changed
+22 -22
+22 -22
View File
@@ -44,7 +44,7 @@ namespace Recyclable.Collections
set => _longCount = value; set => _longCount = value;
} }
public int ReservedBlockCount => (int)(_capacity >> _blockSizePow2Shift) + ((_capacity & (_blockSize - 1)) > 0 ? 1 : 0); public int ReservedBlockCount => checked((int)(_capacity >> _blockSizePow2Shift) + ((_capacity & (_blockSize - 1)) > 0 ? 1 : 0));
public int BlockSize => _blockSize; public int BlockSize => _blockSize;
public int NextItemBlockIndex => _nextItemBlockIndex; public int NextItemBlockIndex => _nextItemBlockIndex;
public int NextItemIndex => _nextItemIndex; public int NextItemIndex => _nextItemIndex;
@@ -55,11 +55,11 @@ namespace Recyclable.Collections
T[][] memoryBlocks = list._memoryBlocks; T[][] memoryBlocks = list._memoryBlocks;
int nextItemIndex = list._nextItemIndex; int nextItemIndex = list._nextItemIndex;
int blockSize = list._blockSize; int blockSize = list._blockSize;
int sourceBlockIndex = (int)((index + 1) >> list._blockSizePow2Shift); int sourceBlockIndex = checked((int)((index + 1) >> list._blockSizePow2Shift));
int sourceItemIndex = (int)((index + 1) & (blockSize - 1)); int sourceItemIndex = checked((int)((index + 1) & (blockSize - 1)));
int targetBlockIndex = (int)(index >> list._blockSizePow2Shift); int targetBlockIndex = checked((int)(index >> list._blockSizePow2Shift));
int targetItemIndex = (int)(index & (blockSize - 1)); int targetItemIndex = checked((int)(index & (blockSize - 1)));
int lastTakenBlockIndex = list.LastTakenBlockIndex; int lastTakenBlockIndex = list.LastTakenBlockIndex;
while (sourceBlockIndex < lastTakenBlockIndex || (sourceBlockIndex == lastTakenBlockIndex && (sourceItemIndex < nextItemIndex || sourceBlockIndex != list._nextItemBlockIndex))) while (sourceBlockIndex < lastTakenBlockIndex || (sourceBlockIndex == lastTakenBlockIndex && (sourceItemIndex < nextItemIndex || sourceBlockIndex != list._nextItemBlockIndex)))
@@ -221,7 +221,7 @@ namespace Recyclable.Collections
itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize); itemIndex = Array.IndexOf(memoryBlocksSpan[blockIndex], item, 0, blockSize);
if (itemIndex >= 0) if (itemIndex >= 0)
{ {
return itemIndex + (blockIndex << (31 - BitOperations.LeadingZeroCount((uint)blockSize))); return itemIndex + ((long)blockIndex << (31 - BitOperations.LeadingZeroCount((uint)blockSize)));
} }
} }
@@ -236,15 +236,15 @@ namespace Recyclable.Collections
return ItemNotFoundIndex; return ItemNotFoundIndex;
} }
return itemIndex >= 0 ? itemIndex + (lastBlockIndex << (31 - BitOperations.LeadingZeroCount((uint)blockSize))) : ItemNotFoundIndex; return itemIndex >= 0 ? itemIndex + ((long)lastBlockIndex << (31 - BitOperations.LeadingZeroCount((uint)blockSize))) : ItemNotFoundIndex;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected static long Resize(ref T[][]? source, int minBlockSize, long oldCapacity, long newCapacity, ArrayPool<T[]> memoryBlocksPool, ArrayPool<T> blockArrayPool) protected static long Resize(ref T[][]? source, int minBlockSize, long oldCapacity, long newCapacity, ArrayPool<T[]> memoryBlocksPool, ArrayPool<T> blockArrayPool)
{ {
int minBlockSizePowerToShift = 31 - BitOperations.LeadingZeroCount((uint)minBlockSize); int minBlockSizePowerToShift = 31 - BitOperations.LeadingZeroCount((uint)minBlockSize);
int sourceBlockCount = (int)(oldCapacity >> minBlockSizePowerToShift); int sourceBlockCount = checked((int)(oldCapacity >> minBlockSizePowerToShift));
int requiredBlockCount = (int)(newCapacity >> minBlockSizePowerToShift) + ((newCapacity & (minBlockSize - 1)) > 0 ? 1 : 0); int requiredBlockCount = checked((int)(newCapacity >> minBlockSizePowerToShift) + ((newCapacity & (minBlockSize - 1)) > 0 ? 1 : 0));
int blockIndex; int blockIndex;
T[][]? newMemoryBlocks; T[][]? newMemoryBlocks;
Span<T[]> memoryBlocksSpan; Span<T[]> memoryBlocksSpan;
@@ -310,13 +310,13 @@ namespace Recyclable.Collections
} }
} }
return newMemoryBlocks.Length << minBlockSizePowerToShift; return (long)newMemoryBlocks.Length << minBlockSizePowerToShift;
} }
protected long EnsureCapacity(long requestedCapacity) protected long EnsureCapacity(long requestedCapacity)
{ {
long newCapacity = _capacity > 0 long newCapacity = _capacity > 0
? checked((long)BitOperations.RoundUpToPowerOf2((ulong)requestedCapacity)) ? checked((long)(BitOperations.RoundUpToPowerOf2((ulong)requestedCapacity) - 1))
: requestedCapacity; : requestedCapacity;
newCapacity = Resize(ref _memoryBlocks!, _blockSize, _capacity, newCapacity, _memoryBlocksPool, _blockArrayPool); newCapacity = Resize(ref _memoryBlocks!, _blockSize, _capacity, newCapacity, _memoryBlocksPool, _blockArrayPool);
@@ -339,7 +339,7 @@ namespace Recyclable.Collections
if (expectedItemsCount > 0) if (expectedItemsCount > 0)
{ {
_capacity = Resize(ref _memoryBlocks!, (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize), 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool); _capacity = Resize(ref _memoryBlocks!, checked((int)(BitOperations.RoundUpToPowerOf2((uint)minBlockSize) - 1)), 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool);
if (_memoryBlocks.Length > 0) if (_memoryBlocks.Length > 0)
{ {
minBlockSize = _memoryBlocks[0].Length; minBlockSize = _memoryBlocks[0].Length;
@@ -350,7 +350,7 @@ namespace Recyclable.Collections
} }
else else
{ {
_blockSize = (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize); _blockSize = checked((int)(BitOperations.RoundUpToPowerOf2((uint)minBlockSize) - 1));
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize); _blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
_memoryBlocks = _emptyMemoryBlocksArray; _memoryBlocks = _emptyMemoryBlocksArray;
} }
@@ -365,7 +365,7 @@ namespace Recyclable.Collections
if (expectedItemsCount > 0) if (expectedItemsCount > 0)
{ {
_capacity = Resize(ref _memoryBlocks!, (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize), 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool); _capacity = Resize(ref _memoryBlocks!, checked((int)(BitOperations.RoundUpToPowerOf2((uint)minBlockSize) - 1)), 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool);
if (_memoryBlocks.Length > 0) if (_memoryBlocks.Length > 0)
{ {
minBlockSize = _memoryBlocks[0].Length; minBlockSize = _memoryBlocks[0].Length;
@@ -376,7 +376,7 @@ namespace Recyclable.Collections
} }
else else
{ {
_blockSize = (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize); _blockSize = checked((int)(BitOperations.RoundUpToPowerOf2((uint)minBlockSize) - 1));
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize); _blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
_memoryBlocks = _emptyMemoryBlocksArray; _memoryBlocks = _emptyMemoryBlocksArray;
} }
@@ -387,7 +387,7 @@ namespace Recyclable.Collections
public T this[long index] public T this[long index]
{ {
get => _memoryBlocks[index >> _blockSizePow2Shift][index & (_blockSize - 1)]; get => _memoryBlocks[index >> _blockSizePow2Shift][index & (_blockSize - 1)];
set => new Span<T>(_memoryBlocks[(int)(index >> _blockSizePow2Shift)])[(int)(index & (_blockSize - 1))] = value; set => new Span<T>(_memoryBlocks[checked((int)(index >> _blockSizePow2Shift))])[checked((int)(index & (_blockSize - 1)))] = value;
} }
public T this[int index] public T this[int index]
@@ -525,7 +525,7 @@ namespace Recyclable.Collections
long copiedCount = 0; long copiedCount = 0;
while (copiedCount < itemsCount) while (copiedCount < itemsCount)
{ {
toCopy = (int)Math.Min(itemsCount - copiedCount, itemsSpan.Length); toCopy = checked((int)Math.Min(itemsCount - copiedCount, itemsSpan.Length));
if (targetBlockArraySpan.Length < toCopy) if (targetBlockArraySpan.Length < toCopy)
{ {
toCopy = targetBlockArraySpan.Length; toCopy = targetBlockArraySpan.Length;
@@ -562,7 +562,7 @@ namespace Recyclable.Collections
} }
else else
{ {
_nextItemIndex = (int)(targetCapacity & (blockSize - 1)); _nextItemIndex = checked((int)(targetCapacity & (blockSize - 1)));
_nextItemBlockIndex = targetBlockIndex; _nextItemBlockIndex = targetBlockIndex;
} }
@@ -738,7 +738,7 @@ namespace Recyclable.Collections
if (_nextItemBlockIndex == 0 || (_nextItemBlockIndex == 1 && _nextItemIndex == 0)) if (_nextItemBlockIndex == 0 || (_nextItemBlockIndex == 1 && _nextItemIndex == 0))
{ {
return Array.IndexOf(_memoryBlocks[0], item, 0, (int)_longCount) >= 0; return Array.IndexOf(_memoryBlocks[0], item, 0, checked((int)_longCount)) >= 0;
} }
Span<T[]> memoryBlocksSpan = new(_memoryBlocks); Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
@@ -762,8 +762,8 @@ namespace Recyclable.Collections
public int IndexOf(T item) => _longCount == 0 public int IndexOf(T item) => _longCount == 0
? ItemNotFoundIndex ? ItemNotFoundIndex
: _nextItemBlockIndex == 0 || (_nextItemBlockIndex == 1 && _nextItemIndex == 0) : _nextItemBlockIndex == 0 || (_nextItemBlockIndex == 1 && _nextItemIndex == 0)
? Array.IndexOf(_memoryBlocks[0], item, 0, (int)_longCount) ? Array.IndexOf(_memoryBlocks[0], item, 0, checked((int)_longCount))
: (int)DoIndexOf(item, _memoryBlocks, LastTakenBlockIndex, _blockSize, _nextItemIndex); : checked((int)DoIndexOf(item, _memoryBlocks, LastTakenBlockIndex, _blockSize, _nextItemIndex));
public void Insert(int index, T item) => throw new NotSupportedException(); public void Insert(int index, T item) => throw new NotSupportedException();
@@ -771,7 +771,7 @@ namespace Recyclable.Collections
public long LongIndexOf(T item) => _longCount == 0 public long LongIndexOf(T item) => _longCount == 0
? ItemNotFoundIndex ? ItemNotFoundIndex
: _nextItemBlockIndex == 0 || (_nextItemBlockIndex == 1 && _nextItemIndex == 0) : _nextItemBlockIndex == 0 || (_nextItemBlockIndex == 1 && _nextItemIndex == 0)
? Array.IndexOf(_memoryBlocks[0], item, 0, (int)_longCount) ? Array.IndexOf(_memoryBlocks[0], item, 0, checked((int)_longCount))
: DoIndexOf(item, _memoryBlocks, LastTakenBlockIndex, _blockSize, _nextItemIndex); : DoIndexOf(item, _memoryBlocks, LastTakenBlockIndex, _blockSize, _nextItemIndex);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]