[gnu.ghostscript.bug] ifelse doesn't save its context

hrp@boring.cray.com (Hal Peterson) (07/26/89)

I am using GhostScript 1.3 with the patches supplied by Tony Li and
snoopy's fix to interp.c.  My platform is an 8MB Sun 3/50 running
SunOS 3.5.  I am compiling with GCC 1.35.

The following short program demonstrates a bug in the implementation
of ifelse:

    %!
    % find the longest and widest strings in systemdict.
    % NOTE:  does not work in GhostScript 1.3.
    /tempWidest 0 def
    /tempLongest 0 def
    /tempString 64 string def
    systemdict {
	pop tempString cvs dup
	stringwidth pop round cvi dup tempWidest gt
	    { /tempWidest exch def }		% def not executed
	    { pop }
	ifelse
	length dup tempLongest gt		% length gets typecheck
	    { /tempLongest exch def }
	    { pop }
	ifelse
    } forall

The code for ifelse in interp() does not save the context of the proc
on the execution stack.  Most of the time this isn't a problem, since
the previous entry on the execution stack was an array; but inside of
the forall there can be a null on the estack, fooling the interpreter
into thinking it's done with the ifelse proc once it has finished the
exch; so the def never gets executed and the ostack is wrong,
resulting in a typecheck from length.

To fix it, I added an s_store_b to the ifelse code, and while I was at
it compressed the two nearly identical cases into one.

--
Hal Peterson			Domain:  hrp@cray.com
Cray Research			Old style:  hrp%cray.com@uc.msc.umn.edu
1440 Northland Dr.		UUCP:  uunet!cray!hrp
Mendota Hts, MN  55120  USA	Telephone:  +1 612 681 3145

========================================================================
*** interp-DIST.c	Wed Jul  5 17:41:44 1989
--- interp.c	Tue Jul 25 12:40:22 1989
***************
*** 282,292 ****
  		store_state(iesp);
  		iosp -= 3;
  		/* Open code "up" for the array case(s) */
! 		if ( iosp[1].value.index )	/* execute iosp[2] */
! 		   {	switch( r_type_xe(iosp + 2) )
  			   {
  			default:
! 				s_store_b(iesp, 1, iosp, 2);
  				iref = iesp + 1;
  				icount = 0;
  				goto top;
--- 282,296 ----
  		store_state(iesp);
  		iosp -= 3;
  		/* Open code "up" for the array case(s) */
! 		{	int which;
! 			if (iosp[1].value.index)
! 				which = 2;
! 			else
! 				which = 3;
! 			switch( r_type_xe(iosp + which) )
  			   {
  			default:
! 				s_store_b(iesp, 1, iosp, which);
  				iref = iesp + 1;
  				icount = 0;
  				goto top;
***************
*** 293,321 ****
  			case exec(t_array): ;
  			case exec(t_packedarray): ;
  			   }
! 			iref = iosp[2].value.refs;
! 			icount = iosp[2].size;
! 		   }
! 		else			/* execute iosp[3] */
! 		   {	switch( r_type_xe(iosp + 3) )
! 			   {
! 			default:
! 				s_store_b(iesp, 1, iosp, 3);
! 				iref = iesp + 1;
! 				icount = 0;
! 				goto top;
! 			case exec(t_array): ;
! 			case exec(t_packedarray): ;
  			   }
! 			iref = iosp[3].value.refs;
! 			icount = iosp[3].size;
! 		   }
! 		if ( --icount <= 0 )		/* <= 1 more elements */
! 		   {	if ( icount < 0 ) goto up;
! 		   }
! 		else
! 			iesp++;
! 		goto top;
  	case plain_exec(tx_op_le):
  		code = obj_compare(iosp, 2+1);
  		if ( code < 0 )
--- 297,313 ----
  			case exec(t_array): ;
  			case exec(t_packedarray): ;
  			   }
! 			iref = iosp[which].value.refs;
! 			icount = iosp[which].size;
! 			if ( --icount <= 0 )	/* <= 1 more elements */
! 			   {	if ( icount < 0 ) goto up;
  			   }
! 			else
! 			   {	iesp++;
! 				s_store_b(iesp, 0, iosp, which);
! 			   }
! 			goto top;
! 		}
  	case plain_exec(tx_op_le):
  		code = obj_compare(iosp, 2+1);
  		if ( code < 0 )