[ENGINE BUG] TArray64 RangeCheck returns incorrect error messages for values over 32 bit

If you try to access TArray64 value past it’s 32 bit you will get incorrect error message.

Steps to reproduce:

	TArray64<float> DebugMatrices;
    int64 n = 2093952;
    DebugMatrices.AddZeroed(n*3*841); // n*3*841 = 5 283 040 896, 32 bit limit is 2 147 483 647
    UE_LOG(LogTemp, Warning, TEXT("DEBUG_LOG: Zeroed 5 283 040 896 matrices len %lld"), DebugMatrices.Num());
    UE_LOG(LogTemp, Warning, TEXT("last value %f"), DebugMatrices[n*3*841-1]);
    UE_LOG(LogTemp, Warning, TEXT("last+1 value is %f"), DebugMatrices[n*3*841]);

The error:

|||[2022.04.21 - 17.26.37:948][33]LogTemp : Warning : DEBUG_LOG : Zeroed 5 283 040 896 matrices len 5283040896|
|||[2022.04.21 - 17.26.37:948][33]LogTemp : Warning : last value 0|
|||[2022.04.21 - 17.26.37:948][33]LogOutputDevice : Warning :|
Assertion failed: (Index >= 0) & (Index < ArrayNum) [File:C:\3D_Software\UE_5.0\Engine\Source\Runtime\Core\Public\Containers\Array.h] [Line: 691] Array index out of bounds: 988073600 from an array of size 988073600

Expected error:


Assertion failed: (Index >= 0) & (Index < ArrayNum) [File:C:\3D_Software\UE_5.0\Engine\Source\Runtime\Core\Public\Containers\Array.h] [Line: 691] Array index out of bounds: 5283040896 from an array of size 5283040896

The part of the engine code that responsible for bug. I guess the solution is to replace %i with %lld in checkf.

	FORCEINLINE void RangeCheck(SizeType Index) const
	{
		CheckInvariants();

		// Template property, branch will be optimized out
		if (AllocatorType::RequireRangeCheck)
		{
			checkf((Index >= 0) & (Index < ArrayNum),TEXT("Array index out of bounds: %i from an array of size %i"),Index,ArrayNum); // & for one branch
		}
	}

Github code location -
https://github.com/EpicGames/UnrealEngine/blob/46544fa5e0aa9e6740c19b44b0628b72e7bbd5ce/Engine/Source/Runtime/Core/Public/Containers/Array.h#L691

Same error goes for ArrayView64 - https://github.com/EpicGames/UnrealEngine/blob/46544fa5e0aa9e6740c19b44b0628b72e7bbd5ce/Engine/Source/Runtime/Core/Public/Containers/ArrayView.h#L254

1 Like

As TArray64 is a template of TArray, it’s a generic type. It’s most useful when triggering an exception in debug mode anyway…

template<typename T, typename Allocator = FDefaultAllocator> class TArray;
template<typename T> using TArray64 = TArray<T, FDefaultAllocator64>;
template<typename T, typename SizeType = int32> class TArrayView;
template<typename T> using TArrayView64 = TArrayView<T, int64>;
template<typename T, typename SizeType = int32> using TConstArrayView = TArrayView<const T, SizeType>;
template<typename T> using TConstArrayView64 = TConstArrayView<T, int64>;
template<typename T> class TTransArray;