vcl/qt5/QtAccessibleWidget.cxx | 96 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 11 deletions(-)
New commits: commit 69ecff82d0e5a0592f9bf6aa4fee364ff1c9754c Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Wed Aug 10 08:47:07 2022 +0200 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Thu Aug 11 08:46:03 2022 +0200 qt a11y: Check range for offset passed to text methods Otherwise LO crashes when invalid offsets are passed from AT when using the qt5/qt6/kf5 VCL plugins. One scenario that resulted in a crash: * start Accerciser * start Calc * press F2 in cell A1 to enter edit mode * navigate to the "Cell A1" object representing the editable cell, then to its paragraph child in Accerciser's treeview of the LO a11y hierarchy * in Accerciser's "Interface Viewer", type Enter, then any character This would crash due to a `com::sun::star::lang::IndexOutOfBoundsException` being thrown by one of the methods of the XAccessibleText/XAccessibleEditableText interfaces. Change-Id: I1b8c6057ca1e4e4485d516418bb82cd1a6697ce1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138078 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx index a7d0457801e6..ac60b3746803 100644 --- a/vcl/qt5/QtAccessibleWidget.cxx +++ b/vcl/qt5/QtAccessibleWidget.cxx @@ -844,7 +844,10 @@ QString QtAccessibleWidget::attributes(int offset, int* startOffset, int* endOff offset = nTextLength - 1; if (offset < 0 || offset > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::attributes called with invalid offset: " << offset); return QString(); + } const Sequence<PropertyValue> attribs = xText->getCharacterAttributes(offset, Sequence<OUString>()); @@ -887,6 +890,7 @@ int QtAccessibleWidget::characterCount() const return xText->getCharacterCount(); return 0; } + QRect QtAccessibleWidget::characterRect(int nOffset) const { Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); @@ -931,11 +935,21 @@ void QtAccessibleWidget::removeSelection(int /* selectionIndex */) { SAL_INFO("vcl.qt", "Unsupported QAccessibleTextInterface::removeSelection"); } + void QtAccessibleWidget::scrollToSubstring(int startIndex, int endIndex) { Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE); + if (!xText.is()) + return; + + sal_Int32 nTextLength = xText->getCharacterCount(); + if (startIndex < 0 || startIndex > nTextLength || endIndex < 0 || endIndex > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::scrollToSubstring called with invalid offset."); + return; + } + + xText->scrollSubstringTo(startIndex, endIndex, AccessibleScrollType_SCROLL_ANYWHERE); } void QtAccessibleWidget::selection(int selectionIndex, int* startOffset, int* endOffset) const @@ -960,25 +974,55 @@ int QtAccessibleWidget::selectionCount() const return 1; // Only 1 selection supported atm return 0; } + void QtAccessibleWidget::setCursorPosition(int position) { Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - xText->setCaretPosition(position); + if (!xText.is()) + return; + + if (position < 0 || position > xText->getCharacterCount()) + { + SAL_WARN("vcl.qt", + "QtAccessibleWidget::setCursorPosition called with invalid offset: " << position); + return; + } + + xText->setCaretPosition(position); } + void QtAccessibleWidget::setSelection(int /* selectionIndex */, int startOffset, int endOffset) { Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - xText->setSelection(startOffset, endOffset); + if (!xText.is()) + return; + + sal_Int32 nTextLength = xText->getCharacterCount(); + if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::setSelection called with invalid offset."); + return; + } + + xText->setSelection(startOffset, endOffset); } + QString QtAccessibleWidget::text(int startOffset, int endOffset) const { Reference<XAccessibleText> xText(getAccessibleContextImpl(), UNO_QUERY); - if (xText.is()) - return toQString(xText->getTextRange(startOffset, endOffset)); - return QString(); + if (!xText.is()) + return QString(); + + sal_Int32 nTextLength = xText->getCharacterCount(); + if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::text called with invalid offset."); + return QString(); + } + + return toQString(xText->getTextRange(startOffset, endOffset)); } + QString QtAccessibleWidget::textAfterOffset(int /* offset */, QAccessible::TextBoundaryType /* boundaryType */, int* /* startOffset */, int* /* endOffset */) const @@ -993,9 +1037,9 @@ QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryTy if (startOffset == nullptr || endOffset == nullptr) return QString(); + const int nCharCount = characterCount(); if (boundaryType == QAccessible::NoBoundary) { - const int nCharCount = characterCount(); *startOffset = 0; *endOffset = nCharCount; return text(0, nCharCount); @@ -1010,7 +1054,14 @@ QString QtAccessibleWidget::textAtOffset(int offset, QAccessible::TextBoundaryTy // special value of -1 for offset means text length if (offset == -1) - offset = xText->getCharacterCount(); + offset = nCharCount; + + if (offset < 0 || offset > nCharCount) + { + SAL_WARN("vcl.qt", + "QtAccessibleWidget::textAtOffset called with invalid offset: " << offset); + return QString(); + } const TextSegment segment = xText->getTextAtIndex(offset, nUnoBoundaryType); *startOffset = segment.SegmentStart; @@ -1037,6 +1088,14 @@ void QtAccessibleWidget::deleteText(int startOffset, int endOffset) Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); if (!xEditableText.is()) return; + + sal_Int32 nTextLength = xEditableText->getCharacterCount(); + if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::deleteText called with invalid offset."); + return; + } + xEditableText->deleteText(startOffset, endOffset); } @@ -1049,6 +1108,13 @@ void QtAccessibleWidget::insertText(int offset, const QString& text) Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); if (!xEditableText.is()) return; + + if (offset < 0 || offset > xEditableText->getCharacterCount()) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::insertText called with invalid offset: " << offset); + return; + } + xEditableText->insertText(toOUString(text), offset); } @@ -1061,6 +1127,14 @@ void QtAccessibleWidget::replaceText(int startOffset, int endOffset, const QStri Reference<XAccessibleEditableText> xEditableText(xAc, UNO_QUERY); if (!xEditableText.is()) return; + + sal_Int32 nTextLength = xEditableText->getCharacterCount(); + if (startOffset < 0 || startOffset > nTextLength || endOffset < 0 || endOffset > nTextLength) + { + SAL_WARN("vcl.qt", "QtAccessibleWidget::replaceText called with invalid offset."); + return; + } + xEditableText->replaceText(startOffset, endOffset, toOUString(text)); }