Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6238699

Intermittent PatternSyntaxException on String#replaceAll with multiple threads

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P4 P4
    • None
    • 1.4.2
    • core-libs

      FULL PRODUCT VERSION :
      1.4.2_02

      ADDITIONAL OS VERSION INFORMATION :
      Windows 2003 Server

      A DESCRIPTION OF THE PROBLEM :
      Given the program

      public class PatternProblem {
        
        private static Pattern pattern=null;
       
        public static void main(String[] args) throws InterruptedException {
          int threads = Integer.parseInt(args[0]);
          int loadPattern = Integer.parseInt(args[1]);
          if(loadPattern==1) {
            pattern = Pattern.compile("^\\p{Digit}");
          }
          TestThread[] tt = new TestThread [threads];
          for (int i = 0; i < tt.length; i++) {
            tt[i] = new TestThread();
          }
          for (int i = 0; i < tt.length; i++) {
            tt[i].start();
          }
          for (int i = 0; i < tt.length; i++) {
            tt[i].join();
          }
        }
      }
       
      class TestThread extends Thread {

        public void run () {
          String str = "1LALA";
          try {
            str = str.replaceAll("^\\p{Digit}", "R");
            str = str.replaceAll("[^\\p{Lower}\\p{Upper}\\p{Digit}]", "_");
          } catch (Exception e) {
            System.out.println(this.getName()+":"+e.getMessage());
          }
        }
       
      }

      regular PatternSyntaxException are returned when started with e.g. 10 threads and 0 for the loadPattern argument. on a multiprocessor machine.
      When starting with loadPattern 1 the exception is never thrown.

      This seems to trace back to the following JDK code (java.util.regex.Pattern)

      private Node retrieveCategoryNode(String name) {
              if (categories == null) {
                  int cns = categoryNodes.length;
                  categories = new HashMap((int)(cns/.75) + 1);
                  for (int x=0; x<cns; x++)
                      categories.put(categoryNames[x], categoryNodes[x]);
              }
              Node n = (Node)categories.get(name);
              if (n != null)
                  return n;
       
              return familyError(name, "Unknown character category {");
          }
      ...
         static HashMap categories = null;
      ...

      THe initialization of the static categories HashMap is not protected which sometimes gives issues in a multithreaded application on a multiprocessor machine.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Execute the repro on a multiprocessor machine with with 10 for the first and 0 for the second run time argument.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No PatternSyntaxException
      ACTUAL -
      Intermittent PatternSyntaxException

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Stack trace as in
      java.util.regex.PatternSyntaxException: Unknown character category {Digit} near index 9
      ^\p{Digit}
      ^
      at java.util.regex.Pattern.error(Unknown Source)
      at java.util.regex.Pattern.familyError(Unknown Source)
      at java.util.regex.Pattern.retrieveCategoryNode(Unknown Source)
      at java.util.regex.Pattern.family(Unknown Source)
      at java.util.regex.Pattern.sequence(Unknown Source)
      at java.util.regex.Pattern.expr(Unknown Source)
      at java.util.regex.Pattern.compile(Unknown Source)
      at java.util.regex.Pattern.<init>(Unknown Source)
      at java.util.regex.Pattern.compile(Unknown Source)
      at java.lang.String.replaceAll(Unknown Source)


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.util.regex.Pattern;



      public class PatternProblem {
        
        private static Pattern pattern=null;

        public static void main(String[] args) throws InterruptedException {
          int threads = Integer.parseInt(args[0]);
          int loadPattern = Integer.parseInt(args[1]);
          if(loadPattern==1) {
            pattern = Pattern.compile("^\\p{Digit}");
          }
          TestThread[] tt = new TestThread [threads];
          for (int i = 0; i < tt.length; i++) {
            tt[i] = new TestThread();
          }
          for (int i = 0; i < tt.length; i++) {
            tt[i].start();
          }
          for (int i = 0; i < tt.length; i++) {
            tt[i].join();
          }
        }
      }

      class TestThread extends Thread {

        public void run () {
          String str = "1LALA";
          try {
            str = str.replaceAll("^\\p{Digit}", "R");
            str = str.replaceAll("[^\\p{Lower}\\p{Upper}\\p{Digit}]", "_");
          } catch (Exception e) {
            System.out.println(this.getName()+":"+e.getMessage());
          }
        }

      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Adding
         pattern = Pattern.compile("^\\p{Digit}");
      to the main thread before other threads are started
      ###@###.### 2005-03-10 09:23:36 GMT

            sherman Xueming Shen
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: