Prevent nested SQL error handlers.

This commit is contained in:
Greyson Parrelli
2023-11-30 16:25:47 -05:00
committed by Cody Henthorne
parent 1355a4a28d
commit 74619f6f8d

View File

@@ -11,6 +11,7 @@ import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider import org.thoughtcrime.securesms.crypto.DatabaseSecretProvider
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
/** /**
@@ -18,39 +19,53 @@ import java.util.concurrent.atomic.AtomicReference
*/ */
@Suppress("ClassName") @Suppress("ClassName")
class SqlCipherErrorHandler(private val databaseName: String) : DatabaseErrorHandler { class SqlCipherErrorHandler(private val databaseName: String) : DatabaseErrorHandler {
companion object {
private val TAG = Log.tag(SqlCipherErrorHandler::class.java)
private val errorHandlingInProgress = AtomicBoolean(false)
}
override fun onCorruption(db: SQLiteDatabase, message: String) { override fun onCorruption(db: SQLiteDatabase, message: String) {
val result: DiagnosticResults = runDiagnostics(ApplicationDependencies.getApplication(), db) if (errorHandlingInProgress.getAndSet(true)) {
var lines: List<String> = result.logs.split("\n") Log.w(TAG, "Error handling already in progress, skipping.")
lines = listOf("Database '$databaseName' corrupted!", "[sqlite] $message", "Diagnostics results:") + lines return
}
Log.e(TAG, "Database '$databaseName' corrupted!") try {
Log.e(TAG, "[sqlite] $message") val result: DiagnosticResults = runDiagnostics(ApplicationDependencies.getApplication(), db)
Log.e(TAG, "Diagnostic results:\n ${result.logs}") var lines: List<String> = result.logs.split("\n")
lines = listOf("Database '$databaseName' corrupted!", "[sqlite] $message", "Diagnostics results:") + lines
if (result is DiagnosticResults.Success) { Log.e(TAG, "Database '$databaseName' corrupted!")
if (result.pragma1Passes && result.pragma2Passes) { Log.e(TAG, "[sqlite] $message")
var endCount = 0 Log.e(TAG, "Diagnostic results:\n ${result.logs}")
while (db.inTransaction() && endCount < 10) {
db.endTransaction() if (result is DiagnosticResults.Success) {
endCount++ if (result.pragma1Passes && result.pragma2Passes) {
var endCount = 0
while (db.inTransaction() && endCount < 10) {
db.endTransaction()
endCount++
}
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_BothChecksPass(lines)
} else if (!result.pragma1Passes && result.pragma2Passes) {
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_NormalCheckFailsCipherCheckPasses(lines)
} else if (result.pragma1Passes && !result.pragma2Passes) {
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_NormalCheckPassesCipherCheckFails(lines)
} else {
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_BothChecksFail(lines)
} }
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_BothChecksPass(lines)
} else if (!result.pragma1Passes && result.pragma2Passes) {
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_NormalCheckFailsCipherCheckPasses(lines)
} else if (result.pragma1Passes && !result.pragma2Passes) {
attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_NormalCheckPassesCipherCheckFails(lines)
} else { } else {
attemptToClearFullTextSearchIndex(db) attemptToClearFullTextSearchIndex(db)
throw DatabaseCorruptedError_BothChecksFail(lines) throw DatabaseCorruptedError_FailedToRunChecks(lines)
} }
} else { } finally {
attemptToClearFullTextSearchIndex(db) errorHandlingInProgress.set(false)
throw DatabaseCorruptedError_FailedToRunChecks(lines)
} }
} }
@@ -184,8 +199,4 @@ class SqlCipherErrorHandler(private val databaseName: String) : DatabaseErrorHan
private class DatabaseCorruptedError_NormalCheckFailsCipherCheckPasses constructor(lines: List<String>) : CustomTraceError(lines) private class DatabaseCorruptedError_NormalCheckFailsCipherCheckPasses constructor(lines: List<String>) : CustomTraceError(lines)
private class DatabaseCorruptedError_NormalCheckPassesCipherCheckFails constructor(lines: List<String>) : CustomTraceError(lines) private class DatabaseCorruptedError_NormalCheckPassesCipherCheckFails constructor(lines: List<String>) : CustomTraceError(lines)
private class DatabaseCorruptedError_FailedToRunChecks constructor(lines: List<String>) : CustomTraceError(lines) private class DatabaseCorruptedError_FailedToRunChecks constructor(lines: List<String>) : CustomTraceError(lines)
companion object {
private val TAG = Log.tag(SqlCipherErrorHandler::class.java)
}
} }