tdf#146626 catch IndexOutOfBoundsException when fetching accessible children
com::sun::star::accessibility::XAccessibleContext::getAccessibleChild()
can throw an IndexOutOfBoundsException exception even when fetching with
an index that is positive and less than the value returned by a call to
the accessible context's getAccessibleChildCount() method so put every
getAccessibleChild() call in a try/catch block.
Note: this is actually expected behavior even though it is rare. For
example, accessibility::AccessibleTextHelper_Impl::getAccessibleChild()
uses the following code snippet to throw such an exception:
if( 0 > i || i >= getAccessibleChildCount() ||
GetTextForwarder().GetParagraphCount() <= i )
In the case of tdf#146626, getAccessibleChildCount() returns 22 but
getAccessibleChild(1) throws such an exception due to the last
condition in the above code snippet.
Change-Id: If974afb7b9178faa99b91dcd79eb5f169bbfe13e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153160
Tested-by: Jenkins
Reviewed-by: Patrick Luby <plubius@neooffice.org>
diff --git a/vcl/osx/a11yfocustracker.cxx b/vcl/osx/a11yfocustracker.cxx
index 8d830cd..2aaa8b0 100644
--- a/vcl/osx/a11yfocustracker.cxx
+++ b/vcl/osx/a11yfocustracker.cxx
@@ -30,8 +30,10 @@
#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
AquaA11yFocusTracker& TheAquaA11yFocusTracker()
@@ -118,10 +120,16 @@ void AquaA11yFocusTracker::notify_toolbox_item_focus(ToolBox *pToolBox)
if( xContext.is() )
{
ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
if( nPos != ToolBox::ITEM_NOTFOUND )
setFocusedObject( xContext->getAccessibleChild( nPos ) );
//TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
try {
ToolBox::ImplToolItems::size_type nPos = pToolBox->GetItemPos( pToolBox->GetHighlightItemId() );
if( nPos != ToolBox::ITEM_NOTFOUND )
setFocusedObject( xContext->getAccessibleChild( nPos ) );
//TODO: ToolBox::ImplToolItems::size_type -> sal_Int32!
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "Accessible object has invalid index in parent");
}
}
}
}
@@ -150,11 +158,17 @@ void AquaA11yFocusTracker::toolbox_open_floater(vcl::Window *pWindow)
return;
}
if ( rxContext -> getAccessibleChildCount() > 0 ) {
Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
if ( ! rxAccessibleChild.is() ) {
return;
try {
Reference < XAccessible > rxAccessibleChild = rxContext -> getAccessibleChild( 0 );
if ( ! rxAccessibleChild.is() ) {
return;
}
setFocusedObject ( rxAccessibleChild );
}
setFocusedObject ( rxAccessibleChild );
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "No valid accessible objects in parent");
}
}
}
}
diff --git a/vcl/osx/a11yrolehelper.mm b/vcl/osx/a11yrolehelper.mm
index 5cb75c9..e95036d 100644
--- a/vcl/osx/a11yrolehelper.mm
+++ b/vcl/osx/a11yrolehelper.mm
@@ -24,8 +24,12 @@
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <sal/log.hxx>
using namespace ::com::sun::star::accessibility;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
@implementation AquaA11yRoleHelper
@@ -153,17 +157,23 @@ using namespace ::com::sun::star::uno;
}
}
} else if ( accessibleContext -> getAccessibleRole() == AccessibleRole::COMBO_BOX ) {
Reference < XAccessible > rxAccessible = accessibleContext -> getAccessibleChild(0);
if ( rxAccessible.is() ) {
Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) {
sal_Int64 nStateSet = rxAccessibleContext -> getAccessibleStateSet();
if ( !(nStateSet & AccessibleStateType::EDITABLE ) ) {
[ nativeRole release ];
nativeRole = NSAccessibilityPopUpButtonRole;
try {
Reference < XAccessible > rxAccessible = accessibleContext -> getAccessibleChild(0);
if ( rxAccessible.is() ) {
Reference < XAccessibleContext > rxAccessibleContext = rxAccessible -> getAccessibleContext();
if ( rxAccessibleContext.is() && rxAccessibleContext -> getAccessibleRole() == AccessibleRole::TEXT ) {
sal_Int64 nStateSet = rxAccessibleContext -> getAccessibleStateSet();
if ( !(nStateSet & AccessibleStateType::EDITABLE ) ) {
[ nativeRole release ];
nativeRole = NSAccessibilityPopUpButtonRole;
}
}
}
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "No valid accessible objects in parent");
}
}
return nativeRole;
}
diff --git a/vcl/osx/a11ywrapper.mm b/vcl/osx/a11ywrapper.mm
index 06967df..0ca256a 100644
--- a/vcl/osx/a11ywrapper.mm
+++ b/vcl/osx/a11ywrapper.mm
@@ -45,6 +45,7 @@
#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp>
#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
#include <com/sun/star/lang/DisposedException.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <sal/log.hxx>
#include <osl/diagnose.h>
@@ -339,19 +340,25 @@ static std::ostream &operator<<(std::ostream &s, NSObject *obj) {
NSMutableArray * children = [ [ NSMutableArray alloc ] init ];
Reference< XAccessibleContext > xContext( [ self accessibleContext ] );
sal_Int64 cnt = xContext -> getAccessibleChildCount();
for ( sal_Int64 i = 0; i < cnt; i++ ) {
Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
if( xChild.is() ) {
Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
// the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
[ children addObject: wrapper ];
[ wrapper release ];
try {
sal_Int64 cnt = xContext -> getAccessibleChildCount();
for ( sal_Int64 i = 0; i < cnt; i++ ) {
Reference< XAccessible > xChild( xContext -> getAccessibleChild( i ) );
if( xChild.is() ) {
Reference< XAccessibleContext > xChildContext( xChild -> getAccessibleContext() );
// the menubar is already accessible (including Apple- and Application-Menu) through NSApplication => omit it here
if ( xChildContext.is() && AccessibleRole::MENU_BAR != xChildContext -> getAccessibleRole() ) {
id wrapper = [ AquaA11yFactory wrapperForAccessibleContext: xChildContext ];
[ children addObject: wrapper ];
[ wrapper release ];
}
}
}
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "Accessible object has invalid index in parent");
}
// if not already acting as RadioGroup now is the time to replace RadioButtons with RadioGroups and remove RadioButtons
if ( ! mActsAsRadioGroup ) {
@@ -1063,16 +1070,22 @@ static Reference < XAccessibleContext > hitTestRunner ( css::awt::Point point,
}
if( bSafeToIterate ) {
for ( sal_Int64 i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
if ( myHitChild.is() ) {
hitChild = myHitChild;
break;
try {
for ( sal_Int64 i = 0; i < rxAccessibleContext -> getAccessibleChildCount(); i++ ) {
Reference < XAccessible > rxAccessibleChild = rxAccessibleContext -> getAccessibleChild ( i );
if ( rxAccessibleChild.is() && rxAccessibleChild -> getAccessibleContext().is() && rxAccessibleChild -> getAccessibleContext() -> getAccessibleRole() != AccessibleRole::LIST ) {
Reference < XAccessibleContext > myHitChild = hitTestRunner ( point, rxAccessibleChild -> getAccessibleContext() );
if ( myHitChild.is() ) {
hitChild = myHitChild;
break;
}
}
}
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "Accessible object has invalid index in parent");
}
}
}
} catch ( RuntimeException ) {
diff --git a/vcl/osx/documentfocuslistener.cxx b/vcl/osx/documentfocuslistener.cxx
index 5f39e7c..44a3506 100644
--- a/vcl/osx/documentfocuslistener.cxx
+++ b/vcl/osx/documentfocuslistener.cxx
@@ -106,7 +106,13 @@ Reference< XAccessible > DocumentFocusListener::getAccessible(const EventObject&
Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
if( xParentContext.is() )
{
return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
try {
return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "Accessible object has invalid index in parent");
}
}
}
}
@@ -153,13 +159,19 @@ void DocumentFocusListener::attachRecursive(
if( ! (nStateSet & AccessibleStateType::MANAGES_DESCENDANTS) )
{
sal_Int64 n, nmax = xContext->getAccessibleChildCount();
for( n = 0; n < nmax; n++ )
{
Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
try {
sal_Int64 n, nmax = xContext->getAccessibleChildCount();
for( n = 0; n < nmax; n++ )
{
Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
if( xChild.is() )
attachRecursive(xChild);
if( xChild.is() )
attachRecursive(xChild);
}
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "Accessible object index does not exist in parent");
}
}
}
@@ -197,13 +209,19 @@ void DocumentFocusListener::detachRecursive(
if( ! (nStateSet & AccessibleStateType::MANAGES_DESCENDANTS) )
{
sal_Int64 n, nmax = xContext->getAccessibleChildCount();
for( n = 0; n < nmax; n++ )
{
Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
try {
sal_Int64 n, nmax = xContext->getAccessibleChildCount();
for( n = 0; n < nmax; n++ )
{
Reference< XAccessible > xChild( xContext->getAccessibleChild( n ) );
if( xChild.is() )
detachRecursive(xChild);
if( xChild.is() )
detachRecursive(xChild);
}
}
catch (const IndexOutOfBoundsException&)
{
SAL_WARN("vcl", "Accessible object index does not exist in parent");
}
}
}