https://issues.apache.org/ooo/show_bug.cgi?id=97539

--- Comment #7 from [email protected] ---
So this is what happens (no comment on fixing). 

There are two variants of the bug shown. In the first variant, we have:

oRangeAddress = oCursor.getRangeAddress()

In this case, getRangeAddress() returns a COPY (because struts are always -- or
at least almost always -- returned as a copy rather than a reference). This is
copied into oRangeAddress. 

In the smaller version, oRangeAddress is declared to be of type 
com.sun.star.table.CellRangeAddress.

In both cases, this variable lives as a UNO struct inside a function. 

Now, the individual properties are stored in array, so I looked in methods1.cxx
at RTLFUNC(Array) and I see code used to build the array:

    for( sal_uInt16 i = 0 ; i < nArraySize ; i++ )
    {
        SbxVariable* pVar = rPar.Get(i+1);
        SbxVariable* pNew = new SbxVariable( *pVar );
        pNew->SetFlag( SBX_WRITE );
        short index = static_cast< short >(i);
        if ( bIncIndex )
        {
            ++index;
        }
        pArray->Put( pNew, &index );
    }

Although you can look in sbxarray.cxx for the method void SbxArray::Put(
SbxVariable* pVar, sal_uInt16 nIdx ) to see how things are stored (end of this
comment), the damage is probably already done with this:

        SbxVariable* pVar = rPar.Get(i+1);
        SbxVariable* pNew = new SbxVariable( *pVar );

We have properties (SbUnoProperty) that are lazy loaded when they are actually
accessed, and we did not actually access them; we only stored a reference to
them. By the time we do get around to referencing the values, which causes the
values to be populated, the parent object has destructed and no longer exists
(it is long out of scope).

See this code that stores stuff.

void SbxArray::Put( SbxVariable* pVar, sal_uInt16 nIdx )
{
    if( !CanWrite() )
        SetError( SbxERR_PROP_READONLY );
    else
    {
        if( pVar )
            if( eType != SbxVARIANT )
                // Convert no objects
                if( eType != SbxOBJECT || pVar->GetClass() != SbxCLASS_OBJECT )
                    pVar->Convert( eType );
        SbxVariableRef& rRef = GetRef( nIdx );
        if( (SbxVariable*) rRef != pVar )
        {
            rRef = pVar;
            SetFlag( SBX_MODIFIED );
        }
    }
}

So, how can you avoid the problem in your macro? You can store a reference to
the struct in the array (feels silly, but it works, I checked), or you can
first create your array and access the values in that array to cause them to
load, and then return that array. 

Probably not the only solutions (like extract the values so that they are
stored as integers, can probably accomplish this by casting the values as they
are stored in the array). 

I expect that it might be a large behavior change (and performance hit) to
cause all properties stored into an array to be accessed on storage, and
perhaps convert them. I have not tried some of the obvious possible unexpected
side effects yet (like store the value in the array, change the actual property
value and then see if it changes in the array itself).

-- 
You are receiving this mail because:
You are on the CC list for the bug.

Reply via email to