0

We are using SQLite (actually SQLCipher) on Android 4.4.2 (Nexus 7 tablets) within an obfuscated (Dexguard) Android application. We have ContentProviders to access the SQLite/SQLCipher database. One of these ContentProviders returns messages from a queue table. This queue gets regularly processed - we retrieve the messages from the queue and then iterate over them using cursor.moveToNext():

// Get cursor to iterate unsent messages
Cursor cursor = queueHelper.getMessages(Queue.STATUS_NEW);

try {
    // Check if there are any unsent messages
    if (cursor == null || cursor.getCount() == 0) {
        // No queued messages to send
        return;
    }

    // Send messages
    while (cursor.moveToNext()) {

        // Do stuff
    }
}

This worked reliably during our own development and testing, however in the field we're seeing occasional but repeated issues where, after successfully processing a queued message, the cursor.moveToNext() call above is throwing an IllegalStateException (note, always row 0 col 0):

java.lang.IllegalStateException: get field slot from row 0 col 0 failed
    at net.sqlcipher.CursorWindow.getLong_native(Native Method)
    at net.sqlcipher.CursorWindow.getLong(:446)
    at net.sqlcipher.AbstractWindowedCursor.getLong(:110)
    at net.sqlcipher.AbstractCursor.moveToPosition(:199)
    at net.sqlcipher.AbstractCursor.moveToNext(:228)
    at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
    at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)

On other occasions this line is instead throwing a CursorIndexOutOfBoundsException (note actual index/size reported changes each time):

net.sqlcipher.CursorIndexOutOfBoundsException: Index 98 requested, with a size of 98
    at net.sqlcipher.AbstractCursor.?(:556)
    at net.sqlcipher.AbstractWindowedCursor.?(:222)
    at net.sqlcipher.AbstractWindowedCursor.getLong(:101)
    at net.sqlcipher.AbstractCursor.moveToPosition(:199)
    at net.sqlcipher.AbstractCursor.moveToNext(:228)
    at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)
    at android.database.CursorWrapper.moveToNext(CursorWrapper.java:166)

We haven't been able to reproduce either problem and only have log files to go on. These logs indicate that the problem occurs after successfully processing a row. After this exception, the process is restarted and carries on without issue. We cannot understand why moveToNext could throw either exception - e.g. if it worked on rows 1-10, why would moving to row 11 throw an exception? Documentation for Cursor.moveToNext says:

Move the cursor to the next row. 

This method will return false if the cursor is already past the last entry in the result set.

Therefore it should successfully move to next (and return true) or fail (and return false), not throw these odd exceptions.

Does this sound like an issue within our code or could it be a SQLite issue, a SQLCipher issue, or related to our obfuscation process, either with Dexguard, or how we use it? Any advice?

Swampie
  • 165
  • 1
  • 1
  • 9
  • Do you run this inside a transaction? And do you maybe delete entries, while you iterate over the cursor? – tknell Jun 20 '14 at 15:25
  • This isn't being run inside a transaction. We don't delete any entries from the queue, only add new entries and change status/update columns of existing entries whilst iterating over the cursor above. – Swampie Jun 21 '14 at 15:00
  • If you are able to provide a reproducible test case scenario, we would be glad to look into it further. The SQLCipher for Android test suite can be found [here](https://github.com/sqlcipher/sqlcipher-android-tests). You might also consider posting your findings to the SQLCipher [mailing list](https://groups.google.com/forum/#!forum/sqlcipher). Thanks! – Nick Parker Jun 23 '14 at 13:25

0 Answers0