Potential Memory Corruption in Release Build (#3559)

* Potential Memory Corruption in Release Build

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* @lumberyard-employee-dm suggested code

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* warnings as errors found in VS2022

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* simplifying some strucutres used and fixing a bug

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* some unused fixes for VS2022

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* fix for other platforms

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>

* fixes check used in unit tests to be case-insensitive
fixes memory leaks/invalid memory operations in AWSCore tests

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-08-26 15:59:40 -07:00
committed by GitHub
parent 9f55212a19
commit 1be95a1e76
20 changed files with 93 additions and 108 deletions
+1 -1
View File
@@ -425,7 +425,7 @@ namespace Editor
AZStd::array<BYTE, sizeof(RAWINPUT)> rawInputBytesArray;
LPBYTE rawInputBytes = rawInputBytesArray.data();
const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
[[maybe_unused]] const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
CRY_ASSERT(bytesCopied == rawInputSize);
RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
@@ -419,9 +419,9 @@ namespace AZ::IO::ZipDir
}
// defining file attributes for opening files using constants to avoid the need to include windows headers
constexpr int FileFlagNoBufferinf = 0x20000000;
constexpr int FileFlagNoBuffering = 0x20000000;
constexpr int FileAttributeNormal = 0x00000080;
if (m_unbufferedFile.Open(filename, AZ::IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY, FileAttributeNormal | FileAttributeNormal))
if (m_unbufferedFile.Open(filename, AZ::IO::SystemFile::OpenMode::SF_OPEN_READ_ONLY, FileFlagNoBuffering | FileAttributeNormal))
{
m_nSize = aznumeric_cast<int64_t>(m_unbufferedFile.Length());
return true;
@@ -14,6 +14,7 @@
#include <AzCore/Casting/lossy_cast.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <cctype>
@@ -283,11 +284,18 @@ namespace AZ
void LocalFileIO::CheckInvalidWrite([[maybe_unused]] const char* path)
{
#if defined(AZ_ENABLE_TRACING)
const char* assetsAlias = GetAlias("@assets@");
if (path && assetsAlias && AZ::IO::PathView(path).IsRelativeTo(assetsAlias))
const char* assetAliasPath = GetAlias("@assets@");
if (path && assetAliasPath)
{
AZ_Error("FileIO", false, "You may not alter data inside the asset cache. Please check the call stack and consider writing into the source asset folder instead.\n"
"Attempted write location: %s", path);
AZStd::string assetsAlias(assetAliasPath);
AZStd::string pathString = path;
AZStd::to_lower(assetsAlias.begin(), assetsAlias.end());
AZStd::to_lower(pathString.begin(), pathString.end());
if (AZ::IO::PathView(pathString.c_str()).IsRelativeTo(assetsAlias.c_str()))
{
AZ_Error("FileIO", false, "You may not alter data inside the asset cache. Please check the call stack and consider writing into the source asset folder instead.\n"
"Attempted write location: %s", path);
}
}
#endif
}
@@ -543,28 +551,12 @@ namespace AZ
char fullPath[AZ_MAX_PATH_LEN];
ConvertToAbsolutePath(path, fullPath, AZ_MAX_PATH_LEN);
const auto it = AZStd::find_if(m_aliases.begin(), m_aliases.end(), [key](const AliasType& alias)
{
return alias.first.compare(key) == 0;
});
if (it != m_aliases.end())
{
it->second = fullPath;
}
else
{
m_aliases.emplace_back(key, fullPath);
}
m_aliases[key] = fullPath;
}
const char* LocalFileIO::GetAlias(const char* key) const
{
const auto it = AZStd::find_if(m_aliases.begin(), m_aliases.end(), [key](const AliasType& alias)
{
return alias.first.compare(key) == 0;
});
const auto it = m_aliases.find(key);
if (it != m_aliases.end())
{
return it->second.c_str();
@@ -574,10 +566,7 @@ namespace AZ
void LocalFileIO::ClearAlias(const char* key)
{
m_aliases.erase(AZStd::remove_if(m_aliases.begin(), m_aliases.end(), [key](const AliasType& alias)
{
return alias.first.compare(key) == 0;
}), m_aliases.end());
m_aliases.erase(key);
}
AZStd::optional<AZ::u64> LocalFileIO::ConvertToAliasBuffer(char* outBuffer, AZ::u64 outBufferLength, AZStd::string_view inBuffer) const
@@ -682,55 +671,67 @@ namespace AZ
bool LocalFileIO::ResolveAliases(const char* path, char* resolvedPath, AZ::u64 resolvedPathSize) const
{
AZ_Assert(path != resolvedPath && resolvedPathSize > strlen(path), "Resolved path is incorrect");
AZ_Assert(path && path[0] != '%', "%% is deprecated, @ is the only valid alias token");
AZStd::string_view pathView(path);
AZStd::string_view aliasKey;
AZStd::string_view aliasValue;
for (const auto& alias : m_aliases)
{
AZStd::string_view key{ alias.first };
if (AZ::StringFunc::StartsWith(pathView, key)) // we only support aliases at the front of the path
{
aliasKey = key;
aliasValue = alias.second;
break;
}
}
size_t requiredResolvedPathSize = pathView.size() - aliasKey.size() + aliasValue.size() + 1;
AZ_Assert(path != resolvedPath && resolvedPathSize >= requiredResolvedPathSize, "Resolved path is incorrect");
// we assert above, but we also need to properly handle the case when the resolvedPath buffer size
// is too small to copy the source into.
size_t pathLen = strlen(path) + 1; // account for null
if (path == resolvedPath || (resolvedPathSize < pathLen))
if (path == resolvedPath || (resolvedPathSize < requiredResolvedPathSize))
{
return false;
}
azstrncpy(resolvedPath, resolvedPathSize, path, pathLen);
for (const auto& alias : m_aliases)
// Skip past the alias key in the pathView
// must ensure that we are replacing the entire folder name, not a partial (e.g. @GAME01@/ vs @GAME0@/)
if (AZStd::string_view postAliasView = pathView.substr(aliasKey.size());
!aliasKey.empty() && (postAliasView.empty() || postAliasView.starts_with('/') || postAliasView.starts_with('\\')))
{
const char* key = alias.first.c_str();
size_t keyLen = alias.first.length();
if (azstrnicmp(resolvedPath, key, keyLen) == 0) // we only support aliases at the front of the path
// Copy over resolved alias path first
size_t resolvedPathLen = 0;
aliasValue.copy(resolvedPath, aliasValue.size());
resolvedPathLen += aliasValue.size();
// Append the post alias path next
postAliasView.copy(resolvedPath + resolvedPathLen, postAliasView.size());
resolvedPathLen += postAliasView.size();
// Null-Terminated the resolved path
resolvedPath[resolvedPathLen] = '\0';
// If the path started with one of the "asset cache" path aliases, lowercase the path
const char* assetAliasPath = GetAlias("@assets@");
const char* rootAliasPath = GetAlias("@root@");
const char* projectPlatformCacheAliasPath = GetAlias("@projectplatformcache@");
const bool lowercasePath = (assetAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, assetAliasPath)) ||
(rootAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, rootAliasPath)) ||
(projectPlatformCacheAliasPath != nullptr && AZ::StringFunc::StartsWith(resolvedPath, projectPlatformCacheAliasPath));
if (lowercasePath)
{
[[maybe_unused]] bool lowercasePath = LowerIfBeginsWith(resolvedPath, resolvedPathSize, "@assets@")
|| LowerIfBeginsWith(resolvedPath, resolvedPathSize, "@root@")
|| LowerIfBeginsWith(resolvedPath, resolvedPathSize, "@projectplatformcache@");
const char* dest = alias.second.c_str();
size_t destLen = alias.second.length();
char* afterKey = resolvedPath + keyLen;
size_t afterKeyLen = pathLen - keyLen;
// must ensure that we are replacing the entire folder name, not a partial (e.g. @GAME01@/ vs @GAME0@/)
if (*afterKey == '/' || *afterKey == '\\' || *afterKey == 0)
{
if (afterKeyLen + destLen + 1 < resolvedPathSize)//if after replacing the alias the length is greater than the max path size than skip
{
// scoot the right hand side of the replacement over to make room
memmove(resolvedPath + destLen, afterKey, afterKeyLen + 1); // make sure null is copied
memcpy(resolvedPath, dest, destLen); // insert replacement
pathLen -= keyLen;
pathLen += destLen;
AZStd::replace(resolvedPath, resolvedPath + resolvedPathSize, '\\', '/');
return true;
}
}
AZStd::to_lower(resolvedPath, resolvedPath + resolvedPathLen);
}
// Replace any backslashes with posix slashes
AZStd::replace(resolvedPath, resolvedPath + resolvedPathLen, AZ::IO::WindowsPathSeparator, AZ::IO::PosixPathSeparator);
return true;
}
else
{
// The input path doesn't start with an available, copy it directly to the resolved path
pathView.copy(resolvedPath, pathView.size());
// Null-Terminated the resolved path
resolvedPath[pathView.size()] = '\0';
}
// warn on failing to resolve an alias
AZ_Warning(
"LocalFileIO::ResolveAlias", path && path[0] != '@',
"Failed to resolve an alias: %s", path ? path : "(null)");
AZ_Warning("LocalFileIO::ResolveAlias", path && path[0] != '@', "Failed to resolve an alias: %s", path ? path : "(null)");
return false;
}
@@ -803,7 +804,7 @@ namespace AZ
return false;
}
AZ::OSString LocalFileIO::RemoveTrailingSlash(const AZ::OSString& pathStr)
AZStd::string LocalFileIO::RemoveTrailingSlash(const AZStd::string& pathStr)
{
if (pathStr.empty() || (pathStr[pathStr.length() - 1] != '/' && pathStr[pathStr.length() - 1] != '\\'))
{
@@ -813,7 +814,7 @@ namespace AZ
return pathStr.substr(0, pathStr.length() - 1);
}
AZ::OSString LocalFileIO::CheckForTrailingSlash(const AZ::OSString& pathStr)
AZStd::string LocalFileIO::CheckForTrailingSlash(const AZStd::string& pathStr)
{
if (pathStr.empty() || pathStr[pathStr.length() - 1] == '/')
{
@@ -8,16 +8,12 @@
#pragma once
#include <AzCore/base.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/utils.h>
#include <AzCore/std/string/osstring.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/parallel/atomic.h>
#include <AzCore/std/parallel/lock.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Memory/Memory.h>
// This header file and CPP handles the platform specific implementation of code as defined by the FileIOBase interface class.
// In order to make your code portable and functional with both this and the RemoteFileIO class, use the interface to access
@@ -33,7 +29,7 @@ namespace AZ
{
public:
AZ_RTTI(LocalFileIO, "{87A8D32B-F695-4105-9A4D-D99BE15DFD50}", FileIOBase);
AZ_CLASS_ALLOCATOR(LocalFileIO, OSAllocator, 0);
AZ_CLASS_ALLOCATOR(LocalFileIO, SystemAllocator, 0);
LocalFileIO();
~LocalFileIO();
@@ -77,8 +73,6 @@ namespace AZ
bool ConvertToAbsolutePath(const char* path, char* absolutePath, AZ::u64 maxLength) const;
private:
typedef AZStd::pair<AZ::OSString, AZ::OSString> AliasType;
SystemFile* GetFilePointerFromHandle(HandleType fileHandle);
HandleType GetNextHandle();
@@ -90,13 +84,13 @@ namespace AZ
bool LowerIfBeginsWith(char* inOutBuffer, AZ::u64 bufferLen, const char* alias) const;
private:
static AZ::OSString RemoveTrailingSlash(const AZ::OSString& pathStr);
static AZ::OSString CheckForTrailingSlash(const AZ::OSString& pathStr);
static AZStd::string RemoveTrailingSlash(const AZStd::string& pathStr);
static AZStd::string CheckForTrailingSlash(const AZStd::string& pathStr);
mutable AZStd::recursive_mutex m_openFileGuard;
AZStd::atomic<HandleType> m_nextHandle;
AZStd::map<HandleType, SystemFile, AZStd::less<HandleType>, AZ::OSStdAllocator> m_openFiles;
AZStd::vector<AliasType, AZ::OSStdAllocator> m_aliases;
AZStd::unordered_map<HandleType, SystemFile> m_openFiles;
AZStd::unordered_map<AZStd::string, AZStd::string> m_aliases;
void CheckInvalidWrite(const char* path);
};
@@ -100,7 +100,7 @@ namespace AZ
char resolvedPath[AZ_MAX_PATH_LEN];
ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
AZ::OSString pathWithoutSlash = RemoveTrailingSlash(resolvedPath);
AZStd::string pathWithoutSlash = RemoveTrailingSlash(resolvedPath);
bool isInAPK = AZ::Android::Utils::IsApkPath(pathWithoutSlash.c_str());
if (isInAPK)
@@ -115,7 +115,7 @@ namespace AZ
// Skip over the current and parent directory paths
if (filenameView != "." && filenameView != ".." && NameMatchesFilter(name, filter))
{
AZ::OSString foundFilePath = CheckForTrailingSlash(resolvedPath);
AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath);
foundFilePath += name;
// if aliased, de-alias!
azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str());
@@ -150,7 +150,7 @@ namespace AZ
// Skip over the current and parent directory paths
if (filenameView != "." && filenameView != ".." && NameMatchesFilter(entry->d_name, filter))
{
AZ::OSString foundFilePath = CheckForTrailingSlash(resolvedPath);
AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath);
foundFilePath += entry->d_name;
// if aliased, de-alias!
azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str());
@@ -199,7 +199,7 @@ namespace AZ
}
// make directories from bottom to top.
AZ::OSString pathBuffer;
AZStd::string pathBuffer;
size_t pathLength = strlen(resolvedPath);
pathBuffer.reserve(pathLength);
for (size_t pathPos = 0; pathPos < pathLength; ++pathPos)
@@ -61,7 +61,7 @@ namespace AZ
char resolvedPath[AZ_MAX_PATH_LEN] = {0};
ResolvePath(filePath, resolvedPath, AZ_MAX_PATH_LEN);
AZ::OSString withoutSlash = RemoveTrailingSlash(resolvedPath);
AZStd::string withoutSlash = RemoveTrailingSlash(resolvedPath);
DIR* dir = opendir(withoutSlash.c_str());
if (dir != nullptr)
@@ -80,7 +80,7 @@ namespace AZ
// Skip over the current and parent directory paths
if (filenameView != "." && filenameView != ".." && NameMatchesFilter(entry->d_name, filter))
{
AZ::OSString foundFilePath = CheckForTrailingSlash(resolvedPath);
AZStd::string foundFilePath = CheckForTrailingSlash(resolvedPath);
foundFilePath += entry->d_name;
// if aliased, dealias!
azstrcpy(tempBuffer, AZ_MAX_PATH_LEN, foundFilePath.c_str());
@@ -116,7 +116,7 @@ namespace AZ
}
// make directories from bottom to top.
AZ::OSString buf;
AZStd::string buf;
size_t pathLength = strlen(resolvedPath);
buf.reserve(pathLength);
for (size_t pos = 0; pos < pathLength; ++pos)
@@ -128,7 +128,7 @@ namespace AZ
}
// make directories from bottom to top.
AZ::OSString buf;
AZStd::string buf;
size_t pathLength = strlen(resolvedPath);
buf.reserve(pathLength);
for (size_t pos = 0; pos < pathLength; ++pos)
@@ -234,7 +234,7 @@ namespace AzFramework
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &rawInputSize, rawInputHeaderSize);
LPBYTE rawInputBytes = new BYTE[rawInputSize];
const UINT bytesCopied = GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
AzFramework::RawInputNotificationBusWindows::Broadcast(
@@ -752,7 +752,9 @@ namespace UnitTest
// Test that sending in a too small output path fails,
// if the output buffer is too small to hold the resolved path
size_t SMALLER_THAN_FINAL_RESOLVED_PATH = expectedResolvedPath.length() - 1;
AZ_TEST_START_TRACE_SUPPRESSION;
resolveDidWork = local.ResolvePath(aliasTestPath, aliasResolvedPath, SMALLER_THAN_FINAL_RESOLVED_PATH);
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
AZ_TEST_ASSERT(!resolveDidWork);
// test clearing an alias
+2 -2
View File
@@ -1650,10 +1650,10 @@ bool CSystem::HandleMessage([[maybe_unused]] HWND hWnd, UINT uMsg, WPARAM wParam
AZStd::array<BYTE, sizeof(RAWINPUT)> rawInputBytesArray;
LPBYTE rawInputBytes = rawInputBytesArray.data();
const UINT bytesCopied = GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
[[maybe_unused]] const UINT bytesCopied = GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
CRY_ASSERT(bytesCopied == rawInputSize);
RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
[[maybe_unused]] RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
CRY_ASSERT(rawInput);
AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput);
+1 -1
View File
@@ -1293,7 +1293,6 @@ XmlString CXmlNode::getXMLUnsafe(int level, char* tmpBuffer, uint32 sizeOfTmpBuf
// TODO: those 2 saving functions are a bit messy. should probably make a separate one for the use of PlatformAPI
bool CXmlNode::saveToFile(const char* fileName)
{
const size_t chunkSizeBytes = (15 * 1024);
if (!fileName)
{
return false;
@@ -1310,6 +1309,7 @@ bool CXmlNode::saveToFile(const char* fileName)
gEnv->pCryPak->FClose(fileHandle);
return true;
#else
constexpr size_t chunkSizeBytes = (15 * 1024);
bool ret = saveToFile(fileName, chunkSizeBytes, fileHandle);
gEnv->pCryPak->FClose(fileHandle);
return ret;
@@ -270,7 +270,6 @@ namespace TestImpact
{
processInFlight.m_process->Terminate(ProcessTerminateErrorCode);
AccumulateProcessStdContent(processInFlight);
const ProcessId processId = processInFlight.m_process->GetProcessInfo().GetId();
if (isCallingBackToClient)
{
@@ -154,8 +154,6 @@ namespace TestImpact
const AZStd::chrono::milliseconds suiteDuration = AZStd::chrono::milliseconds{suite[TestRunFields::Keys[TestRunFields::DurationKey]].GetUint()};
// Suite enabled
const bool enabled = suite[TestRunFields::Keys[TestRunFields::EnabledKey]].GetBool();
testSuites.emplace_back(TestRunSuite{
suite[TestRunFields::Keys[TestRunFields::NameKey]].GetString(),
suite[TestRunFields::Keys[TestRunFields::EnabledKey]].GetBool(),
@@ -211,7 +211,6 @@ namespace AWSAttributionUnitTest
m_localFileIO->ResolvePath("@user@/Registry/", m_resolvedSettingsPath.data(), m_resolvedSettingsPath.size());
AZ::IO::SystemFile::DeleteDir(m_resolvedSettingsPath.data());
delete AZ::IO::FileIOBase::GetInstance();
AZ::IO::FileIOBase::SetInstance(nullptr);
AWSCoreFixture::TearDown();
@@ -130,10 +130,11 @@ public:
m_settingsRegistry.reset();
AZ::IO::FileIOBase::SetInstance(nullptr);
delete m_localFileIO;
if (m_otherFileIO)
{
delete m_localFileIO;
AZ::IO::FileIOBase::SetInstance(m_otherFileIO);
}
@@ -104,8 +104,6 @@ namespace AZ
{
const RHI::BufferDescriptor& descriptor = request.m_descriptor;
Buffer* buffer = static_cast<Buffer*>(request.m_buffer);
const size_t alignmentInBytes = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
const size_t sizeInBytes = RHI::AlignUp<size_t>(descriptor.m_byteCount, alignmentInBytes);
MemoryView memoryView =
GetDX12RHIDevice().CreateBufferPlaced(
@@ -378,7 +378,6 @@ namespace AZ
}
const uint32_t endRow = AZStd::GetMin(startRow + rowsPerSplit, subresourceLayout.m_rowCount);
const uint32_t numRowsToCopy = endRow - startRow;
// Calculate the blocksize for BC formatted images; the copy command works in texels.
uint32_t heightToCopy = (endRow - startRow) * compressedTexelBlockSizeHeight;
@@ -530,7 +530,6 @@ namespace AZ
transition.StateAfter = GetResourceState(*scopeAttachment);
logger.SetStateAfter(transition.StateAfter);
const bool isCopyQueueAfter = scopeAfter.GetHardwareQueueClass() == RHI::HardwareQueueClass::Copy;
RHI::ImageSubresourceRange viewRange = RHI::ImageSubresourceRange(scopeAttachment->GetImageView()->GetDescriptor());
for (const auto& subresourceState : image.GetAttachmentStateByIndex(&viewRange))
{
@@ -43,8 +43,6 @@ namespace Blast
const Nv::Blast::ExtPxChunk* pxChunks = blastFamily.GetPxAsset().getChunks();
const NvBlastChunk* chunks = tkAsset->getChunks();
const uint32_t pxChunkCount = blastFamily.GetPxAsset().getChunkCount();
const uint32_t chunkCount = tkAsset->getChunkCount();
const uint32_t nodeCount = tkActor.getGraphNodeCount();
AZ_Assert(pxChunks, "ExtPxAsset asset has a null chunk array.");
AZ_Assert(chunks, "TkActor's asset has a null chunk array.");
@@ -183,8 +181,6 @@ namespace Blast
bool BlastActorFactoryImpl::VisibleChunksHasStaticActor(
const BlastFamily& blastFamily, const AZStd::vector<uint32_t>& chunkIndices) const
{
const uint32_t chunkCount = blastFamily.GetPxAsset().getChunkCount();
const Nv::Blast::ExtPxChunk* pxChunks = blastFamily.GetPxAsset().getChunks();
if (!pxChunks)
{
@@ -1821,7 +1821,6 @@ namespace UnitTest
Api::InitializeAsUnitTriangle(*m_whiteBox);
const auto vertexCount = Api::MeshVertexCount(*m_whiteBox);
const auto vertexHandles = Api::MeshVertexHandles(*m_whiteBox);
const auto vertexPositions = Api::MeshVertexPositions(*m_whiteBox);