undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
492
test/langtools/tools/javac/6889255/T6889255.java
Normal file
492
test/langtools/tools/javac/6889255/T6889255.java
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
/*
|
||||
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6889255
|
||||
* @summary ClassReader does not read parameter names correctly
|
||||
* @modules jdk.compiler/com.sun.tools.javac.code
|
||||
* jdk.compiler/com.sun.tools.javac.file
|
||||
* jdk.compiler/com.sun.tools.javac.jvm
|
||||
* jdk.compiler/com.sun.tools.javac.util
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import javax.tools.StandardLocation;
|
||||
import com.sun.tools.javac.code.Flags;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Symtab;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import com.sun.tools.javac.code.Type.ClassType;
|
||||
import com.sun.tools.javac.code.TypeTag;
|
||||
import com.sun.tools.javac.file.JavacFileManager;
|
||||
import com.sun.tools.javac.jvm.ClassReader;
|
||||
import com.sun.tools.javac.util.Context;
|
||||
import com.sun.tools.javac.util.Names;
|
||||
|
||||
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
|
||||
|
||||
public class T6889255 {
|
||||
boolean testInterfaces = true;
|
||||
boolean testSyntheticMethods = true;
|
||||
|
||||
// The following enums control the generation of the test methods to be compiled.
|
||||
enum GenericKind {
|
||||
NOT_GENERIC,
|
||||
GENERIC
|
||||
};
|
||||
|
||||
enum ClassKind {
|
||||
CLASS("Clss"),
|
||||
INTERFACE("Intf"),
|
||||
ENUM("Enum");
|
||||
final String base;
|
||||
ClassKind(String base) { this.base = base; }
|
||||
};
|
||||
|
||||
enum NestedKind {
|
||||
/** Declare methods inside the outermost container. */
|
||||
NONE,
|
||||
/** Declare methods inside a container with a 'static' modifier. */
|
||||
NESTED,
|
||||
/** Declare methods inside a container without a 'static' modifier. */
|
||||
INNER,
|
||||
/** Declare methods inside a local class in an initializer. */
|
||||
INIT_LOCAL,
|
||||
/** Declare methods inside an anonymous class in an initializer. */
|
||||
INIT_ANON,
|
||||
/** Declare methods inside a local class in a method. */
|
||||
METHOD_LOCAL,
|
||||
/** Declare methods inside an anonymous class in a method. */
|
||||
METHOD_ANON
|
||||
};
|
||||
|
||||
enum MethodKind {
|
||||
ABSTRACT,
|
||||
CONSTRUCTOR,
|
||||
METHOD,
|
||||
STATIC_METHOD,
|
||||
BRIDGE_METHOD
|
||||
};
|
||||
|
||||
enum FinalKind {
|
||||
/** Method body does not reference external final variables. */
|
||||
NO_FINAL,
|
||||
/** Method body references external final variables. */
|
||||
USE_FINAL
|
||||
};
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
new T6889255().run();
|
||||
}
|
||||
|
||||
void run() throws Exception {
|
||||
genTest();
|
||||
|
||||
test("no-args", false);
|
||||
test("g", true, "-g");
|
||||
|
||||
if (errors > 0)
|
||||
throw new Exception(errors + " errors found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file containing lots of method definitions to be tested.
|
||||
* There are 3 sets of nested loops that generate the methods.
|
||||
* 1. The outermost set declares [generic] (class | interface | enum)
|
||||
* 2. The middle set declares [(nested | inner | anon | local)] class
|
||||
* 3. The innermost set declares
|
||||
* [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope]
|
||||
* Invalid combinations are filtered out.
|
||||
*/
|
||||
void genTest() throws Exception {
|
||||
BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));
|
||||
|
||||
// This interface is used to force bridge methods to be generated, by
|
||||
// implementing its methods with subtypes of Object
|
||||
out.write("interface Base {\n");
|
||||
out.write(" Object base_m1(int i1);\n");
|
||||
out.write(" Object base_m2(int i1);\n");
|
||||
out.write("}\n");
|
||||
|
||||
int outerNum = 0;
|
||||
// Outermost set of loops, to generate a top level container
|
||||
for (GenericKind outerGenericKind: GenericKind.values()) {
|
||||
for (ClassKind outerClassKind: ClassKind.values()) {
|
||||
if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM)
|
||||
continue;
|
||||
String outerClassName = outerClassKind.base + (outerNum++);
|
||||
String outerTypeArg = outerClassKind.toString().charAt(0) + "T";
|
||||
if (outerClassKind == ClassKind.CLASS)
|
||||
out.write("abstract ");
|
||||
out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName);
|
||||
if (outerGenericKind == GenericKind.GENERIC)
|
||||
out.write("<" + outerTypeArg + ">");
|
||||
if (outerClassKind == ClassKind.INTERFACE)
|
||||
out.write(" extends Base");
|
||||
else
|
||||
out.write(" implements Base");
|
||||
out.write(" {\n");
|
||||
if (outerClassKind == ClassKind.ENUM) {
|
||||
out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
|
||||
out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n");
|
||||
}
|
||||
// Middle set of loops, to generate an optional nested container
|
||||
int nestedNum = 0;
|
||||
int methodNum = 0;
|
||||
for (GenericKind nestedGenericKind: GenericKind.values()) {
|
||||
nextNestedKind:
|
||||
for (NestedKind nestedKind: NestedKind.values()) {
|
||||
// if the nested kind is none, there is no point iterating over all
|
||||
// nested generic kinds, so arbitarily limit it to just one kind
|
||||
if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC)
|
||||
continue;
|
||||
if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
|
||||
&& nestedGenericKind == GenericKind.GENERIC)
|
||||
continue;
|
||||
String indent = " ";
|
||||
boolean haveFinal = false;
|
||||
switch (nestedKind) {
|
||||
case METHOD_ANON: case METHOD_LOCAL:
|
||||
if (outerClassKind == ClassKind.INTERFACE)
|
||||
continue nextNestedKind;
|
||||
out.write(indent + "void m" + + (nestedNum++) + "() {\n");
|
||||
indent += " ";
|
||||
out.write(indent + "final int fi1 = 0;\n");
|
||||
haveFinal = true;
|
||||
break;
|
||||
case INIT_ANON: case INIT_LOCAL:
|
||||
if (outerClassKind == ClassKind.INTERFACE)
|
||||
continue nextNestedKind;
|
||||
out.write(indent + "{\n");
|
||||
indent += " ";
|
||||
break;
|
||||
}
|
||||
for (ClassKind nestedClassKind: ClassKind.values()) {
|
||||
if ((nestedGenericKind == GenericKind.GENERIC)
|
||||
&& (nestedClassKind == ClassKind.ENUM))
|
||||
continue;
|
||||
if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL
|
||||
|| nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)
|
||||
&& nestedClassKind != ClassKind.CLASS)
|
||||
continue;
|
||||
// if the nested kind is none, there is no point iterating over all
|
||||
// nested class kinds, so arbitarily limit it to just one kind
|
||||
if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS)
|
||||
continue;
|
||||
|
||||
ClassKind methodClassKind;
|
||||
String methodClassName;
|
||||
boolean allowAbstractMethods;
|
||||
boolean allowStaticMethods;
|
||||
switch (nestedKind) {
|
||||
case NONE:
|
||||
methodClassKind = outerClassKind;
|
||||
methodClassName = outerClassName;
|
||||
allowAbstractMethods = (outerClassKind == ClassKind.CLASS);
|
||||
allowStaticMethods = (outerClassKind != ClassKind.INTERFACE);
|
||||
break;
|
||||
case METHOD_ANON:
|
||||
case INIT_ANON:
|
||||
out.write(indent + "new Base() {\n");
|
||||
indent += " ";
|
||||
methodClassKind = ClassKind.CLASS;
|
||||
methodClassName = null;
|
||||
allowAbstractMethods = false;
|
||||
allowStaticMethods = false;
|
||||
break;
|
||||
default: { // INNER, NESTED, LOCAL
|
||||
String nestedClassName = "N" + nestedClassKind.base + (nestedNum++);
|
||||
String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T";
|
||||
out.write(indent);
|
||||
if (nestedKind == NestedKind.NESTED)
|
||||
out.write("static ");
|
||||
if (nestedClassKind == ClassKind.CLASS)
|
||||
out.write("abstract ");
|
||||
out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName);
|
||||
if (nestedGenericKind == GenericKind.GENERIC)
|
||||
out.write("<" + nestedTypeArg + ">");
|
||||
if (nestedClassKind == ClassKind.INTERFACE)
|
||||
out.write(" extends Base ");
|
||||
else
|
||||
out.write(" implements Base ");
|
||||
out.write(" {\n");
|
||||
indent += " ";
|
||||
if (nestedClassKind == ClassKind.ENUM) {
|
||||
out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
|
||||
out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n");
|
||||
}
|
||||
methodClassKind = nestedClassKind;
|
||||
methodClassName = nestedClassName;
|
||||
allowAbstractMethods = (nestedClassKind == ClassKind.CLASS);
|
||||
allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Innermost loops, to generate methods
|
||||
for (GenericKind methodGenericKind: GenericKind.values()) {
|
||||
for (FinalKind finalKind: FinalKind.values()) {
|
||||
for (MethodKind methodKind: MethodKind.values()) {
|
||||
// out.write("// " + outerGenericKind
|
||||
// + " " + outerClassKind
|
||||
// + " " + nestedKind
|
||||
// + " " + nestedGenericKind
|
||||
// + " " + nestedClassKind
|
||||
// + " " + methodGenericKind
|
||||
// + " " + finalKind
|
||||
// + " " + methodKind
|
||||
// + "\n");
|
||||
switch (methodKind) {
|
||||
case CONSTRUCTOR:
|
||||
if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
|
||||
break;
|
||||
if (methodClassKind != ClassKind.CLASS)
|
||||
break;
|
||||
if (finalKind == FinalKind.USE_FINAL && !haveFinal)
|
||||
break;
|
||||
out.write(indent);
|
||||
if (methodGenericKind == GenericKind.GENERIC) {
|
||||
out.write("<CT> " + methodClassName + "(CT c1, CT c2");
|
||||
} else {
|
||||
out.write(methodClassName + "(boolean b1, char c2");
|
||||
}
|
||||
if (finalKind == FinalKind.USE_FINAL) {
|
||||
// add a dummy parameter to avoid duplicate declaration
|
||||
out.write(", int i3) { int i = fi1; }\n");
|
||||
} else
|
||||
out.write(") { }\n");
|
||||
break;
|
||||
case ABSTRACT:
|
||||
if (!allowAbstractMethods)
|
||||
continue;
|
||||
// fallthrough
|
||||
case METHOD:
|
||||
if (finalKind == FinalKind.USE_FINAL && !haveFinal)
|
||||
break;
|
||||
out.write(indent);
|
||||
if (methodKind == MethodKind.ABSTRACT)
|
||||
out.write("abstract ");
|
||||
if (methodGenericKind == GenericKind.GENERIC)
|
||||
out.write("<MT> ");
|
||||
out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)");
|
||||
if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE)
|
||||
out.write(";\n");
|
||||
else {
|
||||
out.write(" {");
|
||||
if (finalKind == FinalKind.USE_FINAL)
|
||||
out.write(" int i = fi1;");
|
||||
out.write(" }\n");
|
||||
}
|
||||
break;
|
||||
case BRIDGE_METHOD:
|
||||
if (methodGenericKind == GenericKind.GENERIC)
|
||||
break;
|
||||
out.write(indent);
|
||||
// methods Base.base_m1 and Base.base_m2 are declared for the
|
||||
// benefit of bridge methods. They need to be implemented
|
||||
// whether or not a final variable is used.
|
||||
String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2");
|
||||
out.write("public String " + methodName + "(int i1)");
|
||||
if (methodClassKind == ClassKind.INTERFACE)
|
||||
out.write(";\n");
|
||||
else {
|
||||
out.write(" {");
|
||||
if (finalKind == FinalKind.USE_FINAL && haveFinal)
|
||||
out.write(" int i = fi1;");
|
||||
out.write(" return null; }\n");
|
||||
}
|
||||
break;
|
||||
case STATIC_METHOD:
|
||||
if (!allowStaticMethods)
|
||||
break;
|
||||
if (finalKind == FinalKind.USE_FINAL && !haveFinal)
|
||||
break;
|
||||
out.write(indent + "static ");
|
||||
if (methodGenericKind == GenericKind.GENERIC)
|
||||
out.write("<MT> ");
|
||||
out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {");
|
||||
if (finalKind == FinalKind.USE_FINAL)
|
||||
out.write(" int i = fi1;");
|
||||
out.write(" }\n");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nestedKind != NestedKind.NONE) {
|
||||
indent = indent.substring(0, indent.length() - 4);
|
||||
out.write(indent + "};\n");
|
||||
}
|
||||
}
|
||||
switch (nestedKind) {
|
||||
case METHOD_ANON: case METHOD_LOCAL:
|
||||
case INIT_ANON: case INIT_LOCAL:
|
||||
indent = indent.substring(0, indent.length() - 4);
|
||||
out.write(indent + "}\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write("}\n\n");
|
||||
}
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
void test(String testName, boolean expectNames, String... opts) throws Exception {
|
||||
System.err.println("Test " + testName
|
||||
+ ": expectNames:" + expectNames
|
||||
+ " javacOpts:" + Arrays.asList(opts));
|
||||
|
||||
File outDir = new File(testName);
|
||||
outDir.mkdirs();
|
||||
compile(outDir, opts);
|
||||
|
||||
Context ctx = new Context();
|
||||
JavacFileManager fm = new JavacFileManager(ctx, true, null);
|
||||
fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));
|
||||
Symtab syms = Symtab.instance(ctx);
|
||||
ClassReader cr = ClassReader.instance(ctx);
|
||||
cr.saveParameterNames = true;
|
||||
Names names = Names.instance(ctx);
|
||||
|
||||
Set<String> classes = getTopLevelClasses(outDir);
|
||||
Deque<String> work = new LinkedList<String>(classes);
|
||||
String classname;
|
||||
while ((classname = work.poll()) != null) {
|
||||
System.err.println("Checking class " + classname);
|
||||
ClassSymbol sym = syms.enterClass(syms.noModule, names.table.fromString(classname));
|
||||
sym.complete();
|
||||
|
||||
if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces)
|
||||
continue;
|
||||
|
||||
for (Symbol s : sym.members_field.getSymbols(NON_RECURSIVE)) {
|
||||
System.err.println("Checking member " + s);
|
||||
switch (s.kind) {
|
||||
case TYP: {
|
||||
String name = s.flatName().toString();
|
||||
if (!classes.contains(name)) {
|
||||
classes.add(name);
|
||||
work.add(name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MTH:
|
||||
verify((MethodSymbol) s, expectNames);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void verify(MethodSymbol m, boolean expectNames) {
|
||||
if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods)
|
||||
return;
|
||||
|
||||
//System.err.println("verify: " + m.params());
|
||||
int i = 1;
|
||||
for (VarSymbol v: m.params()) {
|
||||
String expectName;
|
||||
if (expectNames)
|
||||
expectName = getExpectedName(v, i);
|
||||
else
|
||||
expectName = "arg" + (i - 1);
|
||||
checkEqual(expectName, v.name.toString());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
String getExpectedName(VarSymbol v, int i) {
|
||||
// special cases:
|
||||
// synthetic method
|
||||
if (((v.owner.owner.flags() & Flags.ENUM) != 0)
|
||||
&& v.owner.name.toString().equals("valueOf"))
|
||||
return "name";
|
||||
// interfaces don't have saved names
|
||||
// -- no Code attribute for the LocalVariableTable attribute
|
||||
if ((v.owner.owner.flags() & Flags.INTERFACE) != 0)
|
||||
return "arg" + (i - 1);
|
||||
// abstract methods don't have saved names
|
||||
// -- no Code attribute for the LocalVariableTable attribute
|
||||
if ((v.owner.flags() & Flags.ABSTRACT) != 0)
|
||||
return "arg" + (i - 1);
|
||||
// bridge methods use argN. No LVT for them anymore
|
||||
if ((v.owner.flags() & Flags.BRIDGE) != 0)
|
||||
return "arg" + (i - 1);
|
||||
|
||||
// The rest of this method assumes the local conventions in the test program
|
||||
Type t = v.type;
|
||||
String s;
|
||||
if (t.hasTag(TypeTag.CLASS))
|
||||
s = ((ClassType) t).tsym.name.toString();
|
||||
else
|
||||
s = t.toString();
|
||||
return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;
|
||||
}
|
||||
|
||||
void compile(File outDir, String... opts) throws Exception {
|
||||
//File testSrc = new File(System.getProperty("test.src"), ".");
|
||||
List<String> args = new ArrayList<String>();
|
||||
args.add("-d");
|
||||
args.add(outDir.getPath());
|
||||
args.addAll(Arrays.asList(opts));
|
||||
//args.add(new File(testSrc, "Test.java").getPath());
|
||||
args.add("Test.java");
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
|
||||
pw.close();
|
||||
if (rc != 0) {
|
||||
System.err.println(sw.toString());
|
||||
throw new Exception("compilation failed unexpectedly");
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> getTopLevelClasses(File outDir) {
|
||||
Set<String> classes = new HashSet<String>();
|
||||
for (String f: outDir.list()) {
|
||||
if (f.endsWith(".class") && !f.contains("$"))
|
||||
classes.add(f.replace(".class", ""));
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
void checkEqual(String expect, String found) {
|
||||
if (!expect.equals(found))
|
||||
error("mismatch: expected:" + expect + " found:" + found);
|
||||
}
|
||||
|
||||
void error(String msg) {
|
||||
System.err.println(msg);
|
||||
errors++;
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
int errors;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue