Troubleshooting sip assignHelper != NULL assertion
Scott Talbert
swt at techie.net
Tue Jun 2 03:00:57 BST 2020
On Mon, 1 Jun 2020, Phil Thompson wrote:
> 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.
Unfortunately, I'm still running into trouble with this
wxSplitterRenderParams class. This is what I get now:
../../../../sip/cpp/sip_corewxRendererNative.cpp: In function ‘PyObject*
meth_wxRendererNative_GetSplitterParams(PyObject*, PyObject*, PyObject*)’:
../../../../sip/cpp/sip_corewxRendererNative.cpp:1464:52: error: use of
deleted function ‘wxSplitterRenderParams&
wxSplitterRenderParams::operator=(wxSplitterRenderParams&&)’
1464 | *sipRes = sipCpp->GetSplitterParams(win);
| ^
In file included from ../../../../sip/cpp/sip_corewxRendererNative.cpp:12:
../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25: note:
‘wxSplitterRenderParams&
wxSplitterRenderParams::operator=(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
../../../../sip/cpp/sip_corewxRendererNative.cpp: In function ‘PyObject*
meth_wxRendererNative_GetVersion(PyObject*, PyObject*)’:
../../../../sip/cpp/sip_corewxRendererNative.cpp:1508:42: error: use of
deleted function ‘wxRendererVersion&
wxRendererVersion::operator=(wxRendererVersion&&)’
1508 | *sipRes = sipCpp->GetVersion();
| ^
In file included from ../../../../sip/cpp/sip_corewxRendererNative.cpp:12:
../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:141:25: note:
‘wxRendererVersion& wxRendererVersion::operator=(wxRendererVersion&&)’ is
implicitly deleted because the default definition would be ill-formed:
141 | struct WXDLLIMPEXP_CORE wxRendererVersion
| ^~~~~~~~~~~~~~~~~
../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:141:25: error:
non-static const member ‘const int wxRendererVersion::version’, cannot use
default assignment operator
../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:141:25: error:
non-static const member ‘const int wxRendererVersion::age’, cannot use
default assignment operator
I looked at what SIP 4.19.19 generated for sip_corewxRendererNative.cpp,
and this is what it did:
sipRes = new ::wxSplitterRenderParams(sipCpp->GetSplitterParams(win));
So, it seems the wxSplitterRenderParams class does actually have an
implicit copy constructor that works. So, it doesn't have an assignment
operator but DOES have a copy constructor.
Thanks,
Scott
More information about the PyQt
mailing list