- Mesaj
- 1.586
- Çözümler
- 57
- Beğeni
- 3.168
- Puan
- 1.839
- Ticaret Puanı
- 0
Release client'ta ışınlanma sırasında çökme (DDS yükleyici sınır kontrolü)
Işınlanma sırasında Release client'ın bazen çökmesi, Debug client'ın ise hiç çökmemesi klasik bir tablodur. Sebep optimizasyon değil, iki derlemenin dosyaları farklı yerden okumasıdır.
Yani hata her iki derlemede de vardır; sadece Release'de patlar. Çağrı yığını genelde şöyle biter:
Düzeltilen sorunlar:
EterImageLib/DXTCImage.h
EterImageLib/DXTCImage.cpp
EterLib/GrpImageTexture.cpp
EterPack/EterPack.cpp
Aşağıdaki satır dosyada 2 kez geçer (
EterLib/Resource.cpp
Aşağıdaki satır dosyada 2 kez geçer (
Işınlanma sırasında Release client'ın bazen çökmesi, Debug client'ın ise hiç çökmemesi klasik bir tablodur. Sebep optimizasyon değil, iki derlemenin dosyaları farklı yerden okumasıdır.
- UserInterface.vcxproj içinde
_DISTRIBUTEsadece Release'de tanımlıdır. Bu da UserInterface.cpp içindekibPackFirstdeğerini değiştirir. - Debug -> SEARCH_FILE_FIRST: dosyalar diskten, 0 offsetinden map'lenir. Dosyanın sonundan sonra tam bir sayfa (4 KB) okunabilir durumda kalır, dolayısıyla taşma sessizce yutulur.
- Release -> SEARCH_PACK_FIRST: dosyalar .epk içinden, tam olarak girdinin boyutu kadar bir
MapViewOfFilepenceresiyle okunur. Verinin bittiği yerden sonraki ilk bayt map'lenmemiş bir sayfaya denk gelebilir ->0xC0000005.
Yani hata her iki derlemede de vardır; sadece Release'de patlar. Çağrı yığını genelde şöyle biter:
Kod:
memcpy
CDXTCImage::Copy DXTCImage.cpp
CGraphicImageTexture::CreateDDSTexture
CGraphicImageTexture::CreateFromMemoryFile
CGraphicImage::OnLoad
CResource::Load
CMapOutdoor::CMapOutdoor MapOutdoor.cpp
CMapManager::AllocMap
CPythonBackground::Create
CPythonNetworkStream::Warp
Düzeltilen sorunlar:
LoadHeaderFromMemoryher görüntü dosyasından (DDS olsun olmasın) koşulsuz 128 bayt okuyordu. fog.tga 76 bayttır; yani her TGA yüklemesinde 52 baytlık taşma oluyordu.- "DDS " imzası kontrolü kaynakta yorum satırı yapılmıştı. DDS olmayan dosyalar DDS gibi ayrıştırılıyordu.
Copy()hiçbir sınır kontrolü yapmadanm_lPitch >> (miplevel * 2)kadar bayt kopyalıyordu. Çöken satır budur.- Mipmap boyut hesabı (
dwLinearSize >>= 2) blok sıkıştırmanın 4x4 minimumunu yok sayıyordu; zincirin sonundaki seviyeler yanlış offsetten okunuyordu. CreateFromMemoryFileiçindekistatic CDXTCImage image, önceki dosyanın (artık yok olmuş) tamponuna işaret eden pointer'ları saklıyordu; ayrıca arka plan yükleme thread'i ile paylaşılıyordu.CEterPack::Get / Get2içindekiout_file.Create()dönüş değeri kontrol edilmiyordu. Başarısız olursa*datahiç yazılmıyor, fonksiyon yine detruedönüyordu;CResource::LoadiçindekifileDatade ilk değer almamış olduğundan yükleyicilere çöp pointer gidiyordu.
EterImageLib/DXTCImage.h
aratın:
const BYTE* m_pbCompBufferByLevels[MAX_MIPLEVELS];
değiştirin:
const BYTE* m_pbCompBufferByLevels[MAX_MIPLEVELS];
// Valid bytes behind each m_pbCompBufferByLevels entry, clamped to the
// size of the buffer the header was parsed from.
DWORD m_adwMipSizes[MAX_MIPLEVELS];
aratın:
bool LoadFromMemory(const BYTE * c_pbMap);
bool LoadHeaderFromMemory(const BYTE * c_pbMap);
bool Copy(int miplevel, BYTE * pbDest, long lDestPitch);
değiştirin:
bool LoadFromMemory(const BYTE * c_pbMap, DWORD dwBufSize);
bool LoadHeaderFromMemory(const BYTE * c_pbMap, DWORD dwBufSize);
bool Copy(int miplevel, BYTE * pbDest, long lDestPitch, DWORD dwDestSize = 0xFFFFFFFF);
EterImageLib/DXTCImage.cpp
aratın:
void CDXTCImage::Initialize()
{
m_nWidth = 0;
m_nHeight = 0;
for (int i = 0; i < MAX_MIPLEVELS; ++i)
{
m_pbCompBufferByLevels[i] = NULL;
}
}
değiştirin:
void CDXTCImage::Initialize()
{
m_nWidth = 0;
m_nHeight = 0;
m_nCompSize = 0;
m_nCompLineSz = 0;
m_strFormat[0] = '\0';
m_CompFormat = PF_UNKNOWN;
m_lPitch = 0;
m_dwMipMapCount = 0;
m_bMipTexture = false;
m_dwFlags = 0;
memset(&m_xddPixelFormat, 0, sizeof(m_xddPixelFormat));
for (int i = 0; i < MAX_MIPLEVELS; ++i)
{
m_pbCompBufferByLevels[i] = NULL;
m_adwMipSizes[i] = 0;
}
}
aratın:
return LoadFromMemory((const BYTE*) pvMap);
değiştirin:
return LoadFromMemory((const BYTE*) pvMap, mappedFile.Size());
aratın:
bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap)
{
//////////////////////////////////////
// start reading the file
// from Microsoft's mssdk D3DIM example "Compress"
DWORD dwMagic;
// Read magic number
dwMagic = *(DWORD*) c_pbMap;
c_pbMap += sizeof(DWORD);
//!@#
// if (dwMagic != MAKEFOURCC('D','D','S',' '))
// return false;
DDSURFACEDESC2 ddsd; // read from dds file
// Read the surface description
memcpy(&ddsd, c_pbMap, sizeof(DDSURFACEDESC2));
c_pbMap += sizeof(DDSURFACEDESC2);
// Does texture have mipmaps?
m_bMipTexture = (ddsd.dwMipMapCount > 0) ? TRUE : FALSE;
// Clear unwanted flags
// Can't do this!!! surface not re-created here
// ddsd.dwFlags &= (~DDSD_PITCH);
// ddsd.dwFlags &= (~DDSD_LINEARSIZE);
// Is it DXTC ?
// I sure hope pixelformat is valid!
m_xddPixelFormat.dwFlags = ddsd.ddpfPixelFormat.dwFlags;
m_xddPixelFormat.dwFourCC = ddsd.ddpfPixelFormat.dwFourCC;
m_xddPixelFormat.dwSize = ddsd.ddpfPixelFormat.dwSize;
m_xddPixelFormat.dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount;
m_xddPixelFormat.dwRGBAlphaBitMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
m_xddPixelFormat.dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask;
m_xddPixelFormat.dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask;
m_xddPixelFormat.dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask;
DecodePixelFormat(m_strFormat, &m_xddPixelFormat);
if (m_CompFormat != PF_DXT1 &&
m_CompFormat != PF_DXT3 &&
m_CompFormat != PF_DXT5)
{
return false;
}
if (ddsd.dwMipMapCount > MAX_MIPLEVELS)
{
ddsd.dwMipMapCount = MAX_MIPLEVELS;
}
m_nWidth = ddsd.dwWidth;
m_nHeight = ddsd.dwHeight;
//!@#
m_dwMipMapCount = max(1, ddsd.dwMipMapCount);
m_dwFlags = ddsd.dwFlags;
if (ddsd.dwFlags & DDSD_PITCH)
{
m_lPitch = ddsd.lPitch;
m_pbCompBufferByLevels[0] = c_pbMap;
}
else
{
m_lPitch = ddsd.dwLinearSize;
if (ddsd.dwFlags & DDSD_MIPMAPCOUNT)
{
for (DWORD dwLinearSize = ddsd.dwLinearSize, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2)
{
m_pbCompBufferByLevels[i] = c_pbMap;
c_pbMap += dwLinearSize;
}
}
else
{
m_pbCompBufferByLevels[0] = c_pbMap;
}
}
return true;
}
değiştirin:
// Bytes occupied by one mip level of a block-compressed surface. A DXT surface
// never shrinks below a single 4x4 block, so the old "linear size >>= 2 per
// level" shortcut is wrong for the tail of the chain.
static DWORD GetDXTLevelSize(EPixFormat compFormat, int nWidth, int nHeight, int nLevel)
{
const DWORD dwBlockBytes = (PF_DXT1 == compFormat) ? 8 : 16;
int nLevelWidth = nWidth >> nLevel;
int nLevelHeight = nHeight >> nLevel;
if (nLevelWidth < 1)
{
nLevelWidth = 1;
}
if (nLevelHeight < 1)
{
nLevelHeight = 1;
}
return (DWORD)((nLevelWidth + 3) / 4) * (DWORD)((nLevelHeight + 3) / 4) * dwBlockBytes;
}
bool CDXTCImage::LoadHeaderFromMemory(const BYTE * c_pbMap, DWORD dwBufSize)
{
// Drop everything the previous file left behind first. A failed probe must
// not leave this object holding pointers into a buffer that is already gone
// (resource buffers are mapped views owned by a stack CMappedFile).
Initialize();
const DWORD c_dwHeaderSize = sizeof(DWORD) + sizeof(DDSURFACEDESC2);
if (!c_pbMap || dwBufSize < c_dwHeaderSize)
{
return false;
}
//////////////////////////////////////
// start reading the file
// from Microsoft's mssdk D3DIM example "Compress"
DWORD dwMagic;
// Read magic number
dwMagic = *(DWORD*) c_pbMap;
c_pbMap += sizeof(DWORD);
// This runs on every image the client loads, DDS or not, so the magic has to
// be checked before the surface description is read out of the buffer.
if (dwMagic != MAKEFOURCC('D', 'D', 'S', ' '))
{
return false;
}
DDSURFACEDESC2 ddsd; // read from dds file
// Read the surface description
memcpy(&ddsd, c_pbMap, sizeof(DDSURFACEDESC2));
c_pbMap += sizeof(DDSURFACEDESC2);
// Does texture have mipmaps?
m_bMipTexture = (ddsd.dwMipMapCount > 0) ? TRUE : FALSE;
// Clear unwanted flags
// Can't do this!!! surface not re-created here
// ddsd.dwFlags &= (~DDSD_PITCH);
// ddsd.dwFlags &= (~DDSD_LINEARSIZE);
// Is it DXTC ?
// I sure hope pixelformat is valid!
m_xddPixelFormat.dwFlags = ddsd.ddpfPixelFormat.dwFlags;
m_xddPixelFormat.dwFourCC = ddsd.ddpfPixelFormat.dwFourCC;
m_xddPixelFormat.dwSize = ddsd.ddpfPixelFormat.dwSize;
m_xddPixelFormat.dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount;
m_xddPixelFormat.dwRGBAlphaBitMask = ddsd.ddpfPixelFormat.dwRGBAlphaBitMask;
m_xddPixelFormat.dwRBitMask = ddsd.ddpfPixelFormat.dwRBitMask;
m_xddPixelFormat.dwGBitMask = ddsd.ddpfPixelFormat.dwGBitMask;
m_xddPixelFormat.dwBBitMask = ddsd.ddpfPixelFormat.dwBBitMask;
DecodePixelFormat(m_strFormat, &m_xddPixelFormat);
if (m_CompFormat != PF_DXT1 &&
m_CompFormat != PF_DXT3 &&
m_CompFormat != PF_DXT5)
{
return false;
}
if (0 == ddsd.dwWidth || 0 == ddsd.dwHeight)
{
return false;
}
if (ddsd.dwMipMapCount > MAX_MIPLEVELS)
{
ddsd.dwMipMapCount = MAX_MIPLEVELS;
}
m_nWidth = ddsd.dwWidth;
m_nHeight = ddsd.dwHeight;
m_dwMipMapCount = max(1, ddsd.dwMipMapCount);
m_dwFlags = ddsd.dwFlags;
const DWORD c_dwDataSize = dwBufSize - c_dwHeaderSize;
if (ddsd.dwFlags & DDSD_PITCH)
{
m_lPitch = ddsd.lPitch;
m_dwMipMapCount = 1;
m_pbCompBufferByLevels[0] = c_pbMap;
m_adwMipSizes[0] = c_dwDataSize;
return c_dwDataSize > 0;
}
m_lPitch = ddsd.dwLinearSize;
const DWORD c_dwLevelCount = (ddsd.dwFlags & DDSD_MIPMAPCOUNT) ? m_dwMipMapCount : 1;
DWORD dwOffset = 0;
DWORD dwValidLevels = 0;
for (DWORD i = 0; i < c_dwLevelCount; ++i)
{
if (dwOffset >= c_dwDataSize)
{
break; // file is truncated - stop instead of running off the end
}
DWORD dwLevelSize = GetDXTLevelSize(m_CompFormat, m_nWidth, m_nHeight, (int) i);
// Never hand out more bytes than the buffer actually holds. In a pack
// build the buffer is a MapViewOfFile window sized to the entry, so one
// byte past the end can be an unmapped page.
if (dwLevelSize > c_dwDataSize - dwOffset)
{
dwLevelSize = c_dwDataSize - dwOffset;
}
m_pbCompBufferByLevels[i] = c_pbMap + dwOffset;
m_adwMipSizes[i] = dwLevelSize;
dwOffset += dwLevelSize;
++dwValidLevels;
}
if (0 == dwValidLevels)
{
return false;
}
m_dwMipMapCount = dwValidLevels;
return true;
}
aratın:
bool CDXTCImage::LoadFromMemory(const BYTE * c_pbMap)
{
if (!LoadHeaderFromMemory(c_pbMap))
{
return false;
}
if (m_dwFlags & DDSD_PITCH)
{
DWORD dwBytesPerRow = m_nWidth * m_xddPixelFormat.dwRGBBitCount / 8;
m_nCompSize = m_lPitch * m_nHeight;
m_nCompLineSz = dwBytesPerRow;
m_bCompVector[0].resize(m_nCompSize);
BYTE * pDest = &m_bCompVector[0][0];
c_pbMap = m_pbCompBufferByLevels[0];
for (int yp = 0; yp < m_nHeight; ++yp)
{
memcpy(pDest, c_pbMap, dwBytesPerRow);
pDest += m_lPitch;
c_pbMap += m_lPitch;
}
}
else
{
if (m_dwFlags & DDSD_MIPMAPCOUNT)
{
for (DWORD dwLinearSize = m_lPitch, i = 0; i < m_dwMipMapCount; ++i, dwLinearSize >>= 2)
{
m_bCompVector[i].resize(dwLinearSize);
Copy(i, &m_bCompVector[i][0], dwLinearSize);
}
}
else
{
m_bCompVector[0].resize(m_lPitch);
Copy(0, &m_bCompVector[0][0], m_lPitch);
}
}
// done reading file
return true;
}
değiştirin:
bool CDXTCImage::LoadFromMemory(const BYTE * c_pbMap, DWORD dwBufSize)
{
if (!LoadHeaderFromMemory(c_pbMap, dwBufSize))
{
return false;
}
if (m_dwFlags & DDSD_PITCH)
{
DWORD dwBytesPerRow = m_nWidth * m_xddPixelFormat.dwRGBBitCount / 8;
if (m_lPitch <= 0 || dwBytesPerRow > (DWORD) m_lPitch)
{
return false;
}
m_nCompSize = m_lPitch * m_nHeight;
m_nCompLineSz = dwBytesPerRow;
m_bCompVector[0].resize(m_nCompSize);
BYTE * pDest = &m_bCompVector[0][0];
const BYTE * c_pbSrc = m_pbCompBufferByLevels[0];
DWORD dwAvailable = m_adwMipSizes[0];
for (int yp = 0; yp < m_nHeight; ++yp)
{
if (dwAvailable < dwBytesPerRow)
{
break; // truncated source - leave the remaining rows zeroed
}
memcpy(pDest, c_pbSrc, dwBytesPerRow);
pDest += m_lPitch;
c_pbSrc += m_lPitch;
dwAvailable -= (dwAvailable < (DWORD) m_lPitch) ? dwAvailable : (DWORD) m_lPitch;
}
}
else
{
for (DWORD i = 0; i < m_dwMipMapCount; ++i)
{
m_bCompVector[i].resize(m_adwMipSizes[i]);
if (m_adwMipSizes[i])
{
Copy((int) i, &m_bCompVector[i][0], m_adwMipSizes[i], m_adwMipSizes[i]);
}
}
}
// done reading file
return true;
}
aratın:
bool CDXTCImage::Copy(int miplevel, BYTE * pbDest, long lDestPitch)
{
if (!(m_dwFlags & DDSD_MIPMAPCOUNT))
if (miplevel)
{
return false;
}
/*
DXTColBlock * pBlock;
WORD * pPos = (WORD *) &m_pbCompBufferByLevels[miplevel][0];
int xblocks = (m_nWidth >> miplevel) / 4;
int yblocks = (m_nHeight >> miplevel) / 4;
for (int y = 0; y < yblocks; ++y)
{
// 8 bytes per block
pBlock = (DXTColBlock*) ((DWORD) pPos + y * xblocks * 8);
memcpy(pbDest, pBlock, xblocks * 8);
pbDest += lDestPitch;
}
*/
memcpy(pbDest, m_pbCompBufferByLevels[miplevel], m_lPitch >> (miplevel * 2));
pbDest += lDestPitch;
return true;
}
değiştirin:
bool CDXTCImage::Copy(int miplevel, BYTE * pbDest, long /*lDestPitch*/, DWORD dwDestSize)
{
if (miplevel < 0 || miplevel >= MAX_MIPLEVELS)
{
return false;
}
if (!pbDest || !m_pbCompBufferByLevels[miplevel])
{
return false;
}
DWORD dwCopySize = m_adwMipSizes[miplevel];
if (0 == dwCopySize)
{
return false;
}
// m_adwMipSizes was clamped to the source buffer when the header was read,
// and dwDestSize bounds the surface we were handed, so this memcpy can no
// longer walk off either end.
if (dwCopySize > dwDestSize)
{
dwCopySize = dwDestSize;
}
memcpy(pbDest, m_pbCompBufferByLevels[miplevel], dwCopySize);
return true;
}
EterLib/GrpImageTexture.cpp
aratın:
// 3. Fill the system memory staging texture
for (DWORD i = 0; i < mipmapCount; ++i)
{
D3DLOCKED_RECT lockedRect;
if (FAILED(lpd3dSysMemTexture->LockRect(i, &lockedRect, nullptr, 0)))
{
TraceError("CreateDDSTexture: Cannot lock system memory texture for mipmap %d", i);
lpd3dSysMemTexture->Release();
m_lpd3dTexture->Release();
m_lpd3dTexture = nullptr;
return false;
}
image.Copy(i, (BYTE*)lockedRect.pBits, lockedRect.Pitch);
lpd3dSysMemTexture->UnlockRect(i);
}
değiştirin:
// 3. Fill the system memory staging texture
// D3DX can hand back fewer levels than we asked for, and the source file
// may hold fewer still, so bound the loop by both.
DWORD dwLevelCount = lpd3dSysMemTexture->GetLevelCount();
if (dwLevelCount > (DWORD) mipmapCount)
{
dwLevelCount = (DWORD) mipmapCount;
}
for (DWORD i = 0; i < dwLevelCount; ++i)
{
D3DSURFACE_DESC levelDesc;
if (FAILED(lpd3dSysMemTexture->GetLevelDesc(i, &levelDesc)))
{
TraceError("CreateDDSTexture: Cannot query system memory texture level %lu", i);
lpd3dSysMemTexture->Release();
m_lpd3dTexture->Release();
m_lpd3dTexture = nullptr;
return false;
}
D3DLOCKED_RECT lockedRect;
if (FAILED(lpd3dSysMemTexture->LockRect(i, &lockedRect, nullptr, 0)))
{
TraceError("CreateDDSTexture: Cannot lock system memory texture for mipmap %lu", i);
lpd3dSysMemTexture->Release();
m_lpd3dTexture->Release();
m_lpd3dTexture = nullptr;
return false;
}
// For a block-compressed surface Pitch is the byte size of one row of
// 4x4 blocks, so this is the size of the whole level.
const DWORD dwDestSize = ((levelDesc.Height + 3) / 4) * (DWORD) lockedRect.Pitch;
image.Copy((int) i, (BYTE*)lockedRect.pBits, lockedRect.Pitch, dwDestSize);
lpd3dSysMemTexture->UnlockRect(i);
}
aratın:
static CDXTCImage image;
değiştirin:
if (!c_pvBuf || 0 == bufSize)
{
TraceError("CreateFromMemoryFile: empty buffer for %s", m_stFileName.c_str());
return false;
}
// Not static: this object holds pointers into c_pvBuf, which is only valid
// for the duration of this call.
CDXTCImage image;
aratın:
if (image.LoadHeaderFromMemory((const BYTE*) c_pvBuf))
değiştirin:
if (image.LoadHeaderFromMemory((const BYTE*) c_pvBuf, bufSize))
EterPack/EterPack.cpp
Aşağıdaki satır dosyada 2 kez geçer (
Get ve Get2 içinde). Her ikisini de değiştirin.
aratın:
out_file.Create(m_stDataFileName.c_str(), data, index->data_position, index->data_size);
değiştirin:
// Must be checked: on failure *data is never written, and the callers
// hand that pointer straight to the resource loaders.
if (!out_file.Create(m_stDataFileName.c_str(), data, index->data_position, index->data_size))
{
TraceError("Failed to map pack data : %s (pos %ld, size %ld)", filename, index->data_position, index->data_size);
return false;
}
EterLib/Resource.cpp
Aşağıdaki satır dosyada 2 kez geçer (
Load ve Reload içinde). Her ikisini de değiştirin.
aratın:
LPCVOID fileData;
değiştirin:
LPCVOID fileData = NULL;
Son düzenleme: