gl: Try the local CacheLocation when the shared one fails

We prefer the shared cache path, because there is no reason to give up
benefitting from sharing the content between applications. If that path
is not QFileInfo().isWritable(), we fall back to the local cache path.

However, there are reportedly systems with security solutions such as
AppArmor where the writable check passes and yet attempting to create a
file still fails. Then there is no cache in effect, because nothing ever
gets written out.

Handle this better: if writing the file fails and we still use our first
choice, the global cache location, fall back to the secondary choice
(the app-local path) and try again.

Pick-to: 6.2 6.1 5.15
Fixes: QTBUG-96789
Change-Id: Ifea32e9af0cf85aa70f3069256ed3d6a7e2fbe90
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Dalton Durst <dalton@ubports.com>
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2021-09-28 12:52:15 +02:00
parent cef788f398
commit 46e6a9a759
2 changed files with 45 additions and 20 deletions

View File

@ -119,20 +119,24 @@ QOpenGLProgramBinaryCache::QOpenGLProgramBinaryCache()
{
const QString subPath = QLatin1String("/qtshadercache-") + QSysInfo::buildAbi() + QLatin1Char('/');
const QString sharedCachePath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation);
m_globalCacheDir = sharedCachePath + subPath;
m_localCacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
if (!sharedCachePath.isEmpty()) {
m_cacheDir = sharedCachePath + subPath;
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
m_currentCacheDir = m_globalCacheDir;
m_cacheWritable = qt_ensureWritableDir(m_currentCacheDir);
}
if (!m_cacheWritable) {
m_cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + subPath;
m_cacheWritable = qt_ensureWritableDir(m_cacheDir);
m_currentCacheDir = m_localCacheDir;
m_cacheWritable = qt_ensureWritableDir(m_currentCacheDir);
}
qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_cacheDir), m_cacheWritable);
qCDebug(lcOpenGLProgramDiskCache, "Cache location '%s' writable = %d", qPrintable(m_currentCacheDir), m_cacheWritable);
}
QString QOpenGLProgramBinaryCache::cacheFileName(const QByteArray &cacheKey) const
{
return m_cacheDir + QString::fromUtf8(cacheKey);
return m_currentCacheDir + QString::fromUtf8(cacheKey);
}
#define BASE_HEADER_SIZE (int(4 * sizeof(quint32)))
@ -361,6 +365,25 @@ static inline void writeStr(uchar **p, const QByteArray &str)
*p += str.size();
}
static inline bool writeFile(const QString &filename, const QByteArray &data)
{
#if QT_CONFIG(temporaryfile)
QSaveFile f(filename);
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
f.write(data);
if (f.commit())
return true;
}
#else
QFile f(filename);
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.write(data) == data.length())
return true;
}
#endif
return false;
}
void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
{
if (!m_cacheWritable)
@ -427,20 +450,20 @@ void QOpenGLProgramBinaryCache::save(const QByteArray &cacheKey, uint programId)
writeUInt(&blobFormatPtr, blobFormat);
#if QT_CONFIG(temporaryfile)
QSaveFile f(cacheFileName(cacheKey));
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
f.write(blob);
if (!f.commit())
#else
QFile f(cacheFileName(cacheKey));
if (f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
if (f.write(blob) < blob.length())
#endif
qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(f.fileName()));
} else {
qCDebug(lcOpenGLProgramDiskCache, "Failed to create %s in shader cache", qPrintable(f.fileName()));
QString filename = cacheFileName(cacheKey);
bool ok = writeFile(filename, blob);
if (!ok && m_currentCacheDir == m_globalCacheDir) {
m_currentCacheDir = m_localCacheDir;
m_cacheWritable = qt_ensureWritableDir(m_currentCacheDir);
qCDebug(lcOpenGLProgramDiskCache, "Cache location changed to '%s' writable = %d",
qPrintable(m_currentCacheDir), m_cacheWritable);
if (m_cacheWritable) {
filename = cacheFileName(cacheKey);
ok = writeFile(filename, blob);
}
}
if (!ok)
qCDebug(lcOpenGLProgramDiskCache, "Failed to write %s to shader cache", qPrintable(filename));
}
#if QT_CONFIG(opengles2)

View File

@ -92,7 +92,9 @@ private:
bool verifyHeader(const QByteArray &buf) const;
bool setProgramBinary(uint programId, uint blobFormat, const void *p, uint blobSize);
QString m_cacheDir;
QString m_globalCacheDir;
QString m_localCacheDir;
QString m_currentCacheDir;
bool m_cacheWritable;
struct MemCacheEntry {
MemCacheEntry(const void *p, int size, uint format)