From 2e52d12ef1ecc53f1affdf7b6d2150e9256eee65 Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine Date: Wed, 19 Oct 2016 02:09:47 +0300 Subject: MAINT-6819 Fix for LLTextureCacheRemoteWorker::doWrite crash --- indra/newview/lltexturecache.cpp | 167 +++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 67 deletions(-) (limited to 'indra/newview/lltexturecache.cpp') diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 36c4f0d516..a541273621 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -547,10 +547,18 @@ bool LLTextureCacheRemoteWorker::doWrite() // First state / stage : check that what we're trying to cache is in an OK shape if (mState == INIT) { - llassert_always(mOffset == 0); // We currently do not support write offsets - llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative... - llassert_always(mImageSize >= mDataSize); - mState = CACHE; + if ((mOffset != 0) // We currently do not support write offsets + || (mDataSize <= 0) // Things will go badly wrong if mDataSize is nul or negative... + || (mImageSize < mDataSize)) + { + LL_WARNS() << "INIT state check failed" << LL_ENDL; + mDataSize = -1; // failed + done = true; + } + else + { + mState = CACHE; + } } // No LOCAL state for write(): because it doesn't make much sense to cache a local file... @@ -559,7 +567,7 @@ bool LLTextureCacheRemoteWorker::doWrite() if (!done && (mState == CACHE)) { bool alreadyCached = false; - LLTextureCache::Entry entry ; + LLTextureCache::Entry entry; // Checks if this image is already in the entry list idx = mCache->getHeaderCacheEntry(mID, entry); @@ -571,107 +579,132 @@ bool LLTextureCacheRemoteWorker::doWrite() // (almost always) write to the fast cache. if (mRawImage->getDataSize()) { - llassert_always(mCache->writeToFastCache(idx, mRawImage, mRawDiscardLevel)); + if(!mCache->writeToFastCache(idx, mRawImage, mRawDiscardLevel)) + { + LL_WARNS() << "writeToFastCache failed" << LL_ENDL; + mDataSize = -1; // failed + done = true; + } + } } } - } else { alreadyCached = mCache->updateEntry(idx, entry, mImageSize, mDataSize); // update the existing entry. } - if (idx < 0) - { - LL_WARNS() << "LLTextureCacheWorker: " << mID - << " Unable to create header entry for writing!" << LL_ENDL; - mDataSize = -1; // failed - done = true; - } - else + if (!done) { - if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)) + if (idx < 0) { - // Small texture already cached case: we're done with writing + LL_WARNS() << "LLTextureCacheWorker: " << mID + << " Unable to create header entry for writing!" << LL_ENDL; + mDataSize = -1; // failed done = true; } else { - // If the texture has already been cached, we don't resave the header and go directly to the body part - mState = alreadyCached ? BODY : HEADER; + if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)) + { + // Small texture already cached case: we're done with writing + done = true; + } + else + { + // If the texture has already been cached, we don't resave the header and go directly to the body part + mState = alreadyCached ? BODY : HEADER; + } } } } + // Third stage / state : write the header record in the header file (texture.cache) if (!done && (mState == HEADER)) { - llassert_always(idx >= 0); // we need an entry here or storing the header makes no sense - S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file - S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header - S32 bytes_written; - - if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE) + if (idx < 0) // we need an entry here or storing the header makes no sense { - // We need to write a full record in the header cache so, if the amount of data is smaller - // than a record, we need to transfer the data to a buffer padded with 0 and write that - U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE); - memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros - memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer - bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); - FREE_MEM(LLImageBase::getPrivatePool(), padBuffer); + LL_WARNS() << "index check failed" << LL_ENDL; + mDataSize = -1; // failed + done = true; } else { - // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file - bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool()); - } + S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE; // skip to the correct spot in the header file + S32 size = TEXTURE_CACHE_ENTRY_SIZE; // record size is fixed for the header + S32 bytes_written; - if (bytes_written <= 0) - { - LL_WARNS() << "LLTextureCacheWorker: " << mID + if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE) + { + // We need to write a full record in the header cache so, if the amount of data is smaller + // than a record, we need to transfer the data to a buffer padded with 0 and write that + U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE); + memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros + memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer + bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool()); + FREE_MEM(LLImageBase::getPrivatePool(), padBuffer); + } + else + { + // Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file + bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool()); + } + + if (bytes_written <= 0) + { + LL_WARNS() << "LLTextureCacheWorker: " << mID << " Unable to write header entry!" << LL_ENDL; - mDataSize = -1; // failed - done = true; - } + mDataSize = -1; // failed + done = true; + } - // If we wrote everything (may be more with padding) in the header cache, - // we're done so we don't have a body to store - if (mDataSize <= bytes_written) - { - done = true; - } - else - { - mState = BODY; + // If we wrote everything (may be more with padding) in the header cache, + // we're done so we don't have a body to store + if (mDataSize <= bytes_written) + { + done = true; + } + else + { + mState = BODY; + } } } // Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name if (!done && (mState == BODY)) { - llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise... - S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE; - + if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE) // wouldn't make sense to be here otherwise... { - // build the cache file name from the UUID - std::string filename = mCache->getTextureFileName(mID); -// LL_INFOS() << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << LL_ENDL; - S32 bytes_written = LLAPRFile::writeEx( filename, - mWriteData + TEXTURE_CACHE_ENTRY_SIZE, - 0, file_size, - mCache->getLocalAPRFilePool()); - if (bytes_written <= 0) + LL_WARNS() << "mDataSize check failed" << LL_ENDL; + mDataSize = -1; // failed + done = true; + } + else + { + S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE; + { - LL_WARNS() << "LLTextureCacheWorker: " << mID + // build the cache file name from the UUID + std::string filename = mCache->getTextureFileName(mID); + // LL_INFOS() << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << LL_ENDL; + S32 bytes_written = LLAPRFile::writeEx(filename, + mWriteData + TEXTURE_CACHE_ENTRY_SIZE, + 0, file_size, + mCache->getLocalAPRFilePool()); + if (bytes_written <= 0) + { + LL_WARNS() << "LLTextureCacheWorker: " << mID << " incorrect number of bytes written to body: " << bytes_written << " / " << file_size << LL_ENDL; - mDataSize = -1; // failed - done = true; + mDataSize = -1; // failed + done = true; + } } + + // Nothing else to do at that point... + done = true; } - - // Nothing else to do at that point... - done = true; } mRawImage = NULL; -- cgit v1.2.3