Troubleshooting sip assignHelper != NULL assertion
Phil Thompson
phil at riverbankcomputing.com
Mon Jun 1 17:07:06 BST 2020
On 31/05/2020 17:48, Scott Talbert wrote:
> On Sun, 31 May 2020, Phil Thompson wrote:
>
>> On 31/05/2020 16:29, Scott Talbert wrote:
>>> On Sun, 31 May 2020, Phil Thompson wrote:
>>>
>>>> On 31/05/2020 01:23, Scott Talbert wrote:
>>>>> On Sat, 30 May 2020, Phil Thompson wrote:
>>>>>
>>>>>> On 28/05/2020 16:52, Scott Talbert wrote:
>>>>>>> On Thu, 28 May 2020, Phil Thompson wrote:
>>>>>>>
>>>>>>>> On 28/05/2020 16:30, Scott Talbert wrote:
>>>>>>>>> On Thu, 28 May 2020, Phil Thompson wrote:
>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I'm running into the following assertion in wxPython that I
>>>>>>>>>>>>> don't
>>>>>>>>>>>>> quite understand:
>>>>>>>>>>>>>
>>>>>>>>>>>>> python3: ../../../../sip/siplib/siplib.c:3444: parseResult:
>>>>>>>>>>>>> Assertion
>>>>>>>>>>>>> `assign_helper != NULL' failed.
>>>>>>>>>>>>>
>>>>>>>>>>>>> This is the relevant C++ class:
>>>>>>>>>>>>>
>>>>>>>>>>>>> class wxPGWindowList
>>>>>>>>>>>>> {
>>>>>>>>>>>>> public:
>>>>>>>>>>>>> wxPGWindowList(wxWindow* primary, wxWindow* secondary =
>>>>>>>>>>>>> NULL)
>>>>>>>>>>>>> : m_primary(primary)
>>>>>>>>>>>>> , m_secondary(secondary)
>>>>>>>>>>>>> {
>>>>>>>>>>>>> }
>>>>>>>>>>>>>
>>>>>>>>>>>>> void SetSecondary(wxWindow* secondary) { m_secondary =
>>>>>>>>>>>>> secondary; }
>>>>>>>>>>>>>
>>>>>>>>>>>>> wxWindow* GetPrimary() const { return m_primary; }
>>>>>>>>>>>>> wxWindow* GetSecondary() const { return m_secondary; }
>>>>>>>>>>>>>
>>>>>>>>>>>>> wxWindow* m_primary;
>>>>>>>>>>>>> wxWindow* m_secondary;
>>>>>>>>>>>>> };
>>>>>>>>>>>>
>>>>>>>>>>>> It doesn't matter what the C++ class looks like, it's the
>>>>>>>>>>>> corresponding .sip that would be of interest.
>>>>>>>>>>>
>>>>>>>>>>> My bad, here it is:
>>>>>>>>>>> class wxPGWindowList
>>>>>>>>>>> {
>>>>>>>>>>> %Docstring
>>>>>>>>>>> PGWindowList(primary, secondary=None)
>>>>>>>>>>>
>>>>>>>>>>> Contains a list of editor windows returned by
>>>>>>>>>>> CreateControls.
>>>>>>>>>>> %End
>>>>>>>>>>> %TypeHeaderCode
>>>>>>>>>>> #include <wx/propgrid/editors.h>
>>>>>>>>>>> %End
>>>>>>>>>>>
>>>>>>>>>>> public:
>>>>>>>>>>> wxPGWindowList(
>>>>>>>>>>> wxWindow * primary,
>>>>>>>>>>> wxWindow * secondary = NULL
>>>>>>>>>>> );
>>>>>>>>>>>
>>>>>>>>>>> void SetSecondary(
>>>>>>>>>>> wxWindow * secondary
>>>>>>>>>>> );
>>>>>>>>>>> %Docstring
>>>>>>>>>>> SetSecondary(secondary)
>>>>>>>>>>> %End
>>>>>>>>>>>
>>>>>>>>>>> wxWindow * GetPrimary() const;
>>>>>>>>>>> %Docstring
>>>>>>>>>>> GetPrimary() -> wx.Window
>>>>>>>>>>>
>>>>>>>>>>> Gets window of primary editor.
>>>>>>>>>>> %End
>>>>>>>>>>>
>>>>>>>>>>> wxWindow * GetSecondary() const;
>>>>>>>>>>> %Docstring
>>>>>>>>>>> GetSecondary() -> wx.Window
>>>>>>>>>>>
>>>>>>>>>>> Gets window of secondary editor.
>>>>>>>>>>> %End
>>>>>>>>>>>
>>>>>>>>>>> public:
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> %Property(name=Primary, get=GetPrimary)
>>>>>>>>>>> %Property(name=Secondary, get=GetSecondary,
>>>>>>>>>>> set=SetSecondary)
>>>>>>>>>>> }; // end of class wxPGWindowList
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>>> The assertion occurs when trying to return an instance of
>>>>>>>>>>>>> wxPGWindowList in a Python method, e.g.:
>>>>>>>>>>>>>
>>>>>>>>>>>>> def foo():
>>>>>>>>>>>>> return wxpg.PGWindowList(a, b)
>>>>>>>>>>>>>
>>>>>>>>>>>>> From what I can tell, there is no assignment helper
>>>>>>>>>>>>> assigned by sip
>>>>>>>>>>>>> because there is no default constructor? I may be missing
>>>>>>>>>>>>> something,
>>>>>>>>>>>>> but I can't see why a default constructor would be needed.
>>>>>>>>>>>>
>>>>>>>>>>>> You don't say what version of the sip module you are using
>>>>>>>>>>>> but I'm guessing that that assertion is when it's parsing
>>>>>>>>>>>> the Python object returned by a re-implementation of a C++
>>>>>>>>>>>> virtual. That doesn't seem to be happening in the above
>>>>>>>>>>>> which suggests things aren't happening where you think they
>>>>>>>>>>>> are.
>>>>>>>>>>>
>>>>>>>>>>> sip module version is 4.19.19. You are correct, I
>>>>>>>>>>> oversimplified what
>>>>>>>>>>> is actually happening. This is really what is happening:
>>>>>>>>>>>
>>>>>>>>>>> class LargeImageEditor(wxpg.PGEditor):
>>>>>>>>>>> def CreateControls(self, propgrid, property, pos, sz):
>>>>>>>>>>> ...
>>>>>>>>>>> return wxpg.PGWindowList(self.tc, btn)
>>>>>>>>>>>
>>>>>>>>>>> Where CreateControls is a C++ virtual, relevant .sip snippet:
>>>>>>>>>>>
>>>>>>>>>>> virtual
>>>>>>>>>>> wxPGWindowList CreateControls(
>>>>>>>>>>> wxPropertyGrid * propgrid,
>>>>>>>>>>> wxPGProperty * property,
>>>>>>>>>>> const wxPoint & pos,
>>>>>>>>>>> const wxSize & size
>>>>>>>>>>> ) const = 0;
>>>>>>>>>>> %Docstring
>>>>>>>>>>> CreateControls(propgrid, property, pos, size) ->
>>>>>>>>>>> PGWindowList
>>>>>>>>>>>
>>>>>>>>>>> Instantiates editor controls.
>>>>>>>>>>> %End
>>>>>>>>>>
>>>>>>>>>> So SIP need to copy the wxPGWindowList from the stack to the
>>>>>>>>>> heap. Shouldn't CreateControls return a pointer to the
>>>>>>>>>> wxPGWindowList?
>>>>>>>>>>
>>>>>>>>>> Of course SIP should detect this when generating the code
>>>>>>>>>> rather than rely on a runtime assertion.
>>>>>>>>>
>>>>>>>>> That is probably how I would have designed the API, but alas it
>>>>>>>>> wasn't
>>>>>>>>> done that way. :)
>>>>>>>>>
>>>>>>>>> Shouldn't a (default) copy constructor be sufficient to copy
>>>>>>>>> the
>>>>>>>>> wxPGWindowList in this case?
>>>>>>>>
>>>>>>>> SIP may be being too conservative when determining if there is
>>>>>>>> an implied copy ctor. Try adding an explicit copy ctor to the
>>>>>>>> wxPGWindowList .sip file.
>>>>>>>
>>>>>>> I don't think that will be enough, though. SIP seems to only set
>>>>>>> the
>>>>>>> assignment helper if there are *both* a public default
>>>>>>> constructor and
>>>>>>> a public copy constructor, see:
>>>>>>>
>>>>>>> https://www.riverbankcomputing.com/hg/sip/file/d85e9957e726/sipgen/transform.c#l596
>>>>>>>
>>>>>>> Scott
>>>>>>
>>>>>> Should be fixed in the current repo. SIP v4.19.23 will be released
>>>>>> next week.
>>>>>>
>>>>>> Be aware that the fix may expose missing private ctors in other
>>>>>> .sip files - PyQt had two cases.
>>>>>
>>>>> Thanks for the quick fix.
>>>>>
>>>>> However, I think I found a situation with the new code where an
>>>>> assign
>>>>> function is getting created where it probably shouldn't be.
>>>>>
>>>>> struct wxSplitterRenderParams
>>>>> {
>>>>> %Docstring
>>>>> SplitterRenderParams(widthSash_, border_, isSens_)
>>>>>
>>>>> This is just a simple struct used as a return value of
>>>>> wxRendererNative::GetSplitterParams().
>>>>> %End
>>>>> %TypeHeaderCode
>>>>> #include <wx/renderer.h>
>>>>> %End
>>>>>
>>>>> wxSplitterRenderParams(
>>>>> wxCoord widthSash_,
>>>>> wxCoord border_,
>>>>> bool isSens_
>>>>> );
>>>>>
>>>>> const wxCoord border;
>>>>>
>>>>> const bool isHotSensitive;
>>>>>
>>>>> const wxCoord widthSash;
>>>>>
>>>>> }; // end of class wxSplitterRenderParams
>>>>>
>>>>> This results in:
>>>>>
>>>>> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp: In function
>>>>> ‘void assign_wxSplitterRenderParams(void*, Py_ssize_t, void*)’:
>>>>> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp:31:125:
>>>>> error:
>>>>> use of deleted function ‘wxSplitterRenderParams&
>>>>> wxSplitterRenderParams::operator=(const wxSplitterRenderParams&)’
>>>>> 31 | reinterpret_cast< ::wxSplitterRenderParams
>>>>> *>(sipDst)[sipDstIdx] = *reinterpret_cast< ::wxSplitterRenderParams
>>>>> *>(sipSrc);
>>>>> | ^
>>>>> In file included from
>>>>> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp:12:
>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>> note: ‘wxSplitterRenderParams&
>>>>> wxSplitterRenderParams::operator=(const
>>>>> wxSplitterRenderParams&)’ is implicitly deleted because the default
>>>>> definition would be ill-formed:
>>>>> 97 | struct WXDLLIMPEXP_CORE wxSplitterRenderParams
>>>>> | ^~~~~~~~~~~~~~~~~~~~~~
>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>> error: non-static const member ‘const wxCoord
>>>>> wxSplitterRenderParams::widthSash’, cannot use default assignment
>>>>> operator
>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>> error: non-static const member ‘const wxCoord
>>>>> wxSplitterRenderParams::border’, cannot use default assignment
>>>>> operator
>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>> error: non-static const member ‘const bool
>>>>> wxSplitterRenderParams::isHotSensitive’, cannot use default
>>>>> assignment
>>>>> operator
>>>>
>>>> Yes, that's what I meant by missing private copy ctors. SIP cannot
>>>> accurately determine whether a copy ctor is available unless it
>>>> knows everything about the C++ class (including private members and
>>>> their types), but SIP is not a full C++ parser (and never will be).
>>>> Therefore you need to declare a private copy ctor in the .sip file
>>>> to correct the assumption that there is a public copy ctor
>>>> available. In the future I may add a class annotation to achieve the
>>>> same thing.
>>>
>>> Thanks, I understand that now. :) After declaring a private copy
>>> ctor in the above .sip file, I'm now getting this:
>>>
>>> ../../../../sip/cpp/sip_corewxDelegateRendererNative.cpp: In function
>>> ‘PyObject* meth_wxDelegateRendererNative_GetSplitterParams(PyObject*,
>>> PyObject*, PyObject*)’:
>>> ../../../../sip/cpp/sip_corewxDelegateRendererNative.cpp:1360:38:
>>> error: taking address of rvalue [-fpermissive]
>>> 1360 | sipRes = &(sipSelfWasArg ? sipCpp->
>>> ::wxDelegateRendererNative::GetSplitterParams(win) :
>>> sipCpp->GetSplitterParams(win));
>>> |
>>> ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>
>>> So, since SIP can't copy the wxSplitterRenderParams, it is trying to
>>> return a reference to the original one, but it seems that doesn't
>>> work?
>>
>> So what does the .sip file for wxDelegateRenderNative look like?
>
> It's a bit long, so attached.
Can you try the current repo.
When you are happy I'll release v4.19.23.
Phil
More information about the PyQt
mailing list