From: arnej@kari.fm.unit.no (Arne Henrik Juul)
Subject: FIX: Bash bombs on Meta-B on Cray
Followup-To: gnu.bash.bug
Keywords: bash,cray,bug
Reply-To: arnej@lise.unit.no
Organization: Norwegian Institute of Technology
Distribution: gnu
Date: Thu, 10 Sep 1992 18:48:06 GMT

After some debugging, I have found the cause for the bug that was
posted here recently, which caused bash to fail on certain commands.

The problem is in the readline code: It uses a common field in its
keymap entry structure to refer to both a new keymap (for ESC
commands, Control-X commands etc.) and a function (for normal keys).
But this is *not* done as a union, because it then becomes difficult
(maybe impossible) to initalize in the way wanted, as the comment in
the keymaps.h file says:

typedef struct _keymap_entry {
  char type;
  Function *function;
} KEYMAP_ENTRY;

/* I wanted to make the above structure contain a union of:
   union { Function *function; struct _keymap_entry *keymap; } value;
   but this made it impossible for me to create a static array.
   Maybe I need C lessons. */

The function field is also used as a Keymap variable (really a
(struct _keymap_entry *)) in various places, and it is initalized by
taking a KEYMAP_ENTRY_ARRAY and just casting it to (Function *).
When it is again used (in rl_dispatch) it is cast back to (Keymap).

On the Cray, this just does not work properly, and I'm not sure if it
is required to - casting between pointer to structure and pointer to
function and back is not very clean. The net effect is that the
pointer is divided by four, as far as I can see. This makes bash jump
off into never-never land, quite literally, by following a bogus
(Function *) pointer.

The easy workaround is just to add another field to the struct
_keymap_entry, like this:

typedef struct _keymap_entry {
  char type;
  Function *function;
  struct _keymap_entry *map;
} KEYMAP_ENTRY;


This wastes some space (but who cares about 60KB on the Cray :-), but
it works. The real problem is to find all occurences of
(something).function and find out if it needs to be replaced with
-----------.map.  I have done this some places, but I may have missed
some.

There may be a related problem with the macro stuff which *also* seems
to overload the same field, but I didn't worry about that for now - I
don't use macros in bash anyway :-)

At the end find enclosed my current diffs for this problem, use at own
risk, warranty void if used, totally untested etc.

Regards,

Arne H. Juul  --  arnej@lise.unit.no  --  University of Trondheim, Norway


diff -rc bash-1.12.dist/lib/readline/emacs_keymap.c bash-1.12.ok/lib/readline/emacs_keymap.c
*** bash-1.12.dist/lib/readline/emacs_keymap.c	Tue Jul  9 13:10:28 1991
--- bash-1.12.ok/lib/readline/emacs_keymap.c	Thu Sep 10 04:54:33 1992
***************
*** 56,65 ****
    { ISFUNC, rl_unix_line_discard },	/* Control-u */
    { ISFUNC, rl_quoted_insert },		/* Control-v */
    { ISFUNC, rl_unix_word_rubout },	/* Control-w */
!   { ISKMAP, (Function *)emacs_ctlx_keymap },	/* Control-x */
    { ISFUNC, rl_yank },			/* Control-y */
    { ISFUNC, (Function *)0x0 },		/* Control-z */
!   { ISKMAP, (Function *)emacs_meta_keymap }, /* Control-[ */
    { ISFUNC, (Function *)0x0 },		/* Control-\ */
    { ISFUNC, (Function *)0x0 },		/* Control-] */
    { ISFUNC, (Function *)0x0 },		/* Control-^ */
--- 56,65 ----
    { ISFUNC, rl_unix_line_discard },	/* Control-u */
    { ISFUNC, rl_quoted_insert },		/* Control-v */
    { ISFUNC, rl_unix_word_rubout },	/* Control-w */
!   { ISKMAP, 0, emacs_ctlx_keymap },	/* Control-x */
    { ISFUNC, rl_yank },			/* Control-y */
    { ISFUNC, (Function *)0x0 },		/* Control-z */
!   { ISKMAP, 0, emacs_meta_keymap },     /* Control-[ */
    { ISFUNC, (Function *)0x0 },		/* Control-\ */
    { ISFUNC, (Function *)0x0 },		/* Control-] */
    { ISFUNC, (Function *)0x0 },		/* Control-^ */
diff -rc bash-1.12.dist/lib/readline/keymaps.c bash-1.12.ok/lib/readline/keymaps.c
*** bash-1.12.dist/lib/readline/keymaps.c	Sun Aug  4 18:54:07 1991
--- bash-1.12.ok/lib/readline/keymaps.c	Thu Sep 10 04:55:20 1992
***************
*** 120,126 ****
  	  break;
  
  	case ISKMAP:
! 	  rl_discard_keymap ((Keymap)map[i].function);
  	  break;
  
  	case ISMACR:
--- 120,126 ----
  	  break;
  
  	case ISKMAP:
! 	  rl_discard_keymap (map[i].map);
  	  break;
  
  	case ISMACR:
diff -rc bash-1.12.dist/lib/readline/keymaps.h bash-1.12.ok/lib/readline/keymaps.h
*** bash-1.12.dist/lib/readline/keymaps.h	Tue Jul  9 13:10:30 1991
--- bash-1.12.ok/lib/readline/keymaps.h	Thu Sep 10 04:53:40 1992
***************
*** 18,23 ****
--- 18,24 ----
  typedef struct _keymap_entry {
    char type;
    Function *function;
+   struct _keymap_entry *map;
  } KEYMAP_ENTRY;
  
  /* I wanted to make the above structure contain a union of:
diff -rc bash-1.12.dist/lib/readline/vi_keymap.c bash-1.12.ok/lib/readline/vi_keymap.c
*** bash-1.12.dist/lib/readline/vi_keymap.c	Tue Jul  9 13:10:32 1991
--- bash-1.12.ok/lib/readline/vi_keymap.c	Thu Sep 10 04:57:56 1992
***************
*** 59,65 ****
    { ISFUNC, rl_yank },			/* Control-y */
    { ISFUNC, (Function *)0x0 },		/* Control-z */
  
!   { ISKMAP, (Function *)vi_escape_keymap }, /* Control-[ */
    { ISFUNC, (Function *)0x0 },		/* Control-\ */
    { ISFUNC, (Function *)0x0 },		/* Control-] */
    { ISFUNC, (Function *)0x0 },		/* Control-^ */
--- 59,65 ----
    { ISFUNC, rl_yank },			/* Control-y */
    { ISFUNC, (Function *)0x0 },		/* Control-z */
  
!   { ISKMAP, 0, vi_escape_keymap }, /* Control-[ */
    { ISFUNC, (Function *)0x0 },		/* Control-\ */
    { ISFUNC, (Function *)0x0 },		/* Control-] */
    { ISFUNC, (Function *)0x0 },		/* Control-^ */
*** bash-1.12.dist/lib/readline/readline.c	Sun Jan 26 19:31:11 1992
--- bash-1.12.ok/lib/readline/readline.c	Thu Sep 10 21:31:08 1992
***************
*** 844,850 ****
      {
        if (map[ESC].type == ISKMAP)
  	{
! 	  map = (Keymap)map[ESC].function;
  	  key -= 128;
  	  rl_dispatch (key, map);
  	}
--- 844,850 ----
      {
        if (map[ESC].type == ISKMAP)
  	{
! 	  map = map[ESC].map;
  	  key -= 128;
  	  rl_dispatch (key, map);
  	}
***************
*** 885,897 ****
        break;
  
      case ISKMAP:
!       if (map[key].function != (Function *)NULL)
  	{
  	  int newkey;
  
  	  rl_key_sequence_length++;
  	  newkey = rl_read_key ();
! 	  rl_dispatch (newkey, (Keymap)map[key].function);
  	}
        else
  	{
--- 885,897 ----
        break;
  
      case ISKMAP:
!       if (map[key].map != NULL)
  	{
  	  int newkey;
  
  	  rl_key_sequence_length++;
  	  newkey = rl_read_key ();
! 	  rl_dispatch (newkey, map[key].map);
  	}
        else
  	{
***************
*** 5312,5318 ****
      {
        if (keymap[ESC].type == ISKMAP)
  	{
! 	  Keymap escmap = (Keymap)keymap[ESC].function;
  
  	  key -= 128;
  	  escmap[key].type = ISFUNC;
--- 5312,5318 ----
      {
        if (keymap[ESC].type == ISKMAP)
  	{
! 	  Keymap escmap = keymap[ESC].map;
  
  	  key -= 128;
  	  escmap[key].type = ISFUNC;
***************
*** 5435,5443 ****
  		free ((char *)map[i].function);
  
  	      map[keys[i]].type = ISKMAP;
! 	      map[keys[i]].function = (Function *)rl_make_bare_keymap ();
  	    }
! 	  map = (Keymap)map[keys[i]].function;
  	}
        else
  	{
--- 5435,5443 ----
  		free ((char *)map[i].function);
  
  	      map[keys[i]].type = ISKMAP;
! 	      map[keys[i]].map = rl_make_bare_keymap ();
  	    }
! 	  map = map[keys[i]].map;
  	}
        else
  	{
***************
*** 6131,6139 ****
  
  	    /* Find the list of keyseqs in this map which have FUNCTION as
  	       their target.  Add the key sequences found to RESULT. */
! 	    if (map[key].function)
  	      seqs =
! 		invoking_keyseqs_in_map (function, (Keymap)map[key].function);
  
  	    if (seqs)
  	      {
--- 6131,6139 ----
  
  	    /* Find the list of keyseqs in this map which have FUNCTION as
  	       their target.  Add the key sequences found to RESULT. */
! 	    if (map[key].map)
  	      seqs =
! 		invoking_keyseqs_in_map (function, map[key].map);
  
  	    if (seqs)
  	      {

Newsgroups: gnu.bash.bug