From 219a0f40ff120f1e4beb4b51ab48edb4106e3d2a Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 20 Apr 2019 12:10:07 -0400 Subject: [PATCH] Prevent infinite save loop when location is unavailable (#3026) This bug impacted unsafe saves. When auto save after every change was enabled, an unsafe save to a location that has become unavailable (eg, dismounted veracrypt drive), the database modified signal would continually activate a save action that failed. This caused an infinite loop. When auto-save on exit was enabled, the database tab and the application itself refused to close if saving failed for whatever reason. The fixes in this commit prevent both of these scenarios from occurring. --- src/gui/DatabaseWidget.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 8cfc4081..e4f175bf 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -1158,9 +1158,10 @@ void DatabaseWidget::onDatabaseModified() { if (!m_blockAutoSave && config()->get("AutoSaveAfterEveryChange").toBool()) { save(); + } else { + // Only block once, then reset + m_blockAutoSave = false; } - - m_blockAutoSave = false; } QString DatabaseWidget::getCurrentSearch() @@ -1258,11 +1259,13 @@ bool DatabaseWidget::lock() } if (m_db->isModified()) { + bool saved = false; + // Attempt to save on exit, but don't block locking if it fails if (config()->get("AutoSaveOnExit").toBool()) { - if (!save()) { - return false; - } - } else { + saved = save(); + } + + if (!saved) { QString msg; if (!m_db->metadata()->name().toHtmlEscaped().isEmpty()) { msg = tr("\"%1\" was modified.\nSave changes?").arg(m_db->metadata()->name().toHtmlEscaped()); @@ -1521,11 +1524,14 @@ bool DatabaseWidget::save() return true; } + // Read-only and new databases ask for filename if (m_db->isReadOnly() || m_db->filePath().isEmpty()) { return saveAs(); } + // Prevent recursions and infinite save loops blockAutoReload(true); + m_blockAutoSave = true; ++m_saveAttempts; // TODO: Make this async, but lock out the database widget to prevent re-entrance @@ -1536,6 +1542,7 @@ bool DatabaseWidget::save() if (ok) { m_saveAttempts = 0; + m_blockAutoSave = false; return true; }