This is an automated email from the ASF dual-hosted git repository.
jimjag pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git
The following commit(s) were added to refs/heads/trunk by this push:
new 60fcfbce1c pyuno: fix crash on objects that implement XInvocation
themselves
60fcfbce1c is described below
commit 60fcfbce1cf55d512c6ebbf7aee11464c2706d80
Author: Jim Jagielski <[email protected]>
AuthorDate: Mon Nov 9 16:14:24 2026 -0500
pyuno: fix crash on objects that implement XInvocation themselves
The Invocation adapter offers no XInvocation2 for them, so pyuno kept
null references and segfaulted on the first attribute access (script
browse nodes). Methods such as getName() are now found through reflection.
---
main/pyuno/source/module/pyuno.cxx | 131 ++++++++++++++++++++++++++--
main/pyuno/source/module/pyuno_callable.cxx | 85 ++++++++++++++++--
main/pyuno/source/module/pyuno_impl.hxx | 11 ++-
main/pyuno/source/module/pyuno_module.cxx | 4 +-
4 files changed, 212 insertions(+), 19 deletions(-)
diff --git a/main/pyuno/source/module/pyuno.cxx
b/main/pyuno/source/module/pyuno.cxx
index 4886689263..18ab58621d 100644
--- a/main/pyuno/source/module/pyuno.cxx
+++ b/main/pyuno/source/module/pyuno.cxx
@@ -28,6 +28,9 @@
#include <osl/thread.h>
+#include <algorithm>
+#include <vector>
+
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
@@ -54,7 +57,10 @@ using com::sun::star::lang::XSingleServiceFactory;
using com::sun::star::lang::XServiceInfo;
using com::sun::star::lang::XTypeProvider;
using com::sun::star::script::XTypeConverter;
+using com::sun::star::script::XInvocation;
using com::sun::star::script::XInvocation2;
+using com::sun::star::reflection::XIdlClass;
+using com::sun::star::reflection::XIdlMethod;
using com::sun::star::beans::XMaterialHolder;
namespace pyuno
@@ -334,6 +340,52 @@ PyObject *PyUNO_repr( PyObject * self )
return ret;
}
+// An object with its own XInvocation (no XInvocation2 from Invocation_Impl)
reports only the
+// members it chooses to, so its interface methods are found through
reflection instead.
+static Sequence< Reference< XIdlClass > > getReflectedInterfaces( PyUNO *me,
const Runtime &runtime )
+{
+ Sequence< Reference< XIdlClass > > ret;
+ Reference< XInvocation2 > inv2( me->members->xInvocation, UNO_QUERY );
+ if( inv2.is() )
+ return ret;
+ Reference< XTypeProvider > typeProvider( me->members->wrappedObject,
UNO_QUERY );
+ if( ! typeProvider.is() )
+ return ret;
+
+ Sequence< Type > types( typeProvider->getTypes() );
+ ret.realloc( types.getLength() );
+ sal_Int32 n = 0;
+ for( sal_Int32 i = 0 ; i < types.getLength() ; i ++ )
+ {
+ Reference< XIdlClass > c(
+ runtime.getImpl()->cargo->xCoreReflection->forName(
types[i].getTypeName() ) );
+ if( c.is() && c->getTypeClass() ==
com::sun::star::uno::TypeClass_INTERFACE )
+ ret[n++] = c;
+ }
+ ret.realloc( n );
+ return ret;
+}
+
+// acquire(), release() and queryInterface() must never be callable from Python
+static bool isXInterfaceMember( const Reference< XIdlMethod > &m )
+{
+ Reference< XIdlClass > decl( m->getDeclaringClass() );
+ return decl.is() && decl->getName().equalsAscii(
"com.sun.star.uno.XInterface" );
+}
+
+static Reference< XIdlMethod > findReflectedMethod(
+ PyUNO *me, const OUString &name, const Runtime &runtime )
+{
+ Sequence< Reference< XIdlClass > > classes( getReflectedInterfaces( me,
runtime ) );
+ for( sal_Int32 i = 0 ; i < classes.getLength() ; i ++ )
+ {
+ Reference< XIdlMethod > m( classes[i]->getMethod( name ) );
+ if( m.is() && ! isXInterfaceMember( m ) )
+ return m;
+ }
+ return Reference< XIdlMethod >();
+}
+
PyObject *PyUNO_invoke( PyObject *object, const char *name , PyObject *args )
{
PyRef ret;
@@ -346,18 +398,25 @@ PyObject *PyUNO_invoke( PyObject *object, const char
*name , PyObject *args )
{
PyUNO* me = (PyUNO*) object;
OUString attrName = OUString::createFromAscii(name);
+ Reference< XIdlMethod > xMethod;
if (! me->members->xInvocation->hasMethod (attrName))
{
- OUStringBuffer buf;
- buf.appendAscii( "Attribute " );
- buf.append( attrName );
- buf.appendAscii( " unknown" );
- throw RuntimeException( buf.makeStringAndClear(), Reference<
XInterface > () );
+ xMethod = findReflectedMethod( me, attrName, runtime );
+ if (! xMethod.is())
+ {
+ OUStringBuffer buf;
+ buf.appendAscii( "Attribute " );
+ buf.append( attrName );
+ buf.appendAscii( " unknown" );
+ throw RuntimeException( buf.makeStringAndClear(),
Reference< XInterface > () );
+ }
}
callable = PyUNO_callable_new (
me->members->xInvocation,
attrName,
- ACCEPT_UNO_ANY);
+ ACCEPT_UNO_ANY,
+ xMethod,
+ me->members->wrappedObject);
paras = args;
}
else
@@ -500,6 +559,20 @@ PyObject* PyUNO_getattr (PyObject* self, PyObject*
attr_name)
return ret.get();
}
+ //or a method of an interface that the object's own XInvocation does
not report
+ Reference< XIdlMethod > xMethod( findReflectedMethod( me, attrName,
runtime ) );
+ if( xMethod.is() )
+ {
+ PyRef ret = PyUNO_callable_new (
+ me->members->xInvocation,
+ attrName,
+ REJECT_UNO_ANY,
+ xMethod,
+ me->members->wrappedObject);
+ Py_XINCREF( ret.get() );
+ return ret.get();
+ }
+
//or else...
PyErr_SetString (PyExc_AttributeError, name);
}
@@ -579,7 +652,42 @@ static PyObject *PyUNO_dir( PyObject *self, PyObject *that
)
Sequence<OUString> oo_member_list;
me = (PyUNO*) self;
- oo_member_list = me->members->xInvocation->getMemberNames ();
+ Reference< XInvocation2 > inv2( me->members->xInvocation, UNO_QUERY );
+ if( inv2.is() )
+ oo_member_list = inv2->getMemberNames ();
+ else
+ {
+ try
+ {
+ Runtime runtime;
+ std::vector< OUString > names;
+ Sequence< Reference< XIdlClass > > classes(
getReflectedInterfaces( me, runtime ) );
+ for( sal_Int32 i = 0 ; i < classes.getLength() ; i ++ )
+ {
+ Sequence< Reference< XIdlMethod > > methods(
classes[i]->getMethods() );
+ for( sal_Int32 j = 0 ; j < methods.getLength() ; j ++ )
+ {
+ OUString n( methods[j]->getName() );
+ if( ! isXInterfaceMember( methods[j] ) &&
+ std::find( names.begin(), names.end(), n ) ==
names.end() )
+ names.push_back( n );
+ }
+ }
+ oo_member_list.realloc( names.size() );
+ for( size_t k = 0 ; k < names.size() ; k ++ )
+ oo_member_list[k] = names[k];
+ }
+ catch( com::sun::star::uno::RuntimeException &e )
+ {
+ raisePyExceptionWithAny( makeAny( e ) );
+ return NULL;
+ }
+ catch( com::sun::star::uno::Exception &e )
+ {
+ raisePyExceptionWithAny( makeAny( e ) );
+ return NULL;
+ }
+ }
member_list = PyList_New (oo_member_list.getLength ());
for (int i = 0; i < oo_member_list.getLength (); i++)
{
@@ -753,10 +861,17 @@ PyObject* PyUNO_new_UNCHECKED (
{
PyThreadDetach antiguard;
tmp_interface = ssf->createInstanceWithArguments (arguments);
- Reference<XInvocation2> tmp_invocation (tmp_interface, UNO_QUERY);
+ Reference<XInvocation> tmp_invocation (tmp_interface, UNO_QUERY);
self->members->xInvocation = tmp_invocation;
self->members->wrappedObject = targetInterface;
}
+ if( ! self->members->xInvocation.is() )
+ {
+ Py_DECREF( (PyObject*) self );
+ throw RuntimeException(
+ OUString( RTL_CONSTASCII_USTRINGPARAM( "pyuno: no XInvocation for
the wrapped object" ) ),
+ Reference< XInterface >() );
+ }
return (PyObject*) self;
}
diff --git a/main/pyuno/source/module/pyuno_callable.cxx
b/main/pyuno/source/module/pyuno_callable.cxx
index a43da97c5c..8838051b93 100644
--- a/main/pyuno/source/module/pyuno_callable.cxx
+++ b/main/pyuno/source/module/pyuno_callable.cxx
@@ -37,15 +37,24 @@ using com::sun::star::uno::RuntimeException;
using com::sun::star::uno::XComponentContext;
using com::sun::star::lang::XSingleServiceFactory;
using com::sun::star::script::XTypeConverter;
-using com::sun::star::script::XInvocation2;
+using com::sun::star::script::XInvocation;
+using com::sun::star::script::CannotConvertException;
+using com::sun::star::lang::IllegalArgumentException;
+using com::sun::star::reflection::XIdlClass;
+using com::sun::star::reflection::XIdlMethod;
+using com::sun::star::reflection::ParamInfo;
+using com::sun::star::reflection::ParamMode_IN;
+using com::sun::star::reflection::ParamMode_OUT;
namespace pyuno
{
typedef struct
{
- Reference<XInvocation2> xInvocation;
+ Reference<XInvocation> xInvocation;
OUString methodName;
ConversionMode mode;
+ Reference<XIdlMethod> xMethod; // set when the object's XInvocation does
not know the method
+ Any target;
} PyUNO_callable_Internals;
typedef struct
@@ -65,6 +74,61 @@ void PyUNO_callable_del (PyObject* self)
return;
}
+// Same argument and out-parameter handling as Invocation_Impl::invoke() has
for introspected objects.
+static Any invokeReflected(
+ RuntimeCargo *cargo, const Reference<XIdlMethod> &xMethod, const Any
&target,
+ const Sequence<Any> &aParams, Sequence<sal_Int16> &aOutIndex,
Sequence<Any> &aOutParam )
+{
+ Sequence<ParamInfo> infos = xMethod->getParameterInfos();
+ sal_Int32 nParams = infos.getLength();
+ if( nParams != aParams.getLength() )
+ throw IllegalArgumentException(
+ OUString( RTL_CONSTASCII_USTRINGPARAM(
+ "incorrect number of parameters passed invoking
function " ) )
+ + xMethod->getName(),
+ Reference<XInterface>(), (sal_Int16) 1 );
+
+ Sequence<Any> aInvoke( nParams );
+ aOutIndex.realloc( nParams );
+ sal_Int32 nOut = 0;
+ for( sal_Int32 i = 0 ; i < nParams ; i ++ )
+ {
+ try
+ {
+ const ParamInfo &info = infos[i];
+ if( info.aMode != ParamMode_OUT )
+ {
+ Reference<XIdlClass> src(
+ cargo->xCoreReflection->forName(
aParams[i].getValueType().getTypeName() ) );
+ if( src.is() && info.aType->isAssignableFrom( src ) )
+ aInvoke[i] = aParams[i];
+ else
+ aInvoke[i] = cargo->xTypeConverter->convertTo(
+ aParams[i], Type( info.aType->getTypeClass(),
info.aType->getName() ) );
+ }
+ if( info.aMode != ParamMode_IN )
+ {
+ aOutIndex[nOut++] = (sal_Int16) i;
+ if( info.aMode == ParamMode_OUT )
+ info.aType->createObject( aInvoke[i] );
+ }
+ }
+ catch( CannotConvertException &e )
+ {
+ e.ArgumentIndex = (sal_Int16) i;
+ throw;
+ }
+ }
+
+ Any ret = xMethod->invoke( target, aInvoke );
+
+ aOutIndex.realloc( nOut );
+ aOutParam.realloc( nOut );
+ for( sal_Int32 j = 0 ; j < nOut ; j ++ )
+ aOutParam[j] = aInvoke[ aOutIndex[j] ];
+ return ret;
+}
+
PyObject* PyUNO_callable_call (PyObject* self, PyObject* args, PyObject*)
{
PyUNO_callable* me;
@@ -107,8 +171,13 @@ PyObject* PyUNO_callable_call (PyObject* self, PyObject*
args, PyObject*)
}
// do the call
- ret_value = me->members->xInvocation->invoke (
- me->members->methodName, aParams, aOutParamIndex, aOutParam);
+ if( me->members->xMethod.is() )
+ ret_value = invokeReflected(
+ cargo, me->members->xMethod, me->members->target,
+ aParams, aOutParamIndex, aOutParam );
+ else
+ ret_value = me->members->xInvocation->invoke (
+ me->members->methodName, aParams, aOutParamIndex,
aOutParam);
// log the reply, if desired
if( isLog( cargo, LogLevel::CALL ) )
@@ -239,9 +308,11 @@ static PyTypeObject PyUNO_callable_Type =
};
PyRef PyUNO_callable_new (
- const Reference<XInvocation2> &my_inv,
+ const Reference<XInvocation> &my_inv,
const OUString & methodName,
- enum ConversionMode mode )
+ enum ConversionMode mode,
+ const Reference<XIdlMethod> &xMethod,
+ const Any &target )
{
PyUNO_callable* self;
@@ -253,6 +324,8 @@ PyRef PyUNO_callable_new (
self->members->xInvocation = my_inv;
self->members->methodName = methodName;
self->members->mode = mode;
+ self->members->xMethod = xMethod;
+ self->members->target = target;
return PyRef( (PyObject*)self, SAL_NO_ACQUIRE );
}
diff --git a/main/pyuno/source/module/pyuno_impl.hxx
b/main/pyuno/source/module/pyuno_impl.hxx
index 2e846d3480..769de65f05 100644
--- a/main/pyuno/source/module/pyuno_impl.hxx
+++ b/main/pyuno/source/module/pyuno_impl.hxx
@@ -34,6 +34,8 @@
#include <com/sun/star/script/XInvocationAdapterFactory2.hpp>
#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/reflection/XIdlClass.hpp>
+#include <com/sun/star/reflection/XIdlMethod.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
@@ -123,7 +125,7 @@ PyObject* PyUNO_new_UNCHECKED (
typedef struct
{
- com::sun::star::uno::Reference <com::sun::star::script::XInvocation2>
xInvocation;
+ com::sun::star::uno::Reference <com::sun::star::script::XInvocation>
xInvocation;
com::sun::star::uno::Any wrappedObject;
} PyUNOInternals;
@@ -149,9 +151,12 @@ void raiseInvocationTargetExceptionWhenNeeded( const
Runtime &runtime );
com::sun::star::uno::TypeClass StringToTypeClass (char* string);
PyRef PyUNO_callable_new (
- const com::sun::star::uno::Reference<com::sun::star::script::XInvocation2>
&xInv,
+ const com::sun::star::uno::Reference<com::sun::star::script::XInvocation>
&xInv,
const rtl::OUString &methodName,
- ConversionMode mode = REJECT_UNO_ANY );
+ ConversionMode mode = REJECT_UNO_ANY,
+ const
com::sun::star::uno::Reference<com::sun::star::reflection::XIdlMethod> &xMethod
+ =
com::sun::star::uno::Reference<com::sun::star::reflection::XIdlMethod>(),
+ const com::sun::star::uno::Any &target = com::sun::star::uno::Any() );
PyObject* PyUNO_Type_new (const char *typeName ,
com::sun::star::uno::TypeClass t , const Runtime &r );
PyObject* PyUNO_Enum_new( const char *enumBase, const char *enumValue, const
Runtime &r );
diff --git a/main/pyuno/source/module/pyuno_module.cxx
b/main/pyuno/source/module/pyuno_module.cxx
index dbda9a40bf..eb3c01d075 100644
--- a/main/pyuno/source/module/pyuno_module.cxx
+++ b/main/pyuno/source/module/pyuno_module.cxx
@@ -61,7 +61,7 @@ using com::sun::star::uno::XComponentContext;
using com::sun::star::container::NoSuchElementException;
using com::sun::star::reflection::XIdlReflection;
using com::sun::star::reflection::XIdlClass;
-using com::sun::star::script::XInvocation2;
+using com::sun::star::script::XInvocation;
using namespace pyuno;
@@ -71,7 +71,7 @@ namespace {
@ index of the next to be used member in the initializer list !
*/
sal_Int32 fillStructWithInitializer(
- const Reference< XInvocation2 > &inv,
+ const Reference< XInvocation > &inv,
typelib_CompoundTypeDescription *pCompType,
PyObject *initializer,
const Runtime &runtime)