Skip to content

Instantly share code, notes, and snippets.

@dpogue
Last active September 25, 2020 06:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dpogue/53d529310355697a0bfdf17644a17840 to your computer and use it in GitHub Desktop.
Save dpogue/53d529310355697a0bfdf17644a17840 to your computer and use it in GitHub Desktop.

This is an explanation of the root cause for WebKit bug 216962.

Okay, so WebKit wants to move from per-ObjectStore Index IDs to global Index IDs.

Our current indices table (in iOS 13) looks like this:

id name objectStoreID
1 uuid 1
2 date 1
1 uuid 2
2 time 2
3 object_uuid 2
4 created_at 2
1 uuid 3
2 name 3
1 uuid 4
2 sort_order 4

This code loops over all the existing indices and picks global IDs for them: https://github.com/WebKit/webkit/blob/37a90a973bb2dbfe5f55e8df2db2ac5a06423a87/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp#L822-L828

So, in our case, that map looks something like this:

{ 1, 1 } = 1
{ 1, 2 } = 2
{ 2, 1 } = 3
{ 2, 2 } = 4
{ 2, 3 } = 5
{ 2, 4 } = 6
{ 3, 1 } = 7
{ 3, 2 } = 8
{ 4, 1 } = 9
{ 4, 2 } = 10

Now, we loop over each entry in that map and run the following:

UPDATE IndexInfo SET id = {map.value} WHERE id = {map.key[0]} AND objectStoreID = {map.key[1]};

Let's walk through this...

First Loop

Basically no change.

UPDATE IndexInfo SET id = 1 WHERE id = 1 AND objectStoreID = 1;
  id name objectStoreID
 🟊 1 uuid 1
  2 date 1
  1 uuid 2
  2 time 2
  3 object_uuid 2
  4 created_at 2
  1 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

Second Loop

Also basically no change.

UPDATE IndexInfo SET id = 2 WHERE id = 2 AND objectStoreID = 1;
  id name objectStoreID
  1 uuid 1
 🟊 2 date 1
  1 uuid 2
  2 time 2
  3 object_uuid 2
  4 created_at 2
  1 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

Third Loop

This is where things start changing...

UPDATE IndexInfo SET id = 3 WHERE id = 1 AND objectStoreID = 2;
  id name objectStoreID
  1 uuid 1
  2 date 1
 🟊 3 uuid 2
  2 time 2
  3 object_uuid 2
  4 created_at 2
  1 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

Fourth Loop

Things are still working as expected here...

UPDATE IndexInfo SET id = 4 WHERE id = 2 AND objectStoreID = 2;
  id name objectStoreID
  1 uuid 1
  2 date 1
  3 uuid 2
 🟊 4 time 2
  3 object_uuid 2
  4 created_at 2
  1 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

Fifth Loop

This is where we run into our first bit of index corruption

UPDATE IndexInfo SET id = 5 WHERE id = 3 AND objectStoreID = 2;
  id name objectStoreID
  1 uuid 1
  2 date 1
 🟊 5 uuid 2
  4 time 2
 🟊 5 object_uuid 2
  4 created_at 2
  1 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

Sixth Loop

This is where the second index gets corrupted

UPDATE IndexInfo SET id = 6 WHERE id = 4 AND objectStoreID = 2;
  id name objectStoreID
  1 uuid 1
  2 date 1
  5 uuid 2
 🟊 6 time 2
  5 object_uuid 2
 🟊 6 created_at 2
  1 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

Seventh Loop

Now it continues on normally

UPDATE IndexInfo SET id = 7 WHERE id = 1 AND objectStoreID = 3;
  id name objectStoreID
  1 uuid 1
  2 date 1
  5 uuid 2
  6 time 2
  5 object_uuid 2
  6 created_at 2
 🟊 7 uuid 3
  2 name 3
  1 uuid 4
  2 sort_order 4

End Result

We have corrupted the index IDs and now our objectStore is broken.

  id name objectStoreID
  1 uuid 1
  2 date 1
 🡂 5 uuid 2
 🡂 6 time 2
  5 object_uuid 2
  6 created_at 2
  7 uuid 3
  8 name 3
  9 uuid 4
  10 sort_order 4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment