do not crash qaccessible by causing a resize in a resize event
ClosedPublic

Authored by sitter on Jul 11 2017, 10:53 AM.

Details

Summary

When enabling accessibility qaccessible will automatically add a11y support
constructs to core qt types such as qtableview.
Unfortunately for qtableview specifically a change of the layout/size will
discard the accessible objects modeling the individual cells in our table.
Combined with the way we control layout through the model [I am not sure
why we do this to begin with] this can result in call chains where
qaccessible triggers a resizeEvent which we'll handle by rejiggering
our model to get a new layout, resulting in qaccessible deleting the
object which originally caused the event and ending in a segfault.

To prevent this problem we delay the rejiggering of our model by running
the call through the eventloop (i.e. the resize is executed once the stack
unwinds again to the event loop).

CHANGELOG: Fixed a crash when searching with accessibility support enabled
BUG: 374933

Also see https://bugreports.qt.io/browse/QTBUG-58153

Test Plan

spent a good while searching and copy pasting and all that fun stuff. no more crashing.

Diff Detail

Repository
R236 KWidgetsAddons
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
sitter created this revision.Jul 11 2017, 10:53 AM
Restricted Application added a project: Frameworks. · View Herald TranscriptJul 11 2017, 10:53 AM
Restricted Application added a subscriber: Frameworks. · View Herald Transcript

FWIW, this is a bit of workaround. Not having kcharselect crash for just about every search is well worth it though.
Also, I am not sure I particularly like the qtimer code. It does beat having to pass const char * method names to invokeMethod and turning the private into a qobject. With the lambda the resize call at least gets checked by the compiler ¯\_(ツ)_/¯

anthonyfieroni added inline comments.
src/kcharselect.cpp
251

QSignalBlocker blockResize(this) ?

sitter added inline comments.Jul 11 2017, 11:25 AM
src/kcharselect.cpp
251

Block inhibits signal emission/slot calling. That is not what we want. We want the signals to run, just not on the same call chain as the resize event.

cfeck added a subscriber: cfeck.Jul 11 2017, 11:28 AM

Reading your description on the referenced QTBUG, does it help to use a compare with previous m_columns in KCharSelectItemModel ::setColumnCount() before doing the emit dance?

In D6624#124077, @cfeck wrote:

Reading your description on the referenced QTBUG, does it help to use a compare with previous m_columns in KCharSelectItemModel ::setColumnCount() before doing the emit dance?

It probably does. To me, that would seem a bit too close to the cause though. If tomorrow another bit of the resizing calculation starts causing a re-layout it would crash again. That said, I think adding an if would be handy either way, what with saving a bunch of cpu cycles.

gladhorn edited edge metadata.Jul 14 2017, 8:04 AM

Considering that the Qt bug will not be fixed in the next few days (I hope to get around to it, but it's involved), this makes sense.

cfeck added a comment.Jul 18 2017, 4:20 AM

It probably does.

Were you able to test? I would prefer the simpler patch. I cannot test it, because my system does not have accessibility enabled.

In D6624#126465, @cfeck wrote:

It probably does.

Were you able to test? I would prefer the simpler patch. I cannot test it, because my system does not have accessibility enabled.

Yes, I did not manage to crash it that way.

As I said though, I do not think making the smallest possible fix is prudent here. While that change would be simpler it would also be more fragile. In resizeEvent() we'd still call a function of which the intention is to change the size of cells, which is meant to result in a layout change and thus potentially causes a resize, bringing us back to the crashing call chain. Making the column update conditional does fix the immediate cause of this right now. Conceptually the issue would still be there: we call a method of which the intention is to change the layout from within a resizeEvent handler. Something that is not safe to do with the current qaccessible lifetime management.
If someone goes ahead and changes the way the models are being used and/or when size calculation happens in the future we'll be crashing again.

TLDR I don't find introducing the if a future-proof solution. It's only treating the symptom. We'd reinforce a bone with a metal plate whilst ignoring the fact that the patient has a disorder that makes her run in front of cars.

(I do think that introducing that if would be handy eitherway, not as a measure of dealing with the crash though)

cfeck added a comment.EditedJul 18 2017, 8:55 AM

If you are sure that your fix is "correct", then please remove the comment. From reading it, it looks like a workaround for a Qt bug.

cfeck added a comment.Jul 18 2017, 9:01 AM

Reading your comment it is also wrong. Resizing the model does not cause a resize of the widget. The widget size is controlled by the layout manager.

In D6624#126503, @cfeck wrote:

If you are sure that your fix is "correct", then please remove the comment. From reading it, it looks like a workaround for a Qt bug.

It is a workaround. It crashes because the life time of the qaccessible objects is managed rather badly and fixing that is less trivial than this workaround.

cfeck added a comment.Jul 18 2017, 9:08 AM

Let's say someone fixes the referenced Qt bug, and we are at a point requiring that Qt version anyway. Are you going to remove the workaround?

In D6624#126506, @cfeck wrote:

Let's say someone fixes the referenced Qt bug, and we are at a point requiring that Qt version anyway. Are you going to remove the workaround?

Anyone who happens to stumble upon it can.

cfeck accepted this revision.Jul 18 2017, 9:20 AM

Would be nice if you also commit the conditional in the KCharSelectItemModel ::setColumnCount.

This revision is now accepted and ready to land.Jul 18 2017, 9:20 AM