Changeset 165145 in webkit


Ignore:
Timestamp:
Mar 5, 2014 5:02:45 PM (10 years ago)
Author:
dbates@webkit.org
Message:

And Alexey Proskuryakov <ap@apple.com>

ASSERT(newestManifest) fails in WebCore::ApplicationCacheGroup::didFinishLoadingManifest()
https://bugs.webkit.org/show_bug.cgi?id=129753
<rdar://problem/12069835>

Reviewed by Alexey Proskuryakov.

Fixes an issue where an assertion failure would occur when visiting a web site whose on-disk
app cache doesn't contain a manifest resource.

For some reason an app cache for a web site may be partially written to disk. In particular, the
app cache may only contain a CacheGroups entry. That is, the manifest resource and origin records
may not be persisted to disk. From looking over the code, we're unclear how such a situation can occur
and hence have been unable to create such an app cache. We were able to reproduce this issue using
an app cache database file that was provided by a person that was affected by this issue.

No test included because it's not straightforward to write a test for this change.

  • loader/appcache/ApplicationCacheGroup.cpp:

(WebCore::ApplicationCacheGroup::checkIfLoadIsComplete): Assert that m_cacheBeingUpdated->manifestResource()
is non-null. Currently we only document this assumption in a code comment. Also separated a single assertion
expression into two assertion expressions to make it straightforward to identify the failing sub-expression
on failure.

  • loader/appcache/ApplicationCacheStorage.cpp:

(WebCore::ApplicationCacheStorage::store): Modified to call ApplicationCacheStorage::deleteCacheGroupRecord()
to remove a cache group and associated cache records (if applicable) before inserting a cache group entry.
This replacement approach will ultimately repair incomplete app cache data for people affected by this bug.
(WebCore::ApplicationCacheStorage::loadCache): Log an error and return nullptr if the cache we loaded doesn't
have a manifest resource.
(WebCore::ApplicationCacheStorage::deleteCacheGroupRecord): Added.
(WebCore::ApplicationCacheStorage::deleteCacheGroup): Extracted deletion logic for cache group record into
ApplicationCacheStorage::deleteCacheGroupRecord().

  • loader/appcache/ApplicationCacheStorage.h:
Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r165141 r165145  
     12014-03-05  Daniel Bates  <dabates@apple.com>
     2            And Alexey Proskuryakov  <ap@apple.com>
     3
     4        ASSERT(newestManifest) fails in WebCore::ApplicationCacheGroup::didFinishLoadingManifest()
     5        https://bugs.webkit.org/show_bug.cgi?id=129753
     6        <rdar://problem/12069835>
     7
     8        Reviewed by Alexey Proskuryakov.
     9
     10        Fixes an issue where an assertion failure would occur when visiting a web site whose on-disk
     11        app cache doesn't contain a manifest resource.
     12
     13        For some reason an app cache for a web site may be partially written to disk. In particular, the
     14        app cache may only contain a CacheGroups entry. That is, the manifest resource and origin records
     15        may not be persisted to disk. From looking over the code, we're unclear how such a situation can occur
     16        and hence have been unable to create such an app cache. We were able to reproduce this issue using
     17        an app cache database file that was provided by a person that was affected by this issue.
     18
     19        No test included because it's not straightforward to write a test for this change.
     20
     21        * loader/appcache/ApplicationCacheGroup.cpp:
     22        (WebCore::ApplicationCacheGroup::checkIfLoadIsComplete): Assert that m_cacheBeingUpdated->manifestResource()
     23        is non-null. Currently we only document this assumption in a code comment. Also separated a single assertion
     24        expression into two assertion expressions to make it straightforward to identify the failing sub-expression
     25        on failure.
     26        * loader/appcache/ApplicationCacheStorage.cpp:
     27        (WebCore::ApplicationCacheStorage::store): Modified to call ApplicationCacheStorage::deleteCacheGroupRecord()
     28        to remove a cache group and associated cache records (if applicable) before inserting a cache group entry.
     29        This replacement approach will ultimately repair incomplete app cache data for people affected by this bug.
     30        (WebCore::ApplicationCacheStorage::loadCache): Log an error and return nullptr if the cache we loaded doesn't
     31        have a manifest resource.
     32        (WebCore::ApplicationCacheStorage::deleteCacheGroupRecord): Added.
     33        (WebCore::ApplicationCacheStorage::deleteCacheGroup): Extracted deletion logic for cache group record into
     34        ApplicationCacheStorage::deleteCacheGroupRecord().
     35        * loader/appcache/ApplicationCacheStorage.h:
     36
    1372014-03-05  Oliver Hunt  <oliver@apple.com>
    238
  • trunk/Source/WebCore/loader/appcache/ApplicationCacheGroup.cpp

    r163914 r165145  
    903903            // the maximum size. In such a case, m_manifestResource may be 0, as
    904904            // the manifest was already set on the newest cache object.
    905             ASSERT(cacheStorage().isMaximumSizeReached() && m_calledReachedMaxAppCacheSize);
     905            ASSERT(m_cacheBeingUpdated->manifestResource());
     906            ASSERT(cacheStorage().isMaximumSizeReached());
     907            ASSERT(m_calledReachedMaxAppCacheSize);
    906908        }
    907909
  • trunk/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp

    r163089 r165145  
    695695    ASSERT(journal);
    696696
     697    // For some reason, an app cache may be partially written to disk. In particular, there may be
     698    // a cache group with an identical manifest URL and associated cache entries. We want to remove
     699    // this cache group and its associated cache entries so that we can create it again (below) as
     700    // a way to repair it.
     701    deleteCacheGroupRecord(group->manifestURL());
     702
    697703    SQLiteStatement statement(m_database, "INSERT INTO CacheGroups (manifestHostHash, manifestURL, origin) VALUES (?, ?, ?)");
    698704    if (statement.prepare() != SQLResultOk)
     
    11761182    if (result != SQLResultDone)
    11771183        LOG_ERROR("Could not load cache resources, error \"%s\"", m_database.lastErrorMsg());
    1178    
     1184
     1185    if (!cache->manifestResource()) {
     1186        LOG_ERROR("Could not load application cache because there was no manifest resource");
     1187        return nullptr;
     1188    }
     1189
    11791190    // Load the online whitelist
    11801191    SQLiteStatement whitelistStatement(m_database, "SELECT url FROM CacheWhitelistURLs WHERE cache=?");
     
    14151426
    14161427    *size = statement.getColumnInt64(0);
     1428    return true;
     1429}
     1430
     1431bool ApplicationCacheStorage::deleteCacheGroupRecord(const String& manifestURL)
     1432{
     1433    ASSERT(SQLiteDatabaseTracker::hasTransactionInProgress());
     1434    SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
     1435    if (idStatement.prepare() != SQLResultOk)
     1436        return false;
     1437
     1438    idStatement.bindText(1, manifestURL);
     1439
     1440    int result = idStatement.step();
     1441    if (result != SQLResultRow)
     1442        return false;
     1443
     1444    int64_t groupId = idStatement.getColumnInt64(0);
     1445
     1446    SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
     1447    if (cacheStatement.prepare() != SQLResultOk)
     1448        return false;
     1449
     1450    SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
     1451    if (groupStatement.prepare() != SQLResultOk)
     1452        return false;
     1453
     1454    cacheStatement.bindInt64(1, groupId);
     1455    executeStatement(cacheStatement);
     1456    groupStatement.bindInt64(1, groupId);
     1457    executeStatement(groupStatement);
    14171458    return true;
    14181459}
     
    14321473        if (!m_database.isOpen())
    14331474            return false;
    1434 
    1435         SQLiteStatement idStatement(m_database, "SELECT id FROM CacheGroups WHERE manifestURL=?");
    1436         if (idStatement.prepare() != SQLResultOk)
    1437             return false;
    1438 
    1439         idStatement.bindText(1, manifestURL);
    1440 
    1441         int result = idStatement.step();
    1442         if (result == SQLResultDone)
    1443             return false;
    1444 
    1445         if (result != SQLResultRow) {
    1446             LOG_ERROR("Could not load cache group id, error \"%s\"", m_database.lastErrorMsg());
     1475        if (!deleteCacheGroupRecord(manifestURL)) {
     1476            LOG_ERROR("Could not delete cache group record, error \"%s\"", m_database.lastErrorMsg());
    14471477            return false;
    14481478        }
    1449 
    1450         int64_t groupId = idStatement.getColumnInt64(0);
    1451 
    1452         SQLiteStatement cacheStatement(m_database, "DELETE FROM Caches WHERE cacheGroup=?");
    1453         if (cacheStatement.prepare() != SQLResultOk)
    1454             return false;
    1455 
    1456         SQLiteStatement groupStatement(m_database, "DELETE FROM CacheGroups WHERE id=?");
    1457         if (groupStatement.prepare() != SQLResultOk)
    1458             return false;
    1459 
    1460         cacheStatement.bindInt64(1, groupId);
    1461         executeStatement(cacheStatement);
    1462         groupStatement.bindInt64(1, groupId);
    1463         executeStatement(groupStatement);
    14641479    }
    14651480
  • trunk/Source/WebCore/loader/appcache/ApplicationCacheStorage.h

    r156550 r165145  
    111111    bool store(ApplicationCache*, ResourceStorageIDJournal*);
    112112    bool store(ApplicationCacheResource*, unsigned cacheStorageID);
     113    bool deleteCacheGroupRecord(const String& manifestURL);
    113114
    114115    bool ensureOriginRecord(const SecurityOrigin*);
Note: See TracChangeset for help on using the changeset viewer.