fix crash in kpixmapcache (#568389)

This commit is contained in:
Lukas Tinkl 2010-03-17 12:19:41 +00:00
parent 8bbb54cbab
commit cb3b87b5e1
2 changed files with 173 additions and 0 deletions

View File

@ -0,0 +1,167 @@
--- kdelibs/kdeui/util/kpixmapcache.cpp 2010/03/17 02:34:11 1104230
+++ kdelibs/kdeui/util/kpixmapcache.cpp 2010/03/17 02:38:08 1104231
@@ -40,6 +40,7 @@
#include <kstandarddirs.h>
#include <kdebug.h>
#include <klockfile.h>
+#include <ksavefile.h>
#include <ksvgrenderer.h>
#include <kdefakes.h>
@@ -633,6 +634,10 @@
qint32 leftchild, rightchild;
stream >> fkey >> foffset >> timesused >> lastused >> leftchild >> rightchild;
+ if (fkey.isEmpty()) {
+ return start;
+ }
+
if (key < fkey) {
if (leftchild) {
return binarySearchKey(stream, key, leftchild);
@@ -660,12 +665,21 @@
// exist yet and there are no entries. Otherwise, do a binary search
// starting from the root node.
if (!stream.atEnd()) {
+ // One exception is that the root node may exist but be invalid,
+ // which can happen when the cache data is discarded. This is
+ // represented by an empty fkey
+ QString fkey;
+ stream >> fkey;
+
+ if (fkey.isEmpty()) {
+ delete device;
+ return -1;
+ }
+
int nodeoffset = binarySearchKey(stream, key, mIndexRootOffset);
// Load the found entry and check if it's the one we're looking for.
device->seek(nodeoffset);
- QString fkey;
- stream >> fkey;
if (fkey == key) {
// Read offset and statistics
qint32 foffset;
@@ -814,7 +828,9 @@
QString fkey;
stream.device()->seek(parentoffset);
stream >> fkey;
- if (key == fkey) {
+
+ // The key would be empty if the cache had been discarded.
+ if (key == fkey || fkey.isEmpty()) {
// We're overwriting an existing entry
offset = parentoffset;
}
@@ -1195,16 +1211,14 @@
return false;
}
- d->invalidateMmapFiles();
- d->unmmapFiles();
-
- d->mEnabled = false;
-
KPCLockFile lock(d->mLockFileName);
// Hope we got the lock...
+ d->invalidateMmapFiles();
+ d->mEnabled = false;
+
// Create index file
- QFile indexfile(d->mIndexFile);
+ KSaveFile indexfile(d->mIndexFile);
if (!indexfile.open(QIODevice::WriteOnly)) {
kError() << "Couldn't create index file" << d->mIndexFile;
return false;
@@ -1212,7 +1226,7 @@
d->mCacheId = ::time(0);
d->mTimestamp = ::time(0);
-
+
// We can't know the full size until custom headers written.
// mmapFiles() will take care of correcting the size.
KPixmapCacheIndexHeader indexHeader = { {0}, KPIXMAPCACHE_VERSION, 0, d->mCacheId, d->mTimestamp };
@@ -1221,7 +1235,7 @@
indexfile.write(reinterpret_cast<char*>(&indexHeader), sizeof indexHeader);
// Create data file
- QFile datafile(d->mDataFile);
+ KSaveFile datafile(d->mDataFile);
if (!datafile.open(QIODevice::WriteOnly)) {
kError() << "Couldn't create data file" << d->mDataFile;
return false;
@@ -1243,40 +1257,54 @@
// Close the files and mmap them (if mmapping is used)
indexfile.close();
datafile.close();
+ indexfile.finalize();
+ datafile.finalize();
+
d->mEnabled = true;
d->mmapFiles();
+
return true;
}
void KPixmapCache::deleteCache(const QString& name)
{
- foreach (KPixmapCache::Private *d, Private::mCaches) {
- if (d->mName == name && d->mInited) {
- d->q->discard();
- }
- }
+ QString indexFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + name + ".index");
+ QString dataFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + name + ".data");
+
+ QFile::remove(indexFile);
+ QFile::remove(dataFile);
}
void KPixmapCache::discard()
{
- d->invalidateMmapFiles();
- d->unmmapFiles();
- d->mInited = false;
+ // To "discard" the cache we simply have to make sure that every that
+ // was in there before is no longer present when we search for them.
+ // Easiest way to do *that* is to simply delete the index.
+
+ KPCLockFile lock(d->mLockFileName);
+ if(!lock.isValid()) {
+ kError(264) << "Unable to lock pixmap cache when trying to discard it";
+ return;
+ }
+
+ QIODevice *device = d->indexDevice();
+ if (!device) {
+ kError(264) << "Unable to access index when trying to discard cache";
+ return;
+ }
+
+ device->seek(d->mIndexRootOffset);
+ QDataStream stream(device);
+
+ // Stream an empty QString as the hash key to signify that the cache
+ // has been discarded.
+ stream << QString();
if (d->mUseQPixmapCache) {
// TODO: This is broken, it removes every cached QPixmap in the whole
// process, not just this KPixmapCache.
QPixmapCache::clear();
}
-
- QString indexFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + d->mName + ".index");
- QString dataFile = KGlobal::dirs()->locateLocal("cache", "kpc/" + d->mName + ".data");
-
- QFile::remove(indexFile);
- QFile::remove(dataFile);
-
- // No need to remove the lockfile
- d->init();
}
void KPixmapCache::removeEntries(int newsize)

View File

@ -83,6 +83,8 @@ Patch24: kdelibs-4.3.1-drkonq.patch
# paths (like /usr/lib64) already! With this, we can drop
# -DCMAKE_SKIP_RPATH:BOOL=ON (finally)
Patch27: kdelibs-4.3.98-no_rpath.patch
# bug:568389 (crash in kpixmapcache)
Patch28: kdelibs-4.4.2-kpixmapcache.patch
# upstreamable
@ -231,6 +233,7 @@ format for easy browsing.
%patch24 -p1 -b .drkonq
%endif
%patch27 -p1 -b .no_rpath
%patch28 -p1 -b .kpixmapcache
# upstreamable patches
@ -426,6 +429,9 @@ rm -rf %{buildroot}
%changelog
* Wed Mar 17 2010 Lukas Tinkl <ltinkl@redhat.com> - 6:4.4.1-6
- fix crash in KPixmapCache (bug#568389)
* Tue Mar 09 2010 Rex Dieter <rdieter@fedoraproject.org> - 6:4.4.1-5
- rebuild (soprano)