arrfab / rpms / glibc

Forked from rpms/glibc 4 years ago
Clone

Blame SOURCES/glibc-rh989862-2.patch

147e83
commit 9795a1801eb1a4f3ae6346e32666d3d05f006115
147e83
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
147e83
Date:   Sun Jun 30 20:45:05 2013 +0530
147e83
147e83
    Fall back to non-cached sequence traversal and comparison
147e83
    
147e83
    strcoll currently falls back to alloca if malloc fails, resulting in a
147e83
    possible stack overflow.  This patch implements sequence traversal and
147e83
    comparison without caching indeces and rules.
147e83
147e83
diff --git glibc-2.17-c758a686/string/strcoll_l.c glibc-2.17-c758a686/string/strcoll_l.c
147e83
index 1bb9e23..1be6874 100644
147e83
--- glibc-2.17-c758a686/string/strcoll_l.c
147e83
+++ glibc-2.17-c758a686/string/strcoll_l.c
147e83
@@ -55,6 +55,12 @@ typedef struct
147e83
   const USTRING_TYPE *us;	/* The string.  */
147e83
   int32_t *idxarr;		/* Array to cache weight indeces.  */
147e83
   unsigned char *rulearr;	/* Array to cache rules.  */
147e83
+  unsigned char rule;		/* Saved rule for the first sequence.  */
147e83
+  int32_t idx;			/* Index to weight of the current sequence.  */
147e83
+  int32_t save_idx;		/* Save looked up index of a forward
147e83
+				   sequence after the last backward
147e83
+				   sequence.  */
147e83
+  const USTRING_TYPE *back_us;	/* Beginning of the backward sequence.  */
147e83
 } coll_seq;
147e83
 
147e83
 /* Get next sequence.  The weight indeces are cached, so we don't need to
147e83
@@ -227,7 +233,191 @@ get_next_seq (coll_seq *seq, int nrules, const unsigned char *rulesets,
147e83
   seq->us = us;
147e83
 }
147e83
 
147e83
-/* Compare two sequences.  */
147e83
+/* Get next sequence.  Traverse the string as required.  This function does not
147e83
+   set or use any index or rule cache.  */
147e83
+static void
147e83
+get_next_seq_nocache (coll_seq *seq, int nrules, const unsigned char *rulesets,
147e83
+		      const USTRING_TYPE *weights, const int32_t *table,
147e83
+		      const USTRING_TYPE *extra, const int32_t *indirect,
147e83
+		      int pass)
147e83
+{
147e83
+#include WEIGHT_H
147e83
+  int val = seq->val = 0;
147e83
+  int len = seq->len;
147e83
+  size_t backw_stop = seq->backw_stop;
147e83
+  size_t backw = seq->backw;
147e83
+  size_t idxcnt = seq->idxcnt;
147e83
+  size_t idxmax = seq->idxmax;
147e83
+  int32_t idx = seq->idx;
147e83
+  const USTRING_TYPE *us = seq->us;
147e83
+
147e83
+  while (len == 0)
147e83
+    {
147e83
+      ++val;
147e83
+      if (backw_stop != ~0ul)
147e83
+	{
147e83
+	  /* The is something pushed.  */
147e83
+	  if (backw == backw_stop)
147e83
+	    {
147e83
+	      /* The last pushed character was handled.  Continue
147e83
+		 with forward characters.  */
147e83
+	      if (idxcnt < idxmax)
147e83
+		{
147e83
+		  idx = seq->save_idx;
147e83
+		  backw_stop = ~0ul;
147e83
+		}
147e83
+	      else
147e83
+		{
147e83
+		  /* Nothing anymore.  The backward sequence ended with
147e83
+		     the last sequence in the string.  Note that len is
147e83
+		     still zero.  */
147e83
+		  idx = 0;
147e83
+		  break;
147e83
+	        }
147e83
+	    }
147e83
+	  else
147e83
+	    {
147e83
+	      /* XXX Traverse BACKW sequences from the beginning of
147e83
+		 BACKW_STOP to get the next sequence.  Is ther a quicker way
147e83
+	         to do this?  */
147e83
+	      int i = backw_stop;
147e83
+	      us = seq->back_us;
147e83
+	      while (i < backw)
147e83
+		{
147e83
+		  int32_t tmp = findidx (&us, -1);
147e83
+		  idx = tmp & 0xffffff;
147e83
+		  i++;
147e83
+		}
147e83
+	      --backw;
147e83
+	      us = seq->us;
147e83
+	    }
147e83
+	}
147e83
+      else
147e83
+	{
147e83
+	  backw_stop = idxmax;
147e83
+	  int32_t prev_idx = idx;
147e83
+
147e83
+	  while (*us != L('\0'))
147e83
+	    {
147e83
+	      int32_t tmp = findidx (&us, -1);
147e83
+	      unsigned char rule = tmp >> 24;
147e83
+	      prev_idx = idx;
147e83
+	      idx = tmp & 0xffffff;
147e83
+	      idxcnt = idxmax++;
147e83
+
147e83
+	      /* Save the rule for the first sequence.  */
147e83
+	      if (__glibc_unlikely (idxcnt == 0))
147e83
+	        seq->rule = rule;
147e83
+
147e83
+	      if ((rulesets[rule * nrules + pass]
147e83
+		   & sort_backward) == 0)
147e83
+		/* No more backward characters to push.  */
147e83
+		break;
147e83
+	      ++idxcnt;
147e83
+	    }
147e83
+
147e83
+	  if (backw_stop >= idxcnt)
147e83
+	    {
147e83
+	      /* No sequence at all or just one.  */
147e83
+	      if (idxcnt == idxmax || backw_stop > idxcnt)
147e83
+		/* Note that len is still zero.  */
147e83
+		break;
147e83
+
147e83
+	      backw_stop = ~0ul;
147e83
+	    }
147e83
+	  else
147e83
+	    {
147e83
+	      /* We pushed backward sequences.  If the stream ended with the
147e83
+		 backward sequence, then we process the last sequence we
147e83
+		 found.  Otherwise we process the sequence before the last
147e83
+		 one since the last one was a forward sequence.  */
147e83
+	      seq->back_us = seq->us;
147e83
+	      seq->us = us;
147e83
+	      backw = idxcnt;
147e83
+	      if (idxmax > idxcnt)
147e83
+		{
147e83
+		  backw--;
147e83
+		  seq->save_idx = idx;
147e83
+		  idx = prev_idx;
147e83
+		}
147e83
+	      if (backw > backw_stop)
147e83
+		backw--;
147e83
+	    }
147e83
+	}
147e83
+
147e83
+      len = weights[idx++];
147e83
+      /* Skip over indeces of previous levels.  */
147e83
+      for (int i = 0; i < pass; i++)
147e83
+	{
147e83
+	  idx += len;
147e83
+	  len = weights[idx];
147e83
+	  idx++;
147e83
+	}
147e83
+    }
147e83
+
147e83
+  /* Update the structure.  */
147e83
+  seq->val = val;
147e83
+  seq->len = len;
147e83
+  seq->backw_stop = backw_stop;
147e83
+  seq->backw = backw;
147e83
+  seq->idxcnt = idxcnt;
147e83
+  seq->idxmax = idxmax;
147e83
+  seq->us = us;
147e83
+  seq->idx = idx;
147e83
+}
147e83
+
147e83
+/* Compare two sequences.  This version does not use the index and rules
147e83
+   cache.  */
147e83
+static int
147e83
+do_compare_nocache (coll_seq *seq1, coll_seq *seq2, int position,
147e83
+		    const USTRING_TYPE *weights)
147e83
+{
147e83
+  int seq1len = seq1->len;
147e83
+  int seq2len = seq2->len;
147e83
+  int val1 = seq1->val;
147e83
+  int val2 = seq2->val;
147e83
+  int idx1 = seq1->idx;
147e83
+  int idx2 = seq2->idx;
147e83
+  int result = 0;
147e83
+
147e83
+  /* Test for position if necessary.  */
147e83
+  if (position && val1 != val2)
147e83
+    {
147e83
+      result = val1 - val2;
147e83
+      goto out;
147e83
+    }
147e83
+
147e83
+  /* Compare the two sequences.  */
147e83
+  do
147e83
+    {
147e83
+      if (weights[idx1] != weights[idx2])
147e83
+	{
147e83
+	  /* The sequences differ.  */
147e83
+	  result = weights[idx1] - weights[idx2];
147e83
+	  goto out;
147e83
+	}
147e83
+
147e83
+      /* Increment the offsets.  */
147e83
+      ++idx1;
147e83
+      ++idx2;
147e83
+
147e83
+      --seq1len;
147e83
+      --seq2len;
147e83
+    }
147e83
+  while (seq1len > 0 && seq2len > 0);
147e83
+
147e83
+  if (position && seq1len != seq2len)
147e83
+    result = seq1len - seq2len;
147e83
+
147e83
+out:
147e83
+  seq1->len = seq1len;
147e83
+  seq2->len = seq2len;
147e83
+  seq1->idx = idx1;
147e83
+  seq2->idx = idx2;
147e83
+  return result;
147e83
+}
147e83
+
147e83
+/* Compare two sequences using the index cache.  */
147e83
 static int
147e83
 do_compare (coll_seq *seq1, coll_seq *seq2, int position,
147e83
 	    const USTRING_TYPE *weights)
147e83
@@ -334,57 +524,62 @@ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
147e83
   memset (&seq1, 0, sizeof (seq1));
147e83
   seq2 = seq1;
147e83
 
147e83
-  /* We need the elements of the strings as unsigned values since they
147e83
-     are used as indeces.  */
147e83
-  seq1.us = (const USTRING_TYPE *) s1;
147e83
-  seq2.us = (const USTRING_TYPE *) s2;
147e83
-
147e83
   if (! __libc_use_alloca ((s1len + s2len) * (sizeof (int32_t) + 1)))
147e83
     {
147e83
       seq1.idxarr = (int32_t *) malloc ((s1len + s2len) * (sizeof (int32_t) + 1));
147e83
-      seq2.idxarr = &seq1.idxarr[s1len];
147e83
-      seq1.rulearr = (unsigned char *) &seq2.idxarr[s2len];
147e83
-      seq2.rulearr = &seq1.rulearr[s1len];
147e83
-
147e83
-      if (seq1.idxarr == NULL)
147e83
-	/* No memory.  Well, go with the stack then.
147e83
-
147e83
-	   XXX Once this implementation is stable we will handle this
147e83
-	   differently.  Instead of precomputing the indeces we will
147e83
-	   do this in time.  This means, though, that this happens for
147e83
-	   every pass again.  */
147e83
-	goto try_stack;
147e83
-      use_malloc = true;
147e83
+
147e83
+      /* If we failed to allocate memory, we leave everything as NULL so that
147e83
+	 we use the nocache version of traversal and comparison functions.  */
147e83
+      if (seq1.idxarr != NULL)
147e83
+	{
147e83
+	  seq2.idxarr = &seq1.idxarr[s1len];
147e83
+	  seq1.rulearr = (unsigned char *) &seq2.idxarr[s2len];
147e83
+	  seq2.rulearr = &seq1.rulearr[s1len];
147e83
+	  use_malloc = true;
147e83
+	}
147e83
     }
147e83
   else
147e83
     {
147e83
-    try_stack:
147e83
       seq1.idxarr = (int32_t *) alloca (s1len * sizeof (int32_t));
147e83
       seq2.idxarr = (int32_t *) alloca (s2len * sizeof (int32_t));
147e83
       seq1.rulearr = (unsigned char *) alloca (s1len);
147e83
       seq2.rulearr = (unsigned char *) alloca (s2len);
147e83
     }
147e83
 
147e83
-  seq1.rulearr[0] = 0;
147e83
+  int rule = 0;
147e83
 
147e83
   /* Cache values in the first pass and if needed, use them in subsequent
147e83
      passes.  */
147e83
   for (int pass = 0; pass < nrules; ++pass)
147e83
     {
147e83
       seq1.idxcnt = 0;
147e83
+      seq1.idx = 0;
147e83
+      seq2.idx = 0;
147e83
       seq1.backw_stop = ~0ul;
147e83
       seq1.backw = ~0ul;
147e83
       seq2.idxcnt = 0;
147e83
       seq2.backw_stop = ~0ul;
147e83
       seq2.backw = ~0ul;
147e83
 
147e83
+      /* We need the elements of the strings as unsigned values since they
147e83
+	 are used as indeces.  */
147e83
+      seq1.us = (const USTRING_TYPE *) s1;
147e83
+      seq2.us = (const USTRING_TYPE *) s2;
147e83
+
147e83
       /* We assume that if a rule has defined `position' in one section
147e83
 	 this is true for all of them.  */
147e83
-      int position = rulesets[seq1.rulearr[0] * nrules + pass] & sort_position;
147e83
+      int position = rulesets[rule * nrules + pass] & sort_position;
147e83
 
147e83
       while (1)
147e83
 	{
147e83
-	  if (pass == 0)
147e83
+	  if (__glibc_unlikely (seq1.idxarr == NULL))
147e83
+	    {
147e83
+	      get_next_seq_nocache (&seq1, nrules, rulesets, weights, table,
147e83
+				    extra, indirect, pass);
147e83
+	      get_next_seq_nocache (&seq2, nrules, rulesets, weights, table,
147e83
+				    extra, indirect, pass);
147e83
+	    }
147e83
+	  else if (pass == 0)
147e83
 	    {
147e83
 	      get_next_seq (&seq1, nrules, rulesets, weights, table, extra,
147e83
 			    indirect);
147e83
@@ -411,10 +606,18 @@ STRCOLL (const STRING_TYPE *s1, const STRING_TYPE *s2, __locale_t l)
147e83
 	      goto free_and_return;
147e83
 	    }
147e83
 
147e83
-	  result = do_compare (&seq1, &seq2, position, weights);
147e83
+	  if (__glibc_unlikely (seq1.idxarr == NULL))
147e83
+	    result = do_compare_nocache (&seq1, &seq2, position, weights);
147e83
+	  else
147e83
+	    result = do_compare (&seq1, &seq2, position, weights);
147e83
 	  if (result != 0)
147e83
 	    goto free_and_return;
147e83
 	}
147e83
+
147e83
+      if (__glibc_likely (seq1.rulearr != NULL))
147e83
+	rule = seq1.rulearr[0];
147e83
+      else
147e83
+	rule = seq1.rule;
147e83
     }
147e83
 
147e83
   /* Free the memory if needed.  */