1 /*
   2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.PrintWriter;
  25 import java.io.StringWriter;
  26 import java.util.ArrayList;
  27 import java.util.List;
  28 import java.util.regex.Matcher;
  29 import java.util.regex.Pattern;
  30 
  31 /*
  32  * @test
  33  * @bug 8038414
  34  * @summary Constant pool's strings are not escaped properly
  35  * @modules jdk.compiler
  36  */
  37 public class T8038414 {
  38     private static final String NEW_LINE = System.getProperty("line.separator");
  39     private static final String TEST_CLASSES = System.getProperty("test.classes", ".");
  40     private static final String GOLDEN_STRING = escapeString(Test.test);
  41 
  42     private static String escapeString(String s) {
  43         StringBuilder sb = new StringBuilder();
  44         for (int i = 0; i < s.length(); i++) {
  45             char c = s.charAt(i);
  46             switch (c) {
  47                 case '\t':
  48                     sb.append('\\').append('t');
  49                     break;
  50                 case '\n':
  51                     sb.append('\\').append('n');
  52                     break;
  53                 case '\r':
  54                     sb.append('\\').append('r');
  55                     break;
  56                 case '\b':
  57                     sb.append('\\').append('b');
  58                     break;
  59                 case '\f':
  60                     sb.append('\\').append('f');
  61                     break;
  62                 case '\"':
  63                     sb.append('\\').append('\"');
  64                     break;
  65                 case '\'':
  66                     sb.append('\\').append('\'');
  67                     break;
  68                 case '\\':
  69                     sb.append('\\').append('\\');
  70                     break;
  71                 default:
  72                     sb.append(c);
  73             }
  74         }
  75         return sb.toString();
  76     }
  77 
  78     public static void main(String... args) {
  79         new T8038414().run();
  80     }
  81 
  82     public void run() {
  83         String output = javap(Test.class.getName());
  84         List<String> actualValues = extractEscapedComments(output);
  85         for (String a : actualValues) {
  86             check(!GOLDEN_STRING.equals(a), String.format("Expected: %s, got: %s", GOLDEN_STRING, a));
  87         }
  88     }
  89 
  90     private List<String> extractConstantPool(String output) {
  91         List<String> cp = new ArrayList<>();
  92         boolean inCp = false;
  93         for (String s : output.split("\n")) {
  94             if (s.equals("{")) {
  95                 break;
  96             }
  97             if (inCp) {
  98                 cp.add(s);
  99             }
 100             if (s.equals("Constant pool:")) {
 101                 inCp = true;
 102             }
 103         }
 104         return cp;
 105     }
 106 
 107     /**
 108      * Returns a list which contains comments of the string entry in the constant pool
 109      * and the appropriate UTF-8 value.
 110      *
 111      * @return a list
 112      */
 113     private List<String> extractEscapedComments(String output) {
 114         List<String> result = new ArrayList<>();
 115         Pattern stringPattern = Pattern.compile(" +#\\d+ = String +#(\\d+) +// +(.*)");
 116         int index = -1;
 117         List<String> cp = extractConstantPool(output);
 118         for (String c : cp) {
 119             Matcher matcher = stringPattern.matcher(c);
 120             if (matcher.matches()) {
 121                 index = Integer.parseInt(matcher.group(1)) - 1;
 122                 result.add(matcher.group(2));
 123                 // only one String entry
 124                 break;
 125             }
 126         }
 127         check(index == -1, "Escaped string is not found in constant pool");
 128         result.add(cp.get(index).replaceAll(".* +", "")); // remove #16 = Utf8
 129         return result;
 130     }
 131 
 132     private String javap(String className) {
 133         StringWriter sw = new StringWriter();
 134         PrintWriter out = new PrintWriter(sw);
 135         int rc = com.sun.tools.javap.Main.run(new String[]{"-v", "-classpath", TEST_CLASSES, className}, out);
 136         out.close();
 137         String output = sw.toString();
 138         System.err.println("class " + className);
 139         System.err.println(output);
 140 
 141         check(rc != 0, "javap failed. rc=" + rc);
 142         return output.replaceAll(NEW_LINE, "\n");
 143     }
 144 
 145     private void check(boolean cond, String msg) {
 146         if (cond) {
 147             throw new RuntimeException(msg);
 148         }
 149     }
 150 
 151     static class Test {
 152         static String test = "\\t\t\b\r\n\f\"\'\\";
 153     }
 154 }