🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

1 total messages Started by Marc Ullman Wed, 05 Jul 1989 18:39
Bug in GNU Make - Improper handling of nested variable references
#96
Author: Marc Ullman
Date: Wed, 05 Jul 1989 18:39
88 lines
3194 bytes
			B U G    R E P O R T
			
	Program: GNU Make
	Version: 3.48
	Computer: Sun 3
	Operating System: SunOS 4.0.1
	Reported By: Marc Ullman (marc@sun-valley.stanford.edu)
	Date: July 5, 1989

gnumake has a bug with nested variable references when text strings contain
parentheses "(",")" and/or braces "{", "}" as the following example makefile
shows:

	SOURCES = src1.c src2.c src3.c
	LIB_NAME = testlib.a
	LIB_OBJS = ${SOURCES:%.c=$(LIB_NAME)(%.o)}

	all :
		@echo "$(LIB_OBJS)"
		
running gnumake on this file produces the following result:

        testlib.a(src1.o testlib.a(src2.o testlib.a(src3.o)
                        ^                ^
                        |                |
                        Missing parentheses

The bug results from an incorrect assumption in the function variable_expand()
in the file variable.c.  A fragment of this function is shown below:


	    /* Is there a variable reference inside the parens or braces?
	       If so, expand it before expanding the entire reference.  */

	    p1 = index (beg, closeparen);
	    if (p1 != 0)
	      p1 = lindex (beg, p1, '$');
	    if (p1 != 0)
	      {
		/* BEG now points past the opening paren or brace.
		   Count parens or braces until it is matched.  */
		int count = 0;
		for (p = beg; *p != '\0'; ++p)
		  {
		    if (*p == openparen)
		      ++count;
		    else if (*p == closeparen && --count < 0)
		      break;
		  }
		/* If count is >= 0, there were unmatched opening parens
		   or braces, so we go to the simple case of a variable name
		   such as `$($(a)'.  */
		if (count < 0)
		  {
		    char *name = expand_argument (beg, p);
		    p1 = concat ("$(", name, ")");
		    free (name);
		    name = expand_argument (p1, p1 + strlen (p1));
		    o = variable_buffer_output (o, name, strlen (name));
		    free (name);
		    break;
		  }
	      }
	      
The line 
	p1 = concat ("$(", name, ")");
	
blindly restores parentheses around the previously evaluated expression
rather than restoring the appropriate delimiters depending on the current
state of the variables "openparen" and "closeparen".  A possible fix is shown below:

	if (count < 0)
	  {
	    char var_start_str[3] = {'$', openparen, '\0' };  /* NEW */
	    char var_end_str[2] = {closeparen, '\0'};	      /* NEW */
	    char *name = expand_argument (beg, p);
	    p1 = concat (var_start_str, name, var_end_str); /* REVISED */
	    free (name);
	    name = expand_argument (p1, p1 + strlen (p1));
	    o = variable_buffer_output (o, name, strlen (name));
	    free (name);
	    break;
	 }

With this revision, the sample makefile shown above yields the desirerd result:

	testlib.a(src1.o) testlib.a(src2.o) testlib.a(src3.o)
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads