Bug 46926 - PyUNO structure comparisons broken (always false)
Summary: PyUNO structure comparisons broken (always false)
Status: RESOLVED FIXED
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: LibreOffice (show other bugs)
Version:
(earliest affected)
3.5.0 RC2
Hardware: All All
: medium normal
Assignee: Michael Stahl (allotropia)
URL:
Whiteboard: target:3.6.0 target:3.5.2
Keywords: regression
Depends on:
Blocks:
 
Reported: 2012-03-03 03:27 UTC by David Bolen
Modified: 2012-04-05 08:11 UTC (History)
4 users (show)

See Also:
Crash report or crash signature:


Attachments
Correct rich comparison of wrapped objects (847 bytes, patch)
2012-03-03 15:14 UTC, David Bolen
Details
Correct comparisons when building for Python 2.x (1.07 KB, patch)
2012-03-05 00:26 UTC, David Bolen
Details
Return new references from PyUNO_cmp (2.22 KB, patch)
2012-03-13 18:27 UTC, David Bolen
Details

Note You need to log in before you can comment on or make changes to this bug.
Description David Bolen 2012-03-03 03:27:43 UTC
It appears that part of the Python 3 commit (a09ce46818fd4d5e08b3af9a478501cd8ef5b4fe), where comparisons were switched to use the rich comparison slot, broke structure comparisons.  At least, structures that compared equal in 3.4.5 no longer do so in 3.5 when using the internal Python interpreter.

For example, using the internal Python interpreter with 3.5.1RC1:

Python 2.6.1 (r261:67515, Feb 24 2012, 08:33:41) 
[GCC 4.2.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import uno
>>> from com.sun.star.style import TabStop
>>> a = TabStop()
>>> b = TabStop()
>>> a==b
False

I haven't figured out precisely what is wrong yet, but a brute force approach of replacing the newer rich comparison PyUNO_cmp with the older traditional comparison slot and PyUNO_cmp code appears to work properly (e.g. the same as 3.4.5).

I did notice that the rich comparison version always returns Py_False at the end, where I think the correct return should be either True/False based on NE/EQ as an operation.  Fixing that has no impact, though since the wrapper objects only have an __eq__ slot installed (for _uno_struct__eq__), I don't think it's even possible for the comparison function to be called with Py_NE.

-- David
Comment 1 David Bolen 2012-03-03 15:13:37 UTC
Ok, this turned out to be pretty simple.  While a new rich comparison function
was implemented in the Python 3 changeset, the tp_flags value in the object
type structure was not set to indicate that rich comparisons were supported.

So the comparison function was never called, and nothing (aside from comparing 
an object to itself) will ever compare true.

I'm attaching a patch correcting this.  I also adjusted the final return code
of the comparison function, though I still suspect the function can never
be called with anything but Py_EQ, so perhaps arguably all support for Py_NE should be removed.  This was a smaller change though.

The patch includes a small change to include the older cmpfunc reference in
the type structure, to maintain consistency with the rest of the structure 
where method values (even if null) show the casts.

-- David
Comment 2 David Bolen 2012-03-03 15:14:11 UTC
Created attachment 57987 [details]
Correct rich comparison of wrapped objects
Comment 3 David Bolen 2012-03-05 00:26:38 UTC
Created attachment 58017 [details]
Correct comparisons when building for Python 2.x

Update the proposed patch to maintain Python 3 compatibility - only Python 2 needs the rich comparison tp_flags value.
Comment 4 Michael Stahl (allotropia) 2012-03-05 10:45:26 UTC
the Python 3 commit apparently converted the PyUNO_cmp function
to a "rich compare" function.

so your patch looks entirely plausible to me;
unless some of the people on CC: who actually know Python
tell me a good reason not to, i'll commit it soon.
Comment 5 Not Assigned 2012-03-07 02:21:39 UTC
David Bolen committed a patch related to this issue.
It has been pushed to "master":

http://cgit.freedesktop.org/libreoffice/core/commit/?id=387389b644b91808fdee74846b2d855382f48ed7

fdo#46926: fix UNO struct comparison in Python 2
Comment 6 Maxime de Roucy 2012-03-08 09:20:41 UTC
cmpfunc isn't supported by python3.2 :
% grep cmpfunc /usr/include/python3.2mu/*
/usr/include/python3.2mu/object.h:typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
/usr/include/python3.2mu/object.h:    richcmpfunc tp_richcompare;

So now when I try to build LO with python3.2 it fail saying that cmpfunc isn't defined.

(Simple solution is to build LO with python2 ... but it's just to let you know.)
Comment 7 David Bolen 2012-03-08 22:30:16 UTC
Drat - that's what I get for throwing in a fairly gratuitous tweak for consistency's sake - it's probably why the original Python 3 patch removed it.

I'm traveling until Saturday night - if anyone wants to attach a patch just to remove the "(cmpfunc)" cast before then that should address this - if not I'll add the fix Sat or Sun.
Comment 8 Not Assigned 2012-03-09 06:45:48 UTC
Michael Stahl committed a patch related to this issue.
It has been pushed to "master":

http://cgit.freedesktop.org/libreoffice/core/commit/?id=06484b6946ac6a974c24af6624fb75bbe298c1e8

fdo#46926: fix the fix for Python 3
Comment 9 Not Assigned 2012-03-12 06:51:23 UTC
David Bolen committed a patch related to this issue.
It has been pushed to "libreoffice-3-5":

http://cgit.freedesktop.org/libreoffice/core/commit/?id=82bf2998cb243f3269e39de8daee56cb6bc04550&g=libreoffice-3-5

fdo#46926: fix UNO struct comparison in Python 2


It will be available in LibreOffice 3.5.2.
Comment 10 Not Assigned 2012-03-12 06:52:21 UTC
Michael Stahl committed a patch related to this issue.
It has been pushed to "libreoffice-3-5":

http://cgit.freedesktop.org/libreoffice/core/commit/?id=94541ebd9eb95a47f40bac95f5f6982a562e5a4d&g=libreoffice-3-5

fdo#46926: fix the fix for Python 3


It will be available in LibreOffice 3.5.2.
Comment 11 David Bolen 2012-03-13 18:25:10 UTC
I'm re-opening this because while the committed patch fixes getting the comparison code called under Python 2.x, after using it for a bit it turns out there's an additional subtler issue with the new rich comparison function that I only started seeing once it was getting called in my environment.

The problem is that the new rich comparison function does not return new references to Py_True/Py_False (e.g., increment reference counts) which leads to memory corruption and an eventual segv after some number of comparisons, or presumably at any time after a comparison depending on memory use.

For example:

    >>> import uno
    >>> from com.sun.star.style import TabStop
    >>> a = [TabStop() for x in range(10)]
    >>> b = [TabStop() for x in range(10)]
    >>> a==b
    True
    >>> a==b
    Segmentation fault

(A bunch of tabstops used just to force more comparisons more quickly)

Personally, I just need LO 3.5.x not to break existing Python 2.x behavior so am almost inclined to just revert to the older 3-way comparison function under Python 2, leaving the rich comparison function as Python 3 only.  But the rich comparison rules (always return a new reference) should be the same there so the crash exposure should already exist in Python 3 as well.  So I've got a new patch to always return a new reference.
Comment 12 David Bolen 2012-03-13 18:27:49 UTC
Created attachment 58412 [details]
Return new references from PyUNO_cmp

Always return a new reference from the rich comparison function.
Comment 13 David Bolen 2012-03-13 20:16:01 UTC
I've been able to verify (though it took a few more iterations to crash) that the bug exists when building for Python 3 (tested against the current 3.2.2), and that the supplied patch is compatible.
Comment 14 Not Assigned 2012-03-16 15:17:31 UTC
David Bolen committed a patch related to this issue.
It has been pushed to "master":

http://cgit.freedesktop.org/libreoffice/core/commit/?id=742dca7366ba6ac3c58b1df6ee548788f4ce24e7

fdo#46926: PyUNO_cmp: return acquired reference
Comment 15 Not Assigned 2012-03-19 01:31:01 UTC
David Bolen committed a patch related to this issue.
It has been pushed to "libreoffice-3-5":

http://cgit.freedesktop.org/libreoffice/core/commit/?id=8d7726c6a54cd65700f4d3183baef7800aaeced5&g=libreoffice-3-5

fdo#46926: PyUNO_cmp: return acquired reference


It will be available in LibreOffice 3.5.2.
Comment 16 Rainer Bielefeld Retired 2012-04-05 08:11:13 UTC
I added Fix submitter as assignee because this will ease queries and bug tracking.