Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug where pressing home on empty tag field crashes the program. #11346

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/gui/tag/TagsEdit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ struct TagsEdit::Impl
assert(i < tags.size());
auto occurrencesOfCurrentText =
std::count_if(tags.cbegin(), tags.cend(), [this](const auto& tag) { return tag.text == currentText(); });
if (currentText().isEmpty() || occurrencesOfCurrentText > 1) {
if ((currentText().isEmpty() && tags.size() > 1) || occurrencesOfCurrentText > 1) {
tags.erase(std::next(tags.begin(), std::ptrdiff_t(editing_index)));
Copy link
Member

@droidmonkey droidmonkey Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yikes this line is ugly as sin. The line below this is what actually causes the crash because it decrements the editing index to -1. We also need to put guards in place in the currentText functions that blindly take the editing_index without any bounds checks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change fixes the specific problem. The tags list will have at least size of 1, such that even after running the function, editing_index will be >=0 and the invariant hold.

Adding guards is probably a good idea, but I'd suggest to do some refactoring instead: What would be a good fallback for currentText() if editing_index is OoB? Crash gracefully? currentRect and currentText may return a reference.

Copy link
Member

@droidmonkey droidmonkey Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currentText should return an empty string and currentRect a zero sized rect. At the end of the day the variables in this class are not safe and the class needs to be refactored to make it safer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the current design of the class, I'd consider handling out-of-bounds as follows:
If tags is not empty, set editing_index to 0, then return tags[editing_index].
If tags is empty, add an empty tag, set editing_index to 0 and return.

Alternatively, we could introduce set/get currentText()/currentRect() member functions to avoid the reference problem (currentText() and currentRect() return references that are actually written to https://github.com/libklein/keepassxc/blob/develop/src/gui/tag/TagsEdit.cpp#L399. This would be my preferred option.

Copy link
Member

@droidmonkey droidmonkey Oct 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just nuts, we should never be returning a reference to a QString. QString is optimized in the backend. If you are inside the class you don't/shouldn't generally use setter/getter functions. Those are meant for external users of the class.

if (editing_index <= i) { // Do we shift positions after `i`?
--i;
Expand Down