Board index FlightGear Development Canvas

Segfault with Canvas and settimer  Topic is solved

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Segfault with Canvas and settimer

Postby Philosopher » Thu Jul 11, 2013 5:35 pm

I'm getting pretty common segfaults with my Nasal-browser addon with 2.10, and it's easily repeatable. Start FG up, launch dialog with nasal_browser.make_window() and then relaunch it (the function closes the dialog if it is active). A couple seconds later, FG will crash:

Code: Select all
Starting update (this line is when I start my Nasal update code)
Missing 'parents' vector for ghost
Missing 'parents' vector for ghost
Missing 'parents' vector for ghost
New canvas element /canvas[0]/by-index[0]/texture[0]/group[0]/group[1]/text[0]
Segmentation fault: 11


Code I'm using is:

Code: Select all
var browser = nil;

var display = func(k,variable,sep=" = ") {
   var t = typeof(variable);
   if (t == 'scalar') {
      call(func size(variable), nil, var err = []);
      if (size(err))
         k~sep~variable;
      else k~sep~"'"~variable~"'";
   } elsif (t == 'hash' or t == 'vector')
      k~"/ (size: "~size(variable)~")";
   elsif (t == 'nil')
      k~sep~"nil";
   elsif (t == 'ghost')
      k~sep~"<ghost/"~ghosttype(variable)~">";
   else k~sep~"<"~t~">";
};
var colors = {
   'scalar': [0.4,0.0,0.6],
   'hash':   [0.0,0.0,0.5],
   'vector': [0.0,0.8,0.0],
   'func':   [1.0,0.2,0.0],
   'ghost':  [1.0,0.3,0.0],
   'nil':    [0.8,0.8,0.8],
};
var color = func(variable) {
   colors[typeof(variable)];
};

var make_window = func {
   if (browser != nil) remove_window();
   browser = getprop("/sim/version/flightgear") == "2.10.0" ? canvas.Dialog.new([400,600]) : canvas.Window.new([400,600]);
   browser.root = globals; browser.scroll = 0;
   browser.history = []; browser.loopid = -10e6;
   browser.editing = nil; browser.children = [];
   browser.listener = setlistener("/devices/status/keyboard/event", func(event) {
      if (!event.getNode("pressed").getValue())
         return;
      var key = event.getNode("key");
      var shift = event.getNode("modifier/shift").getValue();
      if (key.getValue() == 27 and !shift) {
         remove_window();
         key.setValue(-1);           # drop key event
      }
   });

   var my_canvas = browser.createCanvas()
                         .setColorBackground(0,0,0,0);
   var root = my_canvas.createGroup();
   # Title bar:
   var title_bar = root.createChild("group");
   title_bar.addEventListener("drag", func(e) { browser.move(e.deltaX, e.deltaY); });
   var x = 0;
   var y = 0;
   var rx = 8;
   var ry = 8;
   var w = 400;
   var h = 20;
   title_bar.createChild("path")
      .moveTo(x + w - rx, y)
      .arcSmallCWTo(rx, ry, 0, x + w, y + ry)
      .vertTo(y + h)
      .horizTo(x)
      .vertTo(y + ry)
      .arcSmallCWTo(rx, ry, 0, x + rx, y)
      .close()
      .setColorFill(0.25,0.24,0.22)
      .setStrokeLineWidth(0)
      .addEventListener("click", func {
         #gui.popupTip("Back");
         browser.root = pop(browser.history);
         if (!size(browser.history)) append(browser.history, globals);
         browser.scroll = 0;
         display_root();
      });
   # Border/background
   x = 0;
   y = 20;
   w = 400;
   h = 580;
   root.createChild("path")
      .moveTo(x + w, y)
      .vertTo(y + h)
      .horizTo(x)
      .vertTo(y)
      .setColorFill(1,1,1)
      .setColor(0,0,0);
   # Red-X: close this dialog
   x = 8;
   y = 5;
   w = 10;
   h = 10;
   title_bar.createChild("path", "icon-close")
      .moveTo(x, y)
      .lineTo(x + w, y + h)
      .moveTo(x + w, y)
      .lineTo(x, y + h)
      .setColor(1,0,0)
      .setStrokeLineWidth(3)
      .addEventListener("click", func remove_window());
   # Editing window
   var editing = root.createChild("text", "editing")
      .setText("")
      .setTranslation(4, 596)
      .setAlignment("left-baseline")
      .setFontSize(14)
      .setFont("LiberationFonts/LiberationSans-Bold.ttf")
      .setColor(0,0,0)
      .hide();
   # Title of this dialog
   title_bar.createChild("text", "dialog-caption")
      .setText("Nasal namespace browser")
      .setTranslation(x + w + 8, 4)
      .setAlignment("left-top")
      .setFontSize(14)
      .setFont("LiberationFonts/LiberationSans-Bold.ttf")
      .setColor(1,1,1);
   var body = root.createChild("group");
      body.addEventListener("click", func(e) {
         var y = e.clientY-20+browser.scroll;
         y /= 16;
         if (y >= size(browser.children)) return;
         var clicked = browser.children[y];
         #gui.popupTip("Clicked on "~clicked.id);
         if (typeof(clicked.value) == 'hash' or typeof(clicked.value) == 'vector') {
            append(browser.history, browser.root);
            browser.root = clicked.value;
            browser.scroll = 0;
            browser.editing = nil;
         } else {
            browser.editing = clicked;
         }
         display_root(browser.loopid += 1);
      });
      body.addEventListener("drag", func(e) {
         browser.scroll += e.deltaY;
         browser.scroll = browser.scroll < 0 ? 0 : browser.scroll > (size(browser.children)-8)*16 ? math.max((size(browser.children)-8)*16,0) : browser.scroll;
         display_root();
      });
      var update_children = func(id=nil) {
         browser.children = [];
         var x = 4;
         var y = 34-16;
         if (typeof(browser.root) == 'hash') {
            foreach (var k; sort(keys(browser.root), cmp)) {
               if (k == "arg" or k == "__gcsave") continue;
               append(browser.children, {
                  id: k, value: browser.root[k], x: x, y: (y+=16),
               });
            }
         } elsif (typeof(browser.root) == 'vector') {
            forindex (var k; browser.root) {
               append(browser.children, {
                  id: k, value: browser.root[k], x: x, y: (y+=16),
               });
            }
         }
      };
      var last = nil;
      var display_root = func(id=nil) {
         if (browser == nil) return;
         if (browser.children == last) return;
         printlog("debug", "Starting update");
         last = browser.children;
         update_children(browser.loopid += 1);
         body.removeAllChildren();
         foreach (var child; browser.children) {
            var composite = child.y-browser.scroll;
            if (composite > 32 and composite < 575)
               body.createChild("text")
                  .setText(display(child.id,child.value))
                  .setTranslation(child.x, composite)
                  .setAlignment("left-baseline")
                  .setFontSize(14)
                  .setFont("LiberationFonts/LiberationSans-Bold.ttf")
                  .setColor(color(child.value));
         }
         if (browser.editing != nil) {
            editing.show().setText(display(browser.editing.id,browser.editing.value,": "));
         } else editing.hide();
         body.update();
         if (id != nil) settimer(func display_root(id), 1);
         printlog("debug", "Ending update");
      };
   display_root(1);
};

var toggle_window = func {
   if (browser != nil) remove_window();
   else {
      make_window();
   }
};
var remove_window = func {
   if (browser == nil) return;
   removelistener(browser.listener);
   browser.del();
   browser = nil;
   io.load_nasal(getprop("/sim/fg-root") ~ "/Nasal/nasal_browser.nas"); #reload ourselves for testing purposes
};


It looks like something with settimer() callbacks: removing my auto-update and just scrolling by hand (which calls the same function) and using it, it suddenly works fine. Any ideas? (I hope I'm not making too much noise)
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Segfault with Canvas and settimer

Postby Hooray » Thu Jul 11, 2013 6:21 pm

confirmed, seeing this with latest SG/FG next, too (BTW: good job at debugging this without a debugger!):
Code: Select all
#0  0x089d1d32 in simgear::canvas::Group::childAdded(SGPropertyNode*) ()
#1  0x089ca1db in simgear::canvas::Element::childAdded(SGPropertyNode*, SGPropertyNode*) ()
#2  0x08ba05b6 in SGPropertyNode::fireChildAdded(SGPropertyNode*, SGPropertyNode*) ()
#3  0x08ba6c46 in SGPropertyNode::addChild(char const*, int, bool) ()
#4  0x089d0ee0 in simgear::canvas::Group::createChild(std::string const&, std::string const&) ()
#5  0x0875799b in f_groupCreateChild(simgear::canvas::Group&, nasal::CallContext const&) ()
#6  0x0875ed71 in boost::detail::function::function_invoker2<naRef (*)(simgear::canvas::Group&, nasal::CallContext const&), naRef, simgear::canvas::Group&, nasal::CallContext const&>::invoke(boost::detail::function::function_buffer&, simgear::canvas::Group&, nasal::CallContext const&) ()
#7  0x0876b971 in boost::disable_if<boost::is_void<naRef>, naRef>::type nasal::Ghost<boost::shared_ptr<simgear::canvas::Group> >::method_invoker<naRef>(boost::function<naRef (simgear::canvas::Group&, nasal::CallContext const&)> const&, simgear::canvas::Group&, nasal::CallContext const&) ()
#8  0x0875f0ea in boost::detail::function::function_obj_invoker2<boost::_bi::bind_t<naRef, naRef (*)(boost::function<naRef (simgear::canvas::Group&, nasal::CallContext const&)> const&, simgear::canvas::Group&, nasal::CallContext const&), boost::_bi::list3<boost::_bi::value<boost::function<naRef (simgear::canvas::Group&, nasal::CallContext const&)> >, boost::arg<1>, boost::arg<2> > >, naRef, simgear::canvas::Group&, nasal::CallContext const&>::invoke(boost::detail::function::function_buffer&, simgear::canvas::Group&, nasal::CallContext const&) ()
#9  0x08773bcf in nasal::Ghost<boost::shared_ptr<simgear::canvas::Group> >::MethodHolder::call(Context*, naRef, int, naRef*, void*) ()
#10 0x08b80679 in setupFuncall ()
#11 0x08b8207f in run ()
#12 0x08b83ab6 in naCall ()
#13 0x08710cba in FGNasalSys::callMethod(naRef, naRef, int, naRef*, naRef) ()
#14 0x08710e2a in FGNasalSys::NasalTimer::timerExpired() ()
#15 0x08bde643 in SGTimerQueue::update(double) ()
#16 0x08bde73b in SGEventMgr::update(double) ()
#17 0x08be0a39 in SGSubsystemGroup::Member::update(double) ()
#18 0x08be0cdb in SGSubsystemGroup::update(double) ()
#19 0x08be08bb in SGSubsystemMgr::update(double) ()
#20 0x082ba97a in fgMainLoop() ()
#21 0x088313f4 in fgOSMainLoop() ()
#22 0x082bba1f in fgMainInit(int, char**) ()
#23 0x08272696 in main ()


The debug output in the Nasal console "loglist" widget would be helpful to look at - but the loglist no longer dumps stuff to the startup console any longer, which is a pity - and a real regression, we should at least dump stuff to $FG_HOME (the fgfs.log file being empty ATM).
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11965
Joined: Tue Mar 25, 2008 8:40 am

Re: Segfault with Canvas and settimer

Postby Johan G » Fri Jul 12, 2013 5:22 am

Hooray wrote in Thu Jul 11, 2013 6:21 pm:...the loglist no longer dumps stuff to the startup console any longer, which is a pity - and a real regression, we should at least dump stuff to $FG_HOME (the fgfs.log file being empty ATM).

Did I get that right? No error log in the startup console and no written log when something in FlightGear crashes? :? (Sorry for the n00bish question).
Low-level flying — It's all fun and games till someone looses an engine. (Paraphrased from a YouTube video)
Improving the Dassault Mirage F1 (Wiki, Forum, GitLab. Work in slow progress)
Johan G
Moderator
 
Posts: 6021
Joined: Fri Aug 06, 2010 5:33 pm
Location: Sweden
Callsign: SE-JG
IRC name: Johan_G
Version: 2020.3.2
OS: Windows 10, 64 bit

Re: Segfault with Canvas and settimer

Postby Hooray » Fri Jul 12, 2013 7:08 am

If I didn't miss anything, that seems to be the case currently ... we will need to ask Zakalawe, because he's the one who implemented the loglist stuff.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11965
Joined: Tue Mar 25, 2008 8:40 am

Re: Segfault with Canvas and settimer

Postby Philosopher » Fri Jul 12, 2013 11:48 am

I did post the --log-level=debug...? Or are you talking about something else?
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Segfault with Canvas and settimer

Postby Johan G » Fri Jul 12, 2013 12:28 pm

Johan G wrote in Fri Jul 12, 2013 5:22 am:No error log in the startup console and no written log when something in FlightGear crashes?

Just to clear any misunderstandings, with "error log in the startup console" I meant any error messages in the console window (a.k.a. the "black box"), and with "written log" I meant any kind of error log file written to disk.
Low-level flying — It's all fun and games till someone looses an engine. (Paraphrased from a YouTube video)
Improving the Dassault Mirage F1 (Wiki, Forum, GitLab. Work in slow progress)
Johan G
Moderator
 
Posts: 6021
Joined: Fri Aug 06, 2010 5:33 pm
Location: Sweden
Callsign: SE-JG
IRC name: Johan_G
Version: 2020.3.2
OS: Windows 10, 64 bit

Re: Segfault with Canvas and settimer  

Postby TheTom » Fri Jul 12, 2013 4:04 pm

I've pushed a fix which prevents the segfault and instead prints a warning message. It seems 'display_root' is called for the old window a few times, even after it has been destroyed...
TheTom
 
Posts: 322
Joined: Sun Oct 09, 2011 10:20 am

Re: Segfault with Canvas and settimer

Postby Hooray » Fri Jul 12, 2013 4:09 pm

I was referring to the loglist widget in the Nasal console, which "filters" any Nasal messages and no longer displays them in the terminal window from where fgfs was started.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11965
Joined: Tue Mar 25, 2008 8:40 am

Re: Segfault with Canvas and settimer

Postby Johan G » Fri Jul 12, 2013 4:16 pm

Ah, that is a bit less alarming. :wink: :)
Low-level flying — It's all fun and games till someone looses an engine. (Paraphrased from a YouTube video)
Improving the Dassault Mirage F1 (Wiki, Forum, GitLab. Work in slow progress)
Johan G
Moderator
 
Posts: 6021
Joined: Fri Aug 06, 2010 5:33 pm
Location: Sweden
Callsign: SE-JG
IRC name: Johan_G
Version: 2020.3.2
OS: Windows 10, 64 bit

Re: Segfault with Canvas and settimer

Postby Hooray » Fri Jul 12, 2013 4:32 pm

actually, it would seem to make sense to always start a session-specific log file and use an exception handler to write to it, in case there's a segfault, so that the full log gets written to some fgfs.pid file. We already have way too many "Unknown exception in the main loop" errors, which are often really tricky to troubleshoot.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11965
Joined: Tue Mar 25, 2008 8:40 am


Return to Canvas

Who is online

Users browsing this forum: No registered users and 2 guests