debugging "Stack Overflow Error"

This is a new one on me:

Error: Stack Overflow Error
Details: 'Failed invoking <symbol>'
Time: 2019-06-22T03:13:09Z
Part-Number: 006-B2697-00
Firmware-Version: '13.30'
Language-Code: eng
ConnectIQ-Version: 3.0.11
Filename: 96G15439
Appname: raceQs
Stack:
  - pc: 0x1000c8c4
  - pc: 0x1000c8c4
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x1000c9b5
  - pc: 0x10006b34
  - pc: 0x10009819

The first PC ref, 0x1000c8c4 converted to decimal 268486852 doesn't get a hit in the debug.xml.

The closest hit is 268486820 which is the Ui.popView(0) below.

		else if (item == :logOut){  
		 	Storage.clearValues();
		 	System.println(" screensMenuDelegate  onMenuItem logOut popView");
		 	Ui.popView(0); // close app

But this doesn't make sense as it's part of the log out process which was certainly not in play at the time, so I'm looking in the wrong place.

Any suggestions, please?

  • Looking at that stack and just wondering if it could be correct - it's suggesting there are 16 iterative calls to some function? The 0x1000c9b5 one. Could that iterative calling be allocating too much memory on the stack (whatever that function is allocating each time it is called) causing it to overflow?

  • look at what's at/near 0x1000c9b5, as that looks to be calling itself a number of time.  recursion can generate this.

  • As mentioned by others, the recursive call to 0x1000c9b5 are likely a big part of the problem. With stack overflow errors, it doesn't really matter how much memory you allocate, what is important is the number of parameters, variables, and temporaries used in the function. The typical solution will be to either reduce the overhead of each recursion (by reducing the number of parameters/variables/temporaries, moving to the heap if needed) or eliminate the recursion (by rewriting the code to use iteration, likely using a stack)

    One other note: If you were using a debug PRG, those stack frames should be translated to file/line information for you automatically.

  • Also, it is possible that the top few frames are garbage due to stack corruption.

  • OK, thanks everyone. It is indeed occurring in a recursive sorting function that I'm using to extract some stats from the track data,

    I'm not able to reduce the number of parameters, but I would like to explore the possibilities of "moving to the heap" as  Travis suggests:

    (by reducing the number of parameters/variables/temporaries, moving to the heap if needed) or eliminate the recursion (by rewriting the code to use iteration, likely using a stack)

    I'm not sure I can rewrite the sorting function using iteration, as it's data dependent. 

    It would be really nice if the SDK had an array.sort 

  • Anything you can implement with recursion can be implemented with iteration. Additionally, there are many different sort algorithms that are easily implemented without recursion.

    For us to provide Array.sort, we'd need to either define how objects of various types and values are compared (i.e., how should the string "hello" compare to the number 1, or the string "1" and the number 2). Since we don't really know how your application wants to sort objects, we need to call back your code to provide the sorting criteria. We'd typically do this with a Lang.Method, but this this is relatively expensive. If all you needed to do was to sort a collection of integers, using a callback like this is very expensive.

  • PHP takes a good approach with usort, where you define the comparison condition, as does javascript with its array.sort.

    Could you point me to some of the sort algorithms that use iteration that I might use please? I just want to sort an array of around 30 numbers into ascending sequence.

  • PHP takes a good approach with usort, where you define the comparison condition, as does javascript with its array.sort.

    Both of those examples basically involve passing a user-defined function as a callback to the library sort function, which is already what Travis described as being too expensive in Monkey C.

    Could you point me to some of the sort algorithms that use iteration that I might use please?

    As Travis said, anything that uses recursion can be rewritten with iteration (this is one of those theoretical Computer Science things that actually has practical consequences), although some sort algorithms lend themselves to iteration a bit more easily than others (as they don't require you to provide your own stack / temporary data area for intermediate results, as Travis alluded to).

    This kind of thing has been discussed to death and is just a google / stackoverflow search away:

    https://stackoverflow.com/questions/12030618/recursive-vs-non-recursive-sorting-algorithms

    "Insertion sort is a simple example of a non-recursive sorting algorithm."

    ^ Also happens to dominate the top hits for this search:

    https://www.google.com/search?q=iterative+sort+algorithms

    Here's a JS implementation which should be easily adaptable to Monkey C :

    https://hackernoon.com/programming-with-js-insertion-sort-1316df8354f5

  • Another approach you may consider is to build things sorted.  When you add something new, insert it where it needs to be.

    if it's less than the current lowest, make it first, greater then the largest, make it last.  Then go by halves.  If it's less than the one in the middle, keep doing halves on the first half.  If it's larger than the one in the middle, keep doing halves on the last half.

    Even if you get past the stack overflow issue, you'll want to be careful with the watchdog timer - where your app runs too long and the VM kills it.  When you're dealing with a bunch of data and doing anything like sorting, the watchdog timer could still bite you.

  • Thanks, the insertion sort did the trick and was quite simple to port from JS.

    which is already what Travis described as being too expensive in Monkey C

    I still suspect a supplied function would be cheaper and more reliable than a do-it-yourself solution.