Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
private static final String FILE_HEADER = "/*\n * Autogenerated by Avro\n *\n * DO NOT EDIT DIRECTLY\n */\n";

public SpecificCompiler(Protocol protocol) {
this();

Check warning on line 151 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[this-escape] possible 'this' escape before subclass is fully initialized
// enqueue all types
for (Schema s : protocol.getTypes()) {
enqueue(s);
Expand All @@ -161,7 +161,7 @@
}

public SpecificCompiler(Collection<Schema> schemas) {
this();

Check warning on line 164 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[this-escape] possible 'this' escape before subclass is fully initialized
for (Schema schema : schemas) {
enqueue(schema);
}
Expand All @@ -182,7 +182,7 @@
this.templateDir = System.getProperty("org.apache.avro.specific.templates",
"/org/apache/avro/compiler/specific/templates/java/classic/");
initializeVelocity();
initializeSpecificData();

Check warning on line 185 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[this-escape] previous possible 'this' escape happens here via invocation

Check warning on line 185 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[this-escape] previous possible 'this' escape happens here via invocation
}

/**
Expand Down Expand Up @@ -427,7 +427,7 @@
}

private void initializeSpecificData() {
addLogicalTypeConversions(specificData);

Check warning on line 430 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[this-escape] previous possible 'this' escape happens here via invocation

Check warning on line 430 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[this-escape] previous possible 'this' escape happens here via invocation
specificData.addLogicalTypeConversion(new Conversions.DecimalConversion());
}

Expand Down Expand Up @@ -940,7 +940,7 @@
// with error(s)
return "void";
}
default:

Check warning on line 943 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-24.04-arm)

[fallthrough] possible fall-through into case

Check warning on line 943 in lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java

View workflow job for this annotation

GitHub Actions / Java Test (ubuntu-latest)

[fallthrough] possible fall-through into case
return javaType(schema, false);
}
}
Expand Down Expand Up @@ -1118,7 +1118,11 @@
* Utility for template use. Escapes comment end with HTML entities.
*/
public static String escapeForJavadoc(String s) {
return s.replace("*/", "*&#47;").replace("<", "&lt;").replace(">", "&gt;");
// Double backslashes first so a value cannot smuggle in a Unicode escape such
// as \\u002a\\u002f: javac processes Unicode escapes before comments, so an
// unneutralized \\u002a\\u002f would decode to */ inside the generated Javadoc
// and let a schema doc break out of the comment into code.
return s.replace("\\", "\\\\").replace("*/", "*&#47;").replace("<", "&lt;").replace(">", "&gt;");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,27 @@ void annotationCannotBreakOutViaStringLiteral() {
assertTrue(validAnnotationEmitted, "Valid annotation missing from generated output");
}

@Test
void docCannotBreakOutViaUnicodeEscape() {
// javac decodes Unicode escapes before it strips comments, so a schema doc
// carrying a backslash-u escape for the comment terminator decodes to that
// terminator inside the generated Javadoc and ends the comment early, turning
// the rest of the doc into code. The escaper must neutralize such escapes.
String jsonSchema = "{\n" + " \"type\": \"record\",\n" + " \"name\": \"DocInjected\",\n" + " \"fields\": [\n"
+ " {\"name\": \"value\", \"type\": \"string\", \"doc\": "
+ "\"\\\\u002a\\\\u002f public static int PWNED = 1; \\\\u002f\\\\u002a\"}\n" + " ]\n" + "}";
Collection<SpecificCompiler.OutputFile> outputs = new SpecificCompiler(SchemaParser.parseSingle(jsonSchema))
.compile();
// A Unicode escape is only decoded by javac when the leading backslash is
// preceded by an even number of backslashes. An eligible escape for a comment
// char in the generated source is the breakout; the doubled form is inert.
Pattern eligibleEscape = Pattern.compile("(?<!\\\\)(?:\\\\\\\\)*\\\\u002[afAF]");
for (SpecificCompiler.OutputFile outputFile : outputs) {
assertFalse(eligibleEscape.matcher(outputFile.contents).find(),
"Unicode-escape comment breakout present? " + outputFile.contents);
}
}

private int countOccurrences(Pattern pattern, String textToSearch) {
int count = 0;
for (Matcher matcher = pattern.matcher(textToSearch); matcher.find();) {
Expand Down
Loading