Well, I guess I've figured this one out... The bug was in readline-4.3. I'm attaching patches for both bash-2.05b-5 and readline-4.3-1 (nearly identical). There is a *long* description of the bug and the fix below for those who are interested, feel free to skip. Igor
On Wed, 2 Oct 2002, Igor Pechtchanski wrote: > Hey, as long as we're shifting the blame, let's shift it correctly ;-) > Details below... > > On Tue, 1 Oct 2002, Jelks Cabaniss wrote: > > > Igor Pechtchanski wrote: > > > > > > > As for the Ctrl-Left, this is something odd in bash. I > > > > > can get the same behavior in a command window running bash, > > > > > or even by typing Esc O c. Bash running on Linux does not > > > > > seem to have this problem. > > > > I wrote, speaking about CTRL+Left: > > > > > > Here it crashes rxvt, but not the bash console. WinXP. > > > > > I can confirm Esc O c crashing a bash command window on Win2k SP2. > > > Seems like Esc O <anything> kills bash... > > > > Ah, you're right! CTRL+Left doesn't crash bash here, but Esc O c sends > > it flying out the window in flames. > > > > /Jelks > > This actually seems to be a readline bug. Bash dies with a SIGSEGV > because of an infinite recursion in _rl_dispatch_subseq() in the readline > library. I've included a transcript of a gdb session below. The keys > pressed were '<Esc> O <space>'. I'm going to try to debug it tomorrow, > but if anyone more familiar with the readline library wants to take a shot > at it earlier, it's fine with me. :-) > > [snip] > > $ gdb -nw ./bash.exe > GNU gdb 5.0 (20010428-3) > [snip] > (gdb) run -i > Starting program: ./bash.exe -i > [snip] > Program received signal SIGSEGV, Segmentation fault. > 0x0045bfc7 in _rl_dispatch_subseq (key=256, map=0x10028188, got_subseq=0) > at readline.c:529 > 529 return _rl_dispatch_subseq (key, map, 0); > (gdb) where > #0 0x0045bfc7 in _rl_dispatch_subseq (key=256, map=0x10028188, got_subseq=0) > at readline.c:529 > #1 0x0045bfbc in _rl_dispatch (key=256, map=0x10028188) at readline.c:529 > #2 0x0045c0a4 in _rl_dispatch_subseq (key=256, map=0x10028188, got_subseq=0) > at readline.c:570 > #3 0x0045bfbc in _rl_dispatch (key=256, map=0x10028188) at readline.c:529 > #4 0x0045c0a4 in _rl_dispatch_subseq (key=256, map=0x10028188, got_subseq=0) > at readline.c:570 > #5 0x0045bfbc in _rl_dispatch (key=256, map=0x10028188) at readline.c:529 > [ Zillions of identical frames here ] > ---Type <return> to continue, or q <return> to quit---q > Quit > [snip] > (gdb) q > The program is running. Exit anyway? (y or n) y > $ Description of the bug and the fix (long and overly technical, feel free to skip): Readline has a mechanism for allowing two mappings where one is a prefix of another, e.g., from .inputrc: "ABCD": dump-variables "A": dump-functions The idea is that if it encounters a prefix of the longer pattern, readline will keep reading characters until it either matches the pattern (in which case it simply executes the mapping) or sees it diverge (in which case it backtracks and executes the mapping for the shorter pattern, and then reinterprets all pending characters). Readline accomplishes that by keeping a "default" map entry in which it stores the target of the shorter mapping. If it encounters a character for which there is no continuation in the sequence, it will use this "default" entry to try to match a shorter sequence or to backtrack. Readline also has a special mapping called rl_do_lowercase_version, which simply redirects the mapping to that of the lowercase letter. This is useful for keeping Meta-a and Meta-A in sync, but doesn't work too well if it's the saved "default" mapping. What readline tried to do is convert the "default" key value to lowercase (which, of course, returned the same value) and try to dispatch on that, which resulted in an infinite loop. The fix is to check whether the default action is rl_do_lowercase_version, and if it is, dispatch explicitly on the lowercase of the current key. This is a bit kludgy, in that it actually does an extra evaluation of the mapping, probably breaking the encapsulation, and certainly duplicating code... If anyone can think of a more elegant solution, I'd be happy. If not, this'll work. Oh, and IMO the default empty mapping created by rl_make_bare_keymap() incorrectly set all entries for capital letters to rl_do_lowercase_version (which is wrong for most mappings), so I fixed that in this patch as well. Well, that's it, sorry for the rant. Igor -- http://cs.nyu.edu/~pechtcha/ |\ _,,,---,,_ [EMAIL PROTECTED] ZZZzz /,`.-'`' -. ;-;;,_ [EMAIL PROTECTED] |,4- ) )-,_. ,\ ( `'-' Igor Pechtchanski '---''(_/--' `-'\_) fL a.k.a JaguaR-R-R-r-r-r-.-.-. Meow! "Water molecules expand as they grow warmer" (C) Popular Science, Oct'02, p.51
--- ./lib/readline/keymaps.c-orig 2002-10-02 20:12:04.000000000 -0400 +++ ./lib/readline/keymaps.c 2002-10-02 20:49:37.000000000 -0400 @@ -64,11 +64,13 @@ rl_make_bare_keymap () keymap[i].function = (rl_command_func_t *)NULL; } +#if 0 for (i = 'A'; i < ('Z' + 1); i++) { keymap[i].type = ISFUNC; keymap[i].function = rl_do_lowercase_version; } +#endif return (keymap); } --- ./lib/readline/readline.c-orig 2002-10-02 18:47:06.000000000 -0400 +++ ./lib/readline/readline.c 2002-10-02 20:52:22.000000000 -0400 @@ -645,12 +645,24 @@ _rl_dispatch_subseq (key, map, got_subse r = _rl_dispatch_subseq (newkey, FUNCTION_TO_KEYMAP (map, key), got_subseq || map[ANYOTHERKEY].function); if (r == -2) - /* We didn't match anything, and the keymap we're indexed into - shadowed a function previously bound to that prefix. Call - the function. The recursive call to _rl_dispatch_subseq has - already taken care of pushing any necessary input back onto - the input queue with _rl_unget_char. */ - r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); + { + /* We didn't match anything, and the keymap we're indexed into + shadowed a function previously bound to that prefix. Call + the function. The recursive call to _rl_dispatch_subseq has + already taken care of pushing any necessary input back onto + the input queue with _rl_unget_char. */ +#if 0 + r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); +#else + Keymap m = FUNCTION_TO_KEYMAP (map, key); + int type = m[ANYOTHERKEY].type; + func = m[ANYOTHERKEY].function; + if (type == ISFUNC && func == rl_do_lowercase_version) + r = _rl_dispatch (_rl_to_lower (key), map); + else + r = _rl_dispatch (ANYOTHERKEY, m); +#endif + } else if (r && map[ANYOTHERKEY].function) { /* We didn't match (r is probably -1), so return something to
--- ./keymaps.c-orig 2002-10-02 21:37:55.000000000 -0400 +++ ./keymaps.c 2002-10-02 22:09:27.000000000 -0400 @@ -64,11 +64,13 @@ rl_make_bare_keymap () keymap[i].function = (rl_command_func_t *)NULL; } +#if 0 for (i = 'A'; i < ('Z' + 1); i++) { keymap[i].type = ISFUNC; keymap[i].function = rl_do_lowercase_version; } +#endif return (keymap); } --- ./readline.c-orig 2002-10-02 21:37:36.000000000 -0400 +++ ./readline.c 2002-10-02 22:09:37.000000000 -0400 @@ -645,12 +645,24 @@ _rl_dispatch_subseq (key, map, got_subse r = _rl_dispatch_subseq (newkey, FUNCTION_TO_KEYMAP (map, key), got_subseq || map[ANYOTHERKEY].function); if (r == -2) - /* We didn't match anything, and the keymap we're indexed into - shadowed a function previously bound to that prefix. Call - the function. The recursive call to _rl_dispatch_subseq has - already taken care of pushing any necessary input back onto - the input queue with _rl_unget_char. */ - r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); + { + /* We didn't match anything, and the keymap we're indexed into + shadowed a function previously bound to that prefix. Call + the function. The recursive call to _rl_dispatch_subseq has + already taken care of pushing any necessary input back onto + the input queue with _rl_unget_char. */ +#if 0 + r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key)); +#else + Keymap m = FUNCTION_TO_KEYMAP (map, key); + int type = m[ANYOTHERKEY].type; + func = m[ANYOTHERKEY].function; + if (type == ISFUNC && func == rl_do_lowercase_version) + r = _rl_dispatch (_rl_to_lower (key), map); + else + r = _rl_dispatch (ANYOTHERKEY, m); +#endif + } else if (r && map[ANYOTHERKEY].function) { /* We didn't match (r is probably -1), so return something to
-- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Bug reporting: http://cygwin.com/bugs.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/