Project

General

Profile

WTreeView scroll with Column Delegate segfault

Added by Mark Petryk 4 months ago

I have a weird problem with a WTableView will segfault on scroll.

I have about 600 rows in this table. I auto-scroll to the bottom
of the table and cause the 'edit' event to happen on that row so
that the user is placed at the bottom of the table ready to type.

If I (mouse wheel) 'scroll-up' a bit, and cause that 'loading'
graphical to appear momentarily, and then scroll back down to
the bottom where the editor was showing, the system segfaults.

Here is the trace log;

**
** On first load, the createEditor is called.
**
[2023-Dec-23 19:03:03.456] 15207 - [info] "wthttp: 192.168.1.33   GET /resources/loading.png HTTP/1.1 200 4267"
src/Gui/AccountRegister.cpp:111 DateDelegate::createEditor() r:698 c:0
src/Gui/AccountRegister.cpp:161 
[2023-Dec-23 19:03:03.460] 15207 - [info] "wthttp: 192.168.1.33   POST /demo?wtd=Df1ndqALPjgMTVUI HTTP/1.1 200 5429"
[2023-Dec-23 19:03:03.518] 15207 - [info] "WebRequest: took 0.632 ms"
[2023-Dec-23 19:03:05.129] 15207 - [info] "wthttp: 192.168.1.33   POST /demo?wtd=Df1ndqALPjgMTVUI HTTP/1.1 200 8316"
[2023-Dec-23 19:03:05.129] 15207 - [info] "WebRequest: took 4.269 ms"
**
** On scroll-up, the editor 'editState' is called (for some reason).
**
**
src/Gui/AccountRegister.cpp:198 Wt::cpp17::any DateDelegate::editState() r:698 c:0 i:o1i5u63c n: s:1 t:PN2Wt7WWidgetE d:0x7fffec037300 m:0x7fffec037300 t:12/23/2023
[2023-Dec-23 19:03:05.238] 15207 - [info] "wthttp: 192.168.1.33   POST /demo?wtd=Df1ndqALPjgMTVUI HTTP/1.1 200 5296"
[2023-Dec-23 19:03:05.238] 15207 - [info] "WebRequest: took 7.246 ms"
**
** On scroll-back-down the system segfaults on createEditor.
**  Note, the delegate is not destroyed either.  I have a tracer
**  on the destructor and it is not called during this event.
**  If I nav to another field without scrolling, the destructor
**  ~is~ called.
**
**
src/Gui/AccountRegister.cpp:111 DateDelegate::createEditor() r:698 c:0
src/Gui/AccountRegister.cpp:161 

Thread 7 "gnucashew-bin" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffea7fc640 (LWP 15333)]
Wt::WContainerWidget::widget (this=0x0, index=index@entry=0) at /usr/include/c++/11/bits/stl_vector.h:1061
1061          operator[](size_type __n) const _GLIBCXX_NOEXCEPT
(gdb) bt
#0  Wt::WContainerWidget::widget(int) const (this=0x0, index=index@entry=0) at /usr/include/c++/11/bits/stl_vector.h:1061
#1  0x00007ffff7966548 in Wt::WItemDelegate::setEditState(Wt::WWidget*, Wt::WModelIndex const&, linb::any const&) const (this=<optimized out>, editor=<optimized out>, index=<optimized out>, value=...)
    at /home/serveradmin/wt/src/src/Wt/WItemDelegate.C:463
#2  0x000055555564afd8 in (anonymous namespace)::DateDelegate::setEditState(Wt::WWidget*, Wt::WModelIndex const&, Wt::cpp17::any const&) const (this=0x7fffc400b300, _editor=0x7fffc4033310, _index=..., _value=...)
    at src/Gui/AccountRegister.cpp:228
#3  0x00007ffff7a4a2b3 in Wt::WTableView::renderWidget(Wt::WWidget*, Wt::WModelIndex const&) (this=0x7fffc4003640, widget=0x7fffc4033310, index=...) at /home/serveradmin/wt/src/src/Wt/WTableView.C:371
#4  0x00007ffff7a4b5de in Wt::WTableView::renderTable(int, int, int, int) (this=0x7fffc4003640, fr=632, lr=<optimized out>, fc=0, lc=7) at /home/serveradmin/wt/src/src/Wt/WTableView.C:683
#5  0x00007ffff7a52c68 in Wt::WTableView::render(Wt::WFlags<Wt::RenderFlag>) (this=0x7fffc4003640, flags=...) at /home/serveradmin/wt/src/src/Wt/WTableView.C:930
#6  0x00007ffff78a6119 in Wt::WCompositeWidget::getSDomChanges(std::vector<Wt::DomElement*, std::allocator<Wt::DomElement*> >&, Wt::WApplication*)
     (this=0x7fffc4003640, result=std::vector of length 0, capacity 0, app=0x7fffd000a300) at /home/serveradmin/wt/src/src/Wt/WCompositeWidget.C:502
#7  0x00007ffff7c95493 in Wt::WebRenderer::collectChanges(std::vector<Wt::DomElement*, std::allocator<Wt::DomElement*> >&) (this=0x7fffd0002050, changes=std::vector of length 0, capacity 0)
    at /home/serveradmin/wt/src/src/web/WebRenderer.C:1645
#8  0x00007ffff7c95718 in Wt::WebRenderer::collectJS(Wt::WStringStream*) (this=0x7fffd0002050, js=0x7fffd0002138) at /home/serveradmin/wt/src/src/web/WebRenderer.C:1757
#9  0x00007ffff7c9673f in Wt::WebRenderer::collectJavaScriptUpdate(Wt::WStringStream&) (this=0x7fffd0002050, out=...) at /home/serveradmin/wt/src/src/web/WebRenderer.C:1677
#10 0x00007ffff7c96cb5 in Wt::WebRenderer::collectJavaScript() (this=0x7fffd0002050) at /home/serveradmin/wt/src/src/web/WebRenderer.C:825
#11 0x00007ffff7c98ff8 in Wt::WebRenderer::serveJavaScriptUpdate(Wt::WebResponse&) (this=0x7fffd0002050, response=...) at /home/serveradmin/wt/src/src/web/WebRenderer.C:594
#12 0x00007ffff7c7e3c4 in Wt::WebSession::serveResponse(Wt::WebSession::Handler&) (this=0x7fffd0001f00, handler=...) at /home/serveradmin/wt/src/src/web/WebSession.h:210
#13 0x00007ffff7c85c38 in Wt::WebSession::render(Wt::WebSession::Handler&) (this=0x7fffd0001f00, handler=...) at /home/serveradmin/wt/src/src/web/WebSession.C:2813
#14 0x00007ffff7c83e35 in Wt::WebSession::handleRequest(Wt::WebSession::Handler&) (this=0x7fffd0001f00, handler=...) at /home/serveradmin/wt/src/src/web/WebSession.C:1739
#15 0x00007ffff7c7039b in Wt::WebController::handleRequest(Wt::WebRequest*) (this=<optimized out>, request=0x7fffd0001d50) at /home/serveradmin/wt/src/src/web/WebController.C:796
#16 0x00007ffff7f8ae74 in std::__invoke_impl<void, void (Wt::WebController::*&)(Wt::WebRequest*), Wt::WebController*&, http::server::HTTPRequest*&>(std::__invoke_memfun_deref, void (Wt::WebController::*&)(Wt::WebRequest*), Wt::WebController*&, http::server::HTTPRequest*&) (__f=<optimized out>, __t=<optimized out>, __f=<synthetic pointer>: <optimized out>, __t=<synthetic pointer>: <optimized out>) at /usr/include/c++/11/bits/invoke.h:74
#17 std::__invoke<void (Wt::WebController::*&)(Wt::WebRequest*), Wt::WebController*&, http::server::HTTPRequest*&>(void (Wt::WebController::*&)(Wt::WebRequest*), Wt::WebController*&, http::server::HTTPRequest*&)
     (__fn=<synthetic pointer>: <optimized out>) at /usr/include/c++/11/bits/invoke.h:96
#18 std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>::__call<void, , 0ul, 1ul>(std::tuple<>&&, std::_Index_tuple<0ul, 1ul>)
    (__args=<optimized out>, this=<synthetic pointer>) at /usr/include/c++/11/functional:420
#19 std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>::operator()<, void>() (this=<synthetic pointer>) at /usr/include/c++/11/functional:503
#20 boost::asio::asio_handler_invoke<std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)> >(std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>&, ...) (function=<synthetic pointer>...) at /usr/include/boost/asio/handler_invoke_hook.hpp:88
#21 boost_asio_handler_invoke_helpers::invoke<std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>, std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)> >(std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>&, std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>&) (context=<synthetic pointer>..., function=<synthetic pointer>...) at /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:54
#22 boost::asio::detail::handler_work<std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u>, void>::complete<std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)> >(std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>&, std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>&) (handler=<synthetic pointer>..., function=<synthetic pointer>..., this=<synthetic pointer>)
    at /usr/include/boost/asio/detail/handler_work.hpp:425
#23 boost::asio::detail::completion_handler<std::_Bind<void (Wt::WebController::*(Wt::WebController*, http::server::HTTPRequest*))(Wt::WebRequest*)>, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0u> >::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) (owner=0x555555735400, base=0x7fffc403edc0) at /usr/include/boost/asio/detail/completion_handler.hpp:74
#24 0x00007ffff79581b3 in boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) (bytes_transferred=<optimized out>, ec=..., owner=0x555555735400, this=0x7fffc403edc0)
    at /usr/include/boost/asio/detail/scheduler_operation.hpp:40
#25 boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info&, boost::system::error_code const&)
    (this=this@entry=0x555555735400, lock=..., this_thread=..., ec=...) at /usr/include/boost/asio/detail/impl/scheduler.ipp:481
#26 0x00007ffff7953051 in boost::asio::detail::scheduler::run(boost::system::error_code&) (this=0x555555735400, ec=...) at /usr/include/boost/asio/detail/impl/scheduler.ipp:204
#27 0x00007ffff79532a6 in boost::asio::io_context::run() (this=<optimized out>, this=0x555555760358) at /usr/include/boost/asio/impl/io_context.ipp:63
--Type <RET> for more, q to quit, c to continue without paging--
#28 Wt::WIOService::run() (this=0x555555760350) at /home/serveradmin/wt/src/src/Wt/WIOService.C:185
#29 0x00007ffff68dc253 in  () at /lib/x86_64-linux-gnu/libstdc++.so.6
#30 0x00007ffff6494ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#31 0x00007ffff6526660 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

So, I'm not really sure what to look at here. If I don't apply the delegate, it works just fine.
Am I simply missing something with how I built that delegate? I have other delegates that don't
seem to exhibit this problem.

Thank you,


Replies (3)

RE: WTreeView scroll with Column Delegate segfault - Added by Mark Petryk 4 months ago

Problem was here;


   218  void
   219  DateDelegate::
   220  setEditState( Wt::WWidget * _editor, const Wt::WModelIndex & _index, const Wt::cpp17::any & _value ) const
   221  {
   227  
          /*
          ** The error is here
          **  This makes a call to the subclass setEditState, and it should NOT be called here
          **  This Delegate uses a WDateEdit not a WLineEdit, and WItemDelegate::setEditState does not handle that well
          */
   228    Wt::WItemDelegate::setEditState( _editor, _index, _value );
   229  
   230  } // endvoid DateDelegate::setEditState( Wt::WWidget * _editor, const Wt::WModelIndex & _index, const Wt::cpp17::any & _value ) const
   231  

RE: WTreeView scroll with Column Delegate segfault - Added by Matthias Van Ceulebroeck 4 months ago

Hi Mark,

indeed the WItemDelegate expects the widget to be a simple WLineEdit. However, it should be able to handle a WDateEdit as well, since that inherits from WLinEdit.
These are always wrapped though, in this case in a WContainerWidget (in the form of IndexContainerWidget, with a little extra information). You replace that with your own custom widget, which breaks the "basic" Wt logic.

Alternatively, it should be possible to override the Wt::WItemDelegate::update(), and edit the content there. I believe that would resolve your issue, in that this will leave the wrapping widget as it is, and thus correctly cast and respectively update the WLineEdit.
Depending on your use-case this may be a better (as in less code) approach.

Best regards,
Matthias

    (1-3/3)