Accidental Infinite Recursion
BlitzMax Forums/BlitzMax Programming/Accidental Infinite Recursion
| ||
I came across an interesting bug yesterday that I'd thought I'd share and check that my new 1.33rc5 build is doing what it should be doing. When typing in a function argument, I accidentally entered type "String" instead of type "Int" for what I was going to use as a boolean. The result was an always true "boolean" argument, and an infinite self-call recursion loop. What concerned me was that this bug sidestepped all my logging routines and gave me no clue where in the code it was occurring. Since my code base is over 500 K lines, it was a tad worrying. Despite my try/catch block, the app in debug mode just dropped out with no errors with a Process complete Obviously infinite recursion is going to break your code. But is there any way it can throw some kind of exception when it does? SuperStrict ' Oops I typed "String" here! Function AccidentalRecursion(_count:Int, _b_recurse:String = False) Print _count If _b_recurse AccidentalRecursion(_count+1) EndIf End Function Try AccidentalRecursion(0) Catch exception:Object Print exception.ToString() End Try Running this on my machine (XP) gives .. 149297 149298 149299 Process complete |
| ||
On Mac, the crash report should show you there's a recursion problem (is so much as there'll be a list of function calls about 512 deep) - although it won't help you to see where it is. |
| ||
On Mac, the crash report should show you there's a recursion problem Alas, most of my users will be on XP/Vista. |
| ||
Make sure to read what you write twice at least, then? There isn't really any other option in BMax short of making sure to have useful debug output, common sense, and so on. |
| ||
Make sure to read what you write twice at least, then? Sure, but mistyping an argument isn't the only way to invoke infinite recursion. I'm sure it would be possible to come up with some hairy user-install specific instances where such a bug could arise. I guess my point is - it is dropping back to the IDE "somehow". It'd be nice if that "somehow" wasn't silent. |
| ||
I'm not sure what you hope for it to do. It isn't failing to report an error as such. You're literally crashing the debugger. Every time you call a new function without returning from the old one, you're adding another set of data to the stack. If you do that often enough without returning, you'll eventually run out of stack space. If you run out of stack space, the debugger will crash. I *suppose* the debugger could track the stack space and report that it's run out, but even then it doesn't automatically mean infinite recursion. You can actually run out of stack space even with a legitimate program if your recursion goes deep enough. Essentially, if you crash the debugger, there's a good chance you ran out of stack space. |
| ||
I'm sure it would be possible to come up with some hairy user-install specific instances where such a bug could arise. Come up with one. I don't think you're going to find an instance where the problem really comes about because of a user's setup. |
| ||
Well my concern wasn't so much for when it happens to me in debugmode in front of my IDE. It is if it happens to a user rarely and intermittently and all they have to tell me is "the app just vanishes". I have built the ability to log function and method entry/exit into 90+% of my code. But this log trace doesn't write to file in such a case. And I can't really have them run full log trace mode, where every entry exit is recorded to file, because the slow down would make the app unwieldy - especially since it could be hours/days/weeks before the bugs shows for them again. When I asked the question, I was concerned my 1.33rc5 build might not have gone right - but if this is expected behaviour on XP then I'll just have to write better code / construct more thorough tests :-) Come up with one? Oh I don’t know – how about when the stars align with this kind of setup: Function A If Condition B Call Function B Function B If Condition C Call Function C .. Function N If Condition N Call Function A |
| ||
Oh I don’t know – how about when the stars align with this kind of setup: That's not a user-specific instance, or even an example...I'll be frank here: you are not going to find a situation where you recurse infinitely without it being your fault and only your fault. For that reason, you need to take care that when you write code, you review it and make sure you wrote it correctly. Then review it again. If it's recursive, make sure your base case works and that you're handling each step into the recursion properly. That's all you'll get in BlitzMax, and that's all you can hope to get in most any programming language. |
| ||
if you are attemting a scripting language then it can certainly be the user's fault but other than that, I don't see why create all these whatifs.. just write neat code, deal with little bugs, and run in superstrict which has caught many bugs that may cause infinite recursion in my own code. were I have something like thisGraphics 640,480,0,60 Global ext:Int = False While Not ext Cls If KeyDown(key_escape) Then a Flip Wend Function a() If ext = False Then ex = True 'typo here b EndIf End Function Function b() Delay 100 a End Function so if you superstrict the code above then it will catch the possible infinite recursion. but if you run as is, the infinite recursion happens as a result of a bug... so if you want to be safe then just make sure you have a function tree drawn out making sure functions higher on the tree don't call functions at the beginning of the tree |