From b05291ae6957268b6be5ddd73aea4d5197d17888 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 23 Feb 2026 17:56:10 +0100 Subject: [PATCH 1/2] Fix crash while loading hunks Reason: When calling QApplication::processEvents() all events are processed also user inputs which might lead to change the diff while we are reading the hunks which leads to a clear of the files where the fetchMore is currently working on it which is not correct and leads to undefined behaviour --- src/ui/DiffView/DiffView.cpp | 25 +++++++++++++++++++++++++ src/ui/DiffView/DiffView.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/src/ui/DiffView/DiffView.cpp b/src/ui/DiffView/DiffView.cpp index 089a11f7a..338d9223e 100644 --- a/src/ui/DiffView/DiffView.cpp +++ b/src/ui/DiffView/DiffView.cpp @@ -374,12 +374,34 @@ bool DiffView::canFetchMore() { mFiles.size() < mDiffTreeModel->fileCount(dtw->selectedIndex()); } +class Guard { +public: + Guard(bool& variable, bool initValue): m_variable(variable), m_initValue(initValue) { + m_variable = m_initValue; + // qDebug() << "Guarding variable" << m_variable; + } + ~Guard() { + m_variable = !m_initValue; + // qDebug() << "Releasing variable" << m_variable; + } +private: + bool& m_variable; + bool m_initValue; +}; + /*! * \brief DiffView::fetchMore * Fetch maxNewFiles more patches * use a while loop with canFetchMore() to get all */ void DiffView::fetchMore(int fetchWidgets) { + if (mFetchMoreInProgress) { + mCancelFetchMore = true; + // We cannot wait here because then processEvents() from below will never return + return; + } + auto g = Guard(mFetchMoreInProgress, true); + QVBoxLayout *layout = static_cast(widget()->layout()); // Add widgets. @@ -403,6 +425,9 @@ void DiffView::fetchMore(int fetchWidgets) { // Load hunk(s) and update scrollbar QApplication::processEvents(); + if (mCancelFetchMore) { + return; + } // Running the eventloop may trigger a view refresh if (mFiles.isEmpty()) diff --git a/src/ui/DiffView/DiffView.h b/src/ui/DiffView/DiffView.h index e72a8b18a..ed9cc33d3 100644 --- a/src/ui/DiffView/DiffView.h +++ b/src/ui/DiffView/DiffView.h @@ -141,6 +141,9 @@ class DiffView : public QScrollArea, public EditorProvider { DiffTreeModel *mDiffTreeModel{nullptr}; QWidget *mParent{nullptr}; QVBoxLayout *mFileWidgetLayout{nullptr}; + + bool mFetchMoreInProgress{false}; + bool mCancelFetchMore{false}; }; #endif From ff1e8f65337eca5a412a8989260494d2e2eb26d1 Mon Sep 17 00:00:00 2001 From: Martin Marmsoler Date: Mon, 23 Feb 2026 22:08:42 +0100 Subject: [PATCH 2/2] Format --- src/ui/DiffView/DiffView.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ui/DiffView/DiffView.cpp b/src/ui/DiffView/DiffView.cpp index 338d9223e..c164b9980 100644 --- a/src/ui/DiffView/DiffView.cpp +++ b/src/ui/DiffView/DiffView.cpp @@ -376,7 +376,8 @@ bool DiffView::canFetchMore() { class Guard { public: - Guard(bool& variable, bool initValue): m_variable(variable), m_initValue(initValue) { + Guard(bool &variable, bool initValue) + : m_variable(variable), m_initValue(initValue) { m_variable = m_initValue; // qDebug() << "Guarding variable" << m_variable; } @@ -384,8 +385,9 @@ class Guard { m_variable = !m_initValue; // qDebug() << "Releasing variable" << m_variable; } + private: - bool& m_variable; + bool &m_variable; bool m_initValue; }; @@ -397,7 +399,8 @@ class Guard { void DiffView::fetchMore(int fetchWidgets) { if (mFetchMoreInProgress) { mCancelFetchMore = true; - // We cannot wait here because then processEvents() from below will never return + // We cannot wait here because then processEvents() from below will never + // return return; } auto g = Guard(mFetchMoreInProgress, true);