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)

Reply via email to