Path: csiph.com!goblin3!goblin1!goblin.stu.neva.ru!usenet.stanford.edu!not-for-mail From: Mike Gerwitz Newsgroups: gnu.bash.bug Subject: Re: Segfault on recursive trap/kill Date: Sun, 07 Oct 2018 01:53:39 -0400 Lines: 200 Approved: bug-bash@gnu.org Message-ID: References: <8736tj3llu.fsf@gnu.org> <25389056-9fcf-1d31-36d8-13098769a43a@case.edu> <874ldy1vka.fsf@gnu.org> <20181006210450465282080@bob.proulx.com> NNTP-Posting-Host: lists.gnu.org Mime-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha512; protocol="application/pgp-signature" X-Trace: usenet.stanford.edu 1538891869 11696 208.118.235.17 (7 Oct 2018 05:57:49 GMT) X-Complaints-To: action@cs.stanford.edu To: bug-bash@gnu.org Envelope-to: bug-bash@gnu.org In-Reply-To: <20181006210450465282080@bob.proulx.com> (Bob Proulx's message of "Sat, 6 Oct 2018 22:44:17 -0600") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.3 (gnu/linux) OpenPGP: id=22175B02E626BC98D7C0C2E5F22BB8158EE30EAB X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:4830:134:3::e X-BeenThere: bug-bash@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Bug reports for the GNU Bourne Again SHell List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Xref: csiph.com gnu.bash.bug:14694 --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hey, Bob! On Sat, Oct 06, 2018 at 22:44:17 -0600, Bob Proulx wrote: > Let me give the discussion this way and I think you will be > convinced. :-) Well, thanks for taking the time for such a long reply. :) > How is your example any different from a C program? Or Perl, Python, > Ruby, and so forth? All of those also allow infinite recursion and > the kernel will terminate them with a segfault. Because all of those > also allow infinite recursion. A program that executes an infinite > recursion would use infinite stack space. But real machines have a > finite amount of stack available and therefore die when the stack is > exceeded. I expect this behavior when writing in C, certainly. But in languages where the user does not deal with memory management, I'm used to a more graceful abort when the stack gets out of control. A segfault means something to a C hacker. It means very little to users who are unfamiliar with the concepts that you were describing. I don't have enough experience with Perl, Python, or Ruby to know how they handle stack issues. But, out of interest, I gave it a try: $ perl -e 'sub foo() { foo(); }; foo()' Out of memory! $ python <<< 'def foo(): > foo() >foo()' |& tail -n1 RuntimeError: maximum recursion depth exceeded $ ruby -e 'def foo() > foo() > end > foo()' -e:2: stack level too deep (SystemStackError) Some languages I'm more familiar with: $ node -e '(function foo() { foo(); })()' [eval]:1 (function foo() { foo(); })() ^ RangeError: Maximum call stack size exceeded $ php -r 'function foo() { foo(); } foo();' Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes) in Command line code on line 1 $ guile -e '(let x () (+ (x)))' allocate_stack failed: Cannot allocate memory Warning: Unwind-only `stack-overflow' exception; skipping pre-unwind hand= ler. $ emacs --batch --eval '(message (defun foo () (foo)) (foo))' Lisp nesting exceeds =E2=80=98max-lisp-eval-depth=E2=80=99 And so on. I understand that in C you usually don't manage your own stack and, consequently, you can't say that it falls under "memory management" in the sense of malloc(3) and brk(2) and such. But C programmers are aware of the mechanisms behind the stack (or at least better be) and won't be surprised when they get a segfault in this situation. But if one of my coworkers who knows some web programming and not much about system programming gets a segfault, that's not a friendly error. If Bash instead said something like the above languages, then that would be useful. When I first saw the error, I didn't know that my trap was recursing. My immediate reaction was "shit, I found a bug". Once I saw it was the trap, I _assumed_ it was just exhausting the stack, but I wanted to report it regardless, just in case; I didn't have the time to dig deeper, and even so, I wasn't sure if it was intended behavior to just let the kernel handle it. > This following complete C program recurses infinitely. Or at least > until the stack is exhausted. At which time it triggers a segfault > because it tries to use memory beyond the page mapped stack. [...] > Would you say that is a bug in the C language? A bug in gcc that > compiled it? A bug in the Unix/Linux kernel for memory management > that trapped the error? The parent shell that reported the exit code > of the program? Or in the program source code? I am hoping that we > will all agree that it is a bug in the program source code and not > either gcc or the kernel. :-) I agree, yes. > Shell script code is program source code. Infinite loops or infinite > recursion are bugs in the shell script source code not the interpreter > that is executing the code as written. I also agree. But the context is very different. Shell is a very, very high-level language. > This feels to me to be related to The Halting Problem. Knowing in advance whether there may be a problem certainly is, but we don't need to do that; we'd just need to detect it at runtime to provide a more useful error message. > Other shells are also fun to check: > > $ dash -c 'trap "kill 0" TERM; kill 0' > Segmentation fault > > $ ash -c 'trap "kill 0" TERM; kill 0' > Segmentation fault > > $ mksh -c 'trap "kill 0" TERM; kill 0' > Segmentation fault Heh, interesting! > $ ksh93 -c 'trap "kill 0" TERM; kill 0' > $ echo $? > 0 This is not the behavior I'd want. > $ posh -c 'trap "kill 0" TERM; kill 0' > Terminated > Terminated > Terminated > ... > Terminated > ^C :x > This finds what look like bugs in posh and ksh93. That's a fair assessment. >> it's just that most users assume that a segfault represents a >> problem with the program > > Yes. And here it indicates a bug too. It is indicating a bug in the > shell program code which sets up the infinite recursion. Programs > should avoid doing that. :-) Indeed they should, but inevitably, such bugs do happen, and mine was a particularly common pitfall: I was trying to set the variable from within a subprocess. But it wasn't in a subprocss when I originally wrote it. > The proper way for a program to terminate itself upon catching a > signal is to set the signal handler back to the default value and then > send the signal to itself so that it will be terminated as a result of > the signal and therefore the exit status will be set correctly. That's good advice. Thank you. > https://www.cons.org/cracauer/sigint.html Thanks. > Hope this helps! There was useful information, yes. I hope I was able to further clarify my concerns as well. =2D-=20 Mike Gerwitz --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCgAGBQJbuZ9kAAoJEIyRe39dxRuiPUEQAJsLEGl/30HQMAqOQD0Xlpgy KhJUVJ7oXhVGDutz7jostNMCfE1VUCfCoGDALpV+4pNWeBvto0+iqoe6sVLafPbs EpQk0P4OH8vOEgnBVlpyxmTc6+vTZuIfW9CVaied+1KHcqlso0vU52kF3UWa3Aqt 3W67dUE4KaZfjJPHF56YL/hc3HNU+4j1iONMLid7cCXT6jRnWqesXeN8mdy9yvT/ af6qSCp2z5zimv8mxYWm+eHGsCpjQc4f+CIIT+JShS7m6EUVRCnOw23iz1sEGi8n o/8EI2+Ga+GQeyyrZigy39EP+9v9PxhIgRxBCeL9scHjMWRRE69ywVYIIrHdsmdO pGREgxmBLCgF5nIhHbXRpy7eX5JOhzI4RTzKnQ/zHAu2Js33U9bE9fs+K4n4ciSC e+t5NoWSwk12dDvYi7rCDnA11G57FIhwN3OX+61HgGsXUNjOU7HrhIevZbbu27XJ ORzqGH3bKeaWYSb5LCovqf0t9RJ788y6J2iGEG2ntLV4OizUKrpCVzWyo1DC8WvC SmgNV0SpqoLi6Mx0/AXIvcgAZh/G1m0G5chCK2Lj9gL8J4xBSEDMcENymIa/Vo5u niVQJ8unIzqPl+EmFqJLkUmS8MuJAohrWkvNYYnDMpo8dyFKazwkPrpeOUbgKFQ0 YtvQ7L3mxg6B3HXLW+f+ =S3FE -----END PGP SIGNATURE----- --=-=-=--