From 05967311defaa72896303bbf7dabf3f2692f8c7b Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 9 Jan 2018 05:09:24 -0500 Subject: [PATCH] [partition] Be defensive against no device-device-available. Scenario is this: you have no suitable installation devices on your system (everything is mounted, or HDD has died), click through to partition page, where you have all the buttons available, but no devices in the list. The following actions then cause a crash: - clicking "back" - clicking any button Prevent that: - you can click "back", but if there is no device selected nothing happens to the device state (no nullptr deref, and no crash) - button code is now more resilient to this scenario - buttons are hidden until a device is available, so you can't even click on them to trigger the code. --- src/modules/partition/gui/ChoicePage.cpp | 35 +++++++++++++++++++----- src/modules/partition/gui/ChoicePage.h | 8 ++++-- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index 77b807a2b..008a64d8d 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -300,6 +300,16 @@ ChoicePage::selectedDevice() } +void +ChoicePage::hideButtons() +{ + m_eraseButton->hide(); + m_replaceButton->hide(); + m_alongsideButton->hide(); + m_somethingElseButton->hide(); +} + + /** * @brief ChoicePage::applyDeviceChoice handler for the selected event of the device * picker. Calls ChoicePage::selectedDevice() to get the current Device*, then @@ -311,7 +321,10 @@ void ChoicePage::applyDeviceChoice() { if ( !selectedDevice() ) + { + hideButtons(); return; + } if ( m_core->isDirty() ) { @@ -342,11 +355,14 @@ ChoicePage::continueApplyDeviceChoice() // applyDeviceChoice() will be called again momentarily as soon as we handle the // PartitionCoreModule::reverted signal. if ( !currd ) + { + hideButtons(); return; + } updateDeviceStatePreview(); - // Preview setup done. Now we show/hide choices as needed. + // Preview setup done. Now we show/hide choices as needed. setupActions(); m_lastSelectedDeviceIndex = m_drivesCombo->currentIndex(); @@ -562,7 +578,11 @@ ChoicePage::onLeave() { if ( m_bootloaderComboBox.isNull() ) { - m_core->setBootLoaderInstallPath( selectedDevice()->deviceNode() ); + auto d_p = selectedDevice(); + if ( d_p ) + m_core->setBootLoaderInstallPath( d_p->deviceNode() ); + else + cDebug() << "WARNING: No device selected for bootloader."; } else { @@ -1156,6 +1176,9 @@ ChoicePage::setupActions() else m_deviceInfoWidget->setPartitionTableType( PartitionTable::unknownTableType ); + // Manual partitioning is always a possibility + m_somethingElseButton->show(); + bool atLeastOneCanBeResized = false; bool atLeastOneCanBeReplaced = false; bool atLeastOneIsMounted = false; // Suppress 'erase' if so @@ -1332,18 +1355,16 @@ ChoicePage::updateNextEnabled() { bool enabled = false; + auto sm_p = m_beforePartitionBarsView ? m_beforePartitionBarsView->selectionModel() : nullptr; + switch ( m_choice ) { case NoChoice: enabled = false; break; case Replace: - enabled = m_beforePartitionBarsView->selectionModel()-> - currentIndex().isValid(); - break; case Alongside: - enabled = m_beforePartitionBarsView->selectionModel()-> - currentIndex().isValid(); + enabled = sm_p && sm_p->currentIndex().isValid(); break; case Erase: case Manual: diff --git a/src/modules/partition/gui/ChoicePage.h b/src/modules/partition/gui/ChoicePage.h index 8d600978e..91274d152 100644 --- a/src/modules/partition/gui/ChoicePage.h +++ b/src/modules/partition/gui/ChoicePage.h @@ -113,8 +113,12 @@ private: void setupChoices(); QComboBox* createBootloaderComboBox( QWidget* parentButton ); Device* selectedDevice(); - void applyDeviceChoice(); - void continueApplyDeviceChoice(); + + /* Change the UI depending on the device selected. */ + void hideButtons(); // Hide everything when no device + void applyDeviceChoice(); // Start scanning new device + void continueApplyDeviceChoice(); // .. called after scan + void updateDeviceStatePreview(); void updateActionChoicePreview( ChoicePage::Choice choice ); void setupActions();