[comp.bugs.sys5] Bug in "comm" utility

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/13/89)

As you can see in the excerpt below, the UNIX "comm" utility makes a
non-portable assumption about pointer arithmetic in its compare() function.
Here is the quick fix I devised for the UNIX System V Release 2.0 source;
other versions of "comm" appear to be similar.

static char sccsid[] = "@(#)comm.c	1.2";
...
main(argc,argv)
char **argv;
{
	int	l;
	char	xlb1[LB+1],xlb2[LB+1];	/* DAG: allow for -- in compare() */
#define	lb1	(&xlb1[1])
#define	lb2	(&xlb2[1])
...
compare(a,b)
char *a,*b;
{
	register char *ra,*rb;

	ra = --a;
	rb = --b;
...

maart@cs.vu.nl (Maarten Litmaath) (06/15/89)

gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
[quick kludge deleted, sorry Doug]

Why didn't you change compare()? The new version should be faster too!

/*
 * old version
 */
compare(a,b)
char *a,*b;
{
	register char *ra,*rb;

	/*
	 * it's non-portable to move a pointer one position before the begin
	 * of the array: on segmented architectures &array[0] could be the
	 * start of a segment
	 */
	ra = --a;
	rb = --b;
	while(*++ra == *++rb)		/* pre-increment instructions?! */
		if(*ra == '\0')
			return(0);
	if(*ra < *rb)
		return(1);
	return(2);
}


/*
 * new version - according to the ANSI standard a pointer may be moved one
 * position PAST the end of the array
 */
int	compare(a, b)
char	*a, *b;
{
	register char	*ra, *rb;

	ra = a;
	rb = b;

	while (*ra == *rb++)		/* post-increment instructions!! */
		if (!*ra++)
			return 0;

	return *ra < *--rb ? 1 : 2;
}
-- 
"I HATE arbitrary limits, especially when |Maarten Litmaath @ VU Amsterdam:
   they're small."  (Stephen Savitzky)    |maart@cs.vu.nl, mcvax!botter!maart