From: dgb@galileo.phys.washington.edu (David Boulware)
Subject: regex bug?
Organization: GNUs Not Usenet
Distribution: gnu
Date: Wed, 19 Aug 1992 19:42:14 GMT

Line 2393ff of regex.c from the textutils-1.1 distribution follow.

The variable 'enough_memory' is a pointer to a boolean quantity; however after
the first couple of uses, 'enough_memory' is used where '*enough_memory' appears
to be correct. These places are marked by /*HERE*/ notations.
If this observation is in error, please let me know.

static boolean
verify_and_adjust_endlines (op_list, group_forward_match_status, 
			    bufp, enough_memory)
  op_list_type op_list;
    /* `duplicate' case needs this: which groups matched something;
        set when went fowards through the pattern.  */
  bits_list_type group_forward_match_status;	
  struct re_pattern_buffer *bufp;
  boolean *enough_memory;
{
  int this_op_offset;	/* Has to be type int because decrementing it.  */
  /* See comments for analogous variables used for '^' in regex_compile.  */

  bits_list_type level_match_status;
  unsigned current_level = 0;
  bits_list_type group_match_status;
  bits_list_type group_active_status;
  char *bend = bufp->buffer + bufp->used;
  char *previous_p = NULL;


  if (!(init_bits_list (&level_match_status) 
        && init_bits_list (&group_match_status)
        && init_bits_list (&group_active_status)))
    {
      *enough_memory = false;
      return true;
    }
  else
    *enough_memory = true;

  for (this_op_offset = op_list.avail - 1; this_op_offset >= 0; 
       this_op_offset--)  
    {
      char *p = bufp->buffer + op_list.offsets[this_op_offset];

      if (!enough_memory) /*HERE*/
        break;

      switch ((enum regexpcode) *p)
        {
          case endline:
          case endline_in_repeat:
          case endline_before_newline:
          case repeated_endline_before_newline:

           /* If the '$' must be at the pattern's end or else is
              in a trailing position.  */
	   
            if ((bufp->syntax & RE_ANCHORS_ONLY_AT_ENDS) 
                 ? p + 1 == bend
		 : ((bufp->syntax & RE_TIGHT_ALT)
                    ? p + 3 == bend  /* Would have two following no_ops.  */
                    : (*p == endline_before_newline
                       || *p == repeated_endline_before_newline
                       || no_levels_match_anything (level_match_status))))
	      {
                if ((enum regexpcode) *p == endline_in_repeat
                    || (enum regexpcode) *p == repeated_endline_before_newline)
                  if (bufp->syntax & RE_REPEATED_ANCHORS_AWAY)
                    *p = no_op;
    		  else
		    *p = endline;
		

                /* If this is a trailing '$' in an empty alternative.  */

                if ((bufp->syntax & RE_NO_EMPTY_ALTS)
	
                    /* If there's an alternation op right before this `$'.  */
                    && ((this_op_offset > 0 
			 && *(bufp->buffer 
	                      + op_list.offsets[this_op_offset - 1])
                            == jump_past_next_alt)
	
                     /* Or this `$' is the only thing in the first
                        alternative of more than one of them.  */
	
                        || ((this_op_offset == 0   /* It's first.  */
			     /* Or it's right after an open-group op.  */
                             || (this_op_offset > 0 
				 && *(bufp->buffer 
	                              + op_list.offsets[this_op_offset - 1])
                                    == start_memory)) 

                            /* And it's right before an alternation op.  */
	                    && previous_p != NULL 
                            && *previous_p == jump_past_next_alt)))
                  return false;
              }
	
            else if (bufp->syntax & RE_CONTEXT_INVALID_ANCHORS)
	      return false;

            else if (!(bufp->syntax & RE_CONTEXT_INDEP_ANCHORS))
              {
                p[0] = (char)exactn; 
                p[1] = (char)1;
                p[2] = '$';
              }
              
            break;


          /* Yes, start and stop_memory are switched because we're going
             backwards through the pattern!  */
    
          case stop_memory:
            increase_level (&current_level);

            if (!make_group_active (&group_active_status, p[1]))
	      enough_memory = false;	       /*HERE*/

            break;

          case start_memory:
            if (get_level_match_status (level_match_status, current_level))
              if (!set_next_lower_level (&level_match_status, current_level))
                  enough_memory = false; /*HERE*/
              else
                {
                  decrease_level (&current_level);
                  make_group_inactive (&group_active_status, p[1]);
                }
      
            break;               


          /* Hit an alternative.  */

          case jump_past_next_alt:
            if (lower_levels_match_nothing (level_match_status, current_level))
              clear_this_and_higher_levels (&level_match_status,current_level);

            break;

	  /* These below mean was followed by a repetition operator.  */
	  case no_op:
          case maybe_pop_jump:
	  case no_pop_jump_n:
	    if (bufp->syntax & RE_REPEATED_ANCHORS_AWAY)
              break;
          case charset:
	  case charset_not:
	  case wordchar:
	  case notwordchar:
	  case exactn:
          case anychar:
            if (!set_this_level (&level_match_status, current_level)
                || !set_match_status_of_active_groups (group_active_status,
                                                       &group_match_status))
              enough_memory = false;; /*HERE*/

            break;

	  case duplicate: 
            /* Only set level_match_status if this back reference
               refers to a nonempty group.  */

            if (get_group_match_status (group_forward_match_status, p[1]))
              if (!set_this_level (&level_match_status, current_level))
                enough_memory = false; /*HERE*/

            break;
                
          default: 
            printf ("Found an unknown operator %u in compiled pattern.\n", *p);
        }
      previous_p = p;
    }
  return true;
}

-- 
					David G. Boulware
					dgb@phys.washington.edu
					Physics Dept, FM-15
					University of Washington
					Seattle, WA 98195
					(206)-543-8591

Newsgroups: gnu.utils.bug