2014-08-28 14:43 GMT-07:00 Eric Blake <ebl...@redhat.com>: > On 08/28/2014 03:00 PM, bogun.dmit...@gmail.com wrote: > >>> Whey there is check on division by zero? We can predict this? - No. But > >> we > >>> can detect it... and we out nice, detailed error message. > >> > >> Actually, division by zero is fairly easy to check, and this is probably > >> a case where bash is checking for division by 0 up front rather than > >> handling SIGFPE after the fact. > >> > > Is it so heavy to check length of $BASH_SOURCE array? > > Checking the length of $BASH_SOURCE array (or indeed, ANY check of some > counter compared to the current recursion depth) is only an > approximation. It tells whether you are nearing an artificial limit. > It does NOT tell you if you will overflow the stack (it's possible to > set the variable too high, and still trigger a stack overflow; more > likely, if you set the variable too low, someone can come up with a > recursive program that _would_ have completed had it been granted full > access to the stack but now fails because your limit got in the way). > > For _certain_ cases of programming, determining maximum stack usage is > computible (start at the leaves, figure out how much they allocate, then > work your way up the call stack). But the moment you introduce > recursion into the mix, where the recursion is conditionally gated on > user input, it is _inherently impossible_ to compute the maximum stack > depth for all possible program execution flows, shy of actually > executing the program. Bash, and many other scripting languages, are in > such a boat - by giving the end user the power to write a recursive > function, they are also giving the end user the power to exhaust an > unknowable stack depth. > > As long as the interpreter implements user recursion by using recursive > functions itself, there is no way to say "if I call your next function, > I will overflow the stack, so pre-emptively error out now, but keep my > interpreter running". The _BEST_ we can do is detect that "I just ran > out of stack, but in jumping to the SIGSEGV handler, I can't guarantee > whether I interrupted a malloc or any other locked code, therefore I > cannot safely use malloc or any other locking function between now and > calling _exit()". > > It is possible to write a class of programs that GUARANTEE that if stack > overflow happens, that it did not happen within any core function that > might hold a lock, and therefore the program can longjmp back to a safe > point, abort the overflowing operation, and carry on with life. But it > is EXTREMELY TRICKY to do - you have to be absolutely vigilant that you > separate your code into two buckets - the set of code that might obtain > any lock, but is used non-recursively (and therefore you can compute the > maximum stack depth of that code), and the set of code that recurses, > but cannot obtain any lock without first checking that the current stack > depth plus the maximum depth of the locking code will still fit in the > stack. With a program like that, you can then pre-emptively detect > stack overflow for the next call into non-recursive code without relying > on SIGSEGV (you'd still want the SIGSEGV handler for the recursive part, > but can now longjmp back to your non-recursive outer handler). But it > is not practical, and would mean a complete rewrite of the bash source > code, and probably even a parallel stripped-down rewrite of glibc. > > In many cases, it is also possible to convert recursive code into > iterative code; but usually, conversions like this involve trade-offs, > such as requiring heap storage to track progress between iterations > where the old code used the stack. Again, doing such conversions to the > bash code base would mean a complete rewrite. And such a conversion is > worthwhile only if everything doable in one leg of the recursion is > known up front - but bash is a scripting language and can't predict what > all user input code will want to do at each level of recursion, short of > executing the script. > > > > >> So why I should got SIGSEGV instead of nice, detailed error message in > >>> recursion? We can detect it? > >> > >> GNU libsigsegv proves that it is possible to detect when SIGSEGV was > >> caused by stack overflow. It can't help prevent stack overflow, and you > >> _don't_ want to penalize your code by adding checking code into the > >> common case (if I'm about to overflow, error out instead), but leave > >> stack overflow as the exceptional case (if I've already overflowed and > >> received SIGSEGV, convert it into a nice error message to the user > >> before exiting cleanly, instead of the default behavior of dumping > >> core). But someone would have to write the patch for bash to link > >> against libsigsegv. > >> > > I undestand it. It better than getting SIGSEGV, but not a solution for > this > > issue. As I think. > > It's not clear what issue you think needs solving. > > If you are trying to solve the issue of "prevent all possible SIGSEGV > from stack overflow", the answer is "it's impossible". > > If you are trying to solve the issue of "bash dumps core based on user > input, but I'd prefer a nice error message telling me my program is > buggy", the answer is "write a patch to use libsigsegv". > > If you are trying to solve the issue of "bash needs to give me a way to > optionally artificially limit source recursion, so that I reduce the set > of programs that can be run, but am less likely to trigger stack > overflow", the answer is "write a patch to copy (or reuse) FUNCNEST > limitations when sourcing" - but such a solution will not be on by > default. Which means that you will only know if the solution makes a > difference for your program if you first run the program unlimited - but > then you are back to the earlier question of whether bash can give a > nice error message instead of a core dump when exiting due to stack > overflow.
Perfect BUG solving. Thank you for "support".