Skip to content

Commit adf0e23

Browse files
Xin LiuPaul Hohensee
authored andcommitted
8257800: CompileCommand TypedMethodOptionMatcher::parse_method_pattern() may over consume
Reviewed-by: thartmann, chagedorn, phh
1 parent 06c24e1 commit adf0e23

File tree

4 files changed

+134
-15
lines changed

4 files changed

+134
-15
lines changed

src/hotspot/share/compiler/compilerOracle.cpp

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ bool CompilerOracle::should_blackhole(const methodHandle& method) {
428428
return true;
429429
}
430430

431-
static enum CompileCommand parse_option_name(const char* line, int* bytes_read, char* errorbuf, int bufsize) {
431+
static enum CompileCommand match_option_name(const char* line, int* bytes_read, char* errorbuf, int bufsize) {
432432
assert(ARRAY_SIZE(option_names) == static_cast<int>(CompileCommand::Count), "option_names size mismatch");
433433

434434
*bytes_read = 0;
@@ -445,6 +445,25 @@ static enum CompileCommand parse_option_name(const char* line, int* bytes_read,
445445
return CompileCommand::Unknown;
446446
}
447447

448+
// match exactly and don't mess with errorbuf
449+
enum CompileCommand CompilerOracle::parse_option_name(const char* line) {
450+
for (uint i = 0; i < ARRAY_SIZE(option_names); i++) {
451+
if (strcasecmp(line, option_names[i]) == 0) {
452+
return static_cast<enum CompileCommand>(i);
453+
}
454+
}
455+
return CompileCommand::Unknown;
456+
}
457+
458+
enum OptionType CompilerOracle::parse_option_type(const char* type_str) {
459+
for (uint i = 0; i < ARRAY_SIZE(optiontype_names); i++) {
460+
if (strcasecmp(type_str, optiontype_names[i]) == 0) {
461+
return static_cast<enum OptionType>(i);
462+
}
463+
}
464+
return OptionType::Unknown;
465+
}
466+
448467
void print_tip() { // CMH Update info
449468
tty->cr();
450469
tty->print_cr("Usage: '-XX:CompileCommand=<option>,<method pattern>' - to set boolean option to true");
@@ -663,7 +682,7 @@ static void scan_option_and_value(enum OptionType type, char* line, int& total_b
663682
total_bytes_read += bytes_read;
664683
int bytes_read2 = 0;
665684
total_bytes_read += skip_whitespace(line);
666-
enum CompileCommand option = parse_option_name(option_buf, &bytes_read2, errorbuf, buf_size);
685+
enum CompileCommand option = match_option_name(option_buf, &bytes_read2, errorbuf, buf_size);
667686
if (option == CompileCommand::Unknown) {
668687
assert(*errorbuf != '\0', "error must have been set");
669688
return;
@@ -692,15 +711,6 @@ void CompilerOracle::print_parse_error(char* error_msg, char* original_line) {
692711
print_tip();
693712
}
694713

695-
enum OptionType parse_option_type(const char* type_str) {
696-
for (uint i = 0; i < ARRAY_SIZE(optiontype_names); i++) {
697-
if (strcasecmp(type_str, optiontype_names[i]) == 0) {
698-
return static_cast<enum OptionType>(i);
699-
}
700-
}
701-
return OptionType::Unknown;
702-
}
703-
704714
class LineCopy : StackObj {
705715
const char* _copy;
706716
public:
@@ -723,7 +733,7 @@ void CompilerOracle::parse_from_line(char* line) {
723733
int bytes_read;
724734
char error_buf[1024] = {0};
725735

726-
enum CompileCommand option = parse_option_name(line, &bytes_read, error_buf, sizeof(error_buf));
736+
enum CompileCommand option = match_option_name(line, &bytes_read, error_buf, sizeof(error_buf));
727737
line += bytes_read;
728738
ResourceMark rm;
729739

@@ -784,7 +794,7 @@ void CompilerOracle::parse_from_line(char* line) {
784794
} else {
785795
// Type (1) option - option_type contains the option name -> bool value = true is implied
786796
int bytes_read;
787-
enum CompileCommand option = parse_option_name(option_type, &bytes_read, error_buf, sizeof(error_buf));
797+
enum CompileCommand option = match_option_name(option_type, &bytes_read, error_buf, sizeof(error_buf));
788798
if (option == CompileCommand::Unknown) {
789799
print_parse_error(error_buf, original.get());
790800
return;
@@ -1001,5 +1011,5 @@ void CompilerOracle::parse_compile_only(char* line) {
10011011
enum CompileCommand CompilerOracle::string_to_option(const char* name) {
10021012
int bytes_read = 0;
10031013
char errorbuf[1024] = {0};
1004-
return parse_option_name(name, &bytes_read, errorbuf, sizeof(errorbuf));
1014+
return match_option_name(name, &bytes_read, errorbuf, sizeof(errorbuf));
10051015
}

src/hotspot/share/compiler/compilerOracle.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ class CompilerOracle : AllStatic {
171171
// convert a string to a proper compilecommand option - used from whitebox.
172172
// returns CompileCommand::Unknown on names not matching an option.
173173
static enum CompileCommand string_to_option(const char* name);
174+
175+
// convert a string to a proper compilecommand option
176+
// returns CompileCommand::Unknown if name is not an option.
177+
static enum CompileCommand parse_option_name(const char* name);
178+
179+
// convert a string to a proper option type
180+
// returns OptionType::Unknown on strings not matching an option type.
181+
static enum OptionType parse_option_type(const char* type_str);
174182
};
175183

176184
#endif // SHARE_COMPILER_COMPILERORACLE_HPP

src/hotspot/share/compiler/methodMatcher.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "precompiled.hpp"
2626
#include "classfile/symbolTable.hpp"
2727
#include "classfile/vmSymbols.hpp"
28+
#include "compiler/compilerOracle.hpp"
2829
#include "compiler/methodMatcher.hpp"
2930
#include "memory/oopFactory.hpp"
3031
#include "memory/resourceArea.hpp"
@@ -105,7 +106,6 @@ bool MethodMatcher::canonicalize(char * line, const char *& error_msg) {
105106
}
106107
}
107108

108-
bool in_signature = false;
109109
char* pos = line;
110110
if (pos != NULL) {
111111
for (char* lp = pos + 1; *lp != '\0'; lp++) {
@@ -269,11 +269,25 @@ void MethodMatcher::parse_method_pattern(char*& line, const char*& error_msg, Me
269269
c_match = check_mode(class_name, error_msg);
270270
m_match = check_mode(method_name, error_msg);
271271

272+
// Over-consumption
273+
// method_name points to an option type or option name because the method name is not specified by users.
274+
// In very rare case, the method name happens to be same as option type/name, so look ahead to make sure
275+
// it doesn't show up again.
276+
if ((OptionType::Unknown != CompilerOracle::parse_option_type(method_name) ||
277+
CompileCommand::Unknown != CompilerOracle::parse_option_name(method_name)) &&
278+
*(line + bytes_read) != '\0' &&
279+
strstr(line + bytes_read, method_name) == NULL) {
280+
error_msg = "Did not specify any method name";
281+
method_name[0] = '\0';
282+
return;
283+
}
284+
272285
if ((strchr(class_name, JVM_SIGNATURE_SPECIAL) != NULL) ||
273286
(strchr(class_name, JVM_SIGNATURE_ENDSPECIAL) != NULL)) {
274287
error_msg = "Chars '<' and '>' not allowed in class name";
275288
return;
276289
}
290+
277291
if ((strchr(method_name, JVM_SIGNATURE_SPECIAL) != NULL) ||
278292
(strchr(method_name, JVM_SIGNATURE_ENDSPECIAL) != NULL)) {
279293
if (!vmSymbols::object_initializer_name()->equals(method_name) &&
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright Amazon.com Inc. 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+
/*
25+
* @test
26+
* @bug 8257800
27+
* @summary Tests CompileCommand=option,package/class,ccstrlist,ControlIntrinsic,+_id
28+
* @library /test/lib /
29+
*
30+
* @run driver compiler.compilercontrol.commands.OptionTest
31+
*/
32+
33+
package compiler.compilercontrol.commands;
34+
35+
import jdk.test.lib.process.ProcessTools;
36+
37+
public class OptionTest {
38+
public static void main(String[] args) throws Exception {
39+
ProcessTools.executeTestJvm("-XX:CompileCommand=option,package/class,ccstrlist,ControlIntrinsic,+_id", "-version")
40+
.shouldHaveExitValue(0)
41+
.shouldContain("CompileCommand: An error occurred during parsing")
42+
.shouldContain("Error: Did not specify any method name")
43+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
44+
45+
ProcessTools.executeTestJvm("-XX:CompileCommand=option,*,ccstrlist,ControlIntrinsic,+_id", "-version")
46+
.shouldHaveExitValue(0)
47+
.shouldContain("CompileCommand: An error occurred during parsing")
48+
.shouldContain("Error: Did not specify any method name")
49+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
50+
51+
// corner case:
52+
// ccstrlist could be a valid method name, so it is accepted in the well-formed case.
53+
ProcessTools.executeTestJvm("-XX:CompileCommand=option,*.ccstrlist,ccstrlist,ControlIntrinsic,+_id", "-version")
54+
.shouldContain("CompileCommand: ControlIntrinsic *.ccstrlist const char* ControlIntrinsic")
55+
.shouldHaveExitValue(0)
56+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
57+
58+
ProcessTools.executeTestJvm("-XX:CompileCommand=option,*.*,ccstrlist,ControlIntrinsic,+_id", "-version")
59+
.shouldContain("CompileCommand: ControlIntrinsic *.* const char* ControlIntrinsic")
60+
.shouldHaveExitValue(0)
61+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
62+
63+
ProcessTools.executeTestJvm("-XX:CompileCommand=option,class,PrintIntrinsics", "-version")
64+
.shouldHaveExitValue(0)
65+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
66+
67+
// corner case:
68+
// PrintIntrinsics could be a valid method name, so it is accepted in the well-formed case.
69+
ProcessTools.executeTestJvm("-XX:CompileCommand=option,class.PrintIntrinsics,PrintIntrinsics", "-version")
70+
.shouldContain("CompileCommand: PrintIntrinsics class.PrintIntrinsics bool PrintIntrinsics = true")
71+
.shouldHaveExitValue(0)
72+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
73+
74+
// corner case:
75+
// _dontinline_* is a valid method pattern, so it should be accepted
76+
ProcessTools.executeTestJvm("-XX:CompileCommand=dontinline,*::dontinline_*", "-version")
77+
.shouldContain("CompileCommand: dontinline *.dontinline_* bool dontinline = true")
78+
.shouldHaveExitValue(0)
79+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
80+
81+
ProcessTools.executeTestJvm("-XX:CompileCommand=dontinline,*.dontinline", "-version")
82+
.shouldContain("CompileCommand: dontinline *.dontinline bool dontinline = true")
83+
.shouldHaveExitValue(0)
84+
.shouldNotContain("Error: Did not specify any method name")
85+
.shouldNotContain("# A fatal error has been detected by the Java Runtime Environment");
86+
}
87+
}

0 commit comments

Comments
 (0)