1
1
/*
2
- * Copyright (c) 2015, 2023 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2015, 2024 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
50
50
#include " runtime/javaCalls.hpp"
51
51
#include " utilities/defaultStream.hpp"
52
52
#include " utilities/macros.hpp"
53
+ #include " utilities/utf8.hpp"
53
54
54
55
volatile Thread* ClassListParser::_parsing_thread = nullptr ;
55
56
ClassListParser* ClassListParser::_instance = nullptr ;
56
57
57
- ClassListParser::ClassListParser (const char * file, ParseMode parse_mode) : _id2klass_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE) {
58
+ ClassListParser::ClassListParser (const char * file, ParseMode parse_mode) :
59
+ _classlist_file(file),
60
+ _id2klass_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
61
+ _file_input(do_open(file), /* need_close=*/ true),
62
+ _input_stream(&_file_input) {
58
63
log_info (cds)(" Parsing %s%s" , file,
59
64
(parse_mode == _parse_lambda_forms_invokers_only) ? " (lambda form invokers only)" : " " );
60
- _classlist_file = file;
61
- _file = nullptr ;
62
- // Use os::open() because neither fopen() nor os::fopen()
63
- // can handle long path name on Windows.
64
- int fd = os::open (file, O_RDONLY, S_IREAD);
65
- if (fd != -1 ) {
66
- // Obtain a File* from the file descriptor so that fgets()
67
- // can be used in parse_one_line()
68
- _file = os::fdopen (fd, " r" );
69
- }
70
- if (_file == nullptr ) {
65
+ if (!_file_input.is_open ()) {
71
66
char errmsg[JVM_MAXPATHLEN];
72
67
os::lasterror (errmsg, JVM_MAXPATHLEN);
73
68
vm_exit_during_initialization (" Loading classlist failed" , errmsg);
74
69
}
75
- _line_no = 0 ;
76
- _token = _line;
70
+ _token = _line = nullptr ;
77
71
_interfaces = new (mtClass) GrowableArray<int >(10 , mtClass);
78
72
_indy_items = new (mtClass) GrowableArray<const char *>(9 , mtClass);
79
73
_parse_mode = parse_mode;
@@ -84,14 +78,24 @@ ClassListParser::ClassListParser(const char* file, ParseMode parse_mode) : _id2k
84
78
Atomic::store (&_parsing_thread, Thread::current ());
85
79
}
86
80
81
+ FILE* ClassListParser::do_open (const char * file) {
82
+ // Use os::open() because neither fopen() nor os::fopen()
83
+ // can handle long path name on Windows. (See JDK-8216184)
84
+ int fd = os::open (file, O_RDONLY, S_IREAD);
85
+ FILE* fp = nullptr ;
86
+ if (fd != -1 ) {
87
+ // Obtain a FILE* from the file descriptor so that _input_stream
88
+ // can be used in ClassListParser::parse()
89
+ fp = os::fdopen (fd, " r" );
90
+ }
91
+ return fp;
92
+ }
93
+
87
94
bool ClassListParser::is_parsing_thread () {
88
95
return Atomic::load (&_parsing_thread) == Thread::current ();
89
96
}
90
97
91
98
ClassListParser::~ClassListParser () {
92
- if (_file != nullptr ) {
93
- fclose (_file);
94
- }
95
99
Atomic::store (&_parsing_thread, (Thread*)nullptr );
96
100
delete _indy_items;
97
101
delete _interfaces;
@@ -101,7 +105,15 @@ ClassListParser::~ClassListParser() {
101
105
int ClassListParser::parse (TRAPS) {
102
106
int class_count = 0 ;
103
107
104
- while (parse_one_line ()) {
108
+ for (; !_input_stream.done (); _input_stream.next ()) {
109
+ _line = _input_stream.current_line ();
110
+ if (*_line == ' #' ) { // comment
111
+ continue ;
112
+ }
113
+ if (!parse_one_line ()) {
114
+ break ;
115
+ }
116
+
105
117
if (lambda_form_line ()) {
106
118
// The current line is "@lambda-form-invoker ...". It has been recorded in LambdaFormInvokers,
107
119
// and will be processed later.
@@ -112,6 +124,7 @@ int ClassListParser::parse(TRAPS) {
112
124
continue ;
113
125
}
114
126
127
+ check_class_name (_class_name);
115
128
TempNewSymbol class_name_symbol = SymbolTable::new_symbol (_class_name);
116
129
if (_indy_items->length () > 0 ) {
117
130
// The current line is "@lambda-proxy class_name". Load the proxy class.
@@ -165,43 +178,26 @@ int ClassListParser::parse(TRAPS) {
165
178
}
166
179
167
180
bool ClassListParser::parse_one_line () {
168
- for (;;) {
169
- if (fgets (_line, sizeof (_line), _file) == nullptr ) {
170
- return false ;
171
- }
172
- ++ _line_no;
173
- _line_len = (int )strlen (_line);
174
- if (_line_len > _max_allowed_line_len) {
175
- error (" input line too long (must be no longer than %d chars)" , _max_allowed_line_len);
176
- }
177
- if (*_line == ' #' ) { // comment
178
- continue ;
179
- }
180
-
181
- {
182
- int len = (int )strlen (_line);
183
- int i;
184
- // Replace \t\r\n\f with ' '
185
- for (i=0 ; i<len; i++) {
186
- if (_line[i] == ' \t ' || _line[i] == ' \r ' || _line[i] == ' \n ' || _line[i] == ' \f ' ) {
187
- _line[i] = ' ' ;
188
- }
181
+ {
182
+ int len = (int )strlen (_line);
183
+ int i;
184
+ // Replace \t\r\n\f with ' '
185
+ for (i=0 ; i<len; i++) {
186
+ if (_line[i] == ' \t ' || _line[i] == ' \r ' || _line[i] == ' \n ' || _line[i] == ' \f ' ) {
187
+ _line[i] = ' ' ;
189
188
}
189
+ }
190
190
191
- // Remove trailing newline/space
192
- while (len > 0 ) {
193
- if (_line[len-1 ] == ' ' ) {
194
- _line[len-1 ] = ' \0 ' ;
195
- len --;
196
- } else {
197
- break ;
198
- }
191
+ // Remove trailing newline/space
192
+ while (len > 0 ) {
193
+ if (_line[len-1 ] == ' ' ) {
194
+ _line[len-1 ] = ' \0 ' ;
195
+ len --;
196
+ } else {
197
+ break ;
199
198
}
200
- _line_len = len;
201
199
}
202
-
203
- // valid line
204
- break ;
200
+ _line_len = len;
205
201
}
206
202
207
203
_class_name = _line;
@@ -286,7 +282,7 @@ int ClassListParser::split_at_tag_from_line() {
286
282
_token = _line;
287
283
char * ptr;
288
284
if ((ptr = strchr (_line, ' ' )) == nullptr ) {
289
- error (" Too few items following the @ tag \" %s\" line #%d " , _line, _line_no );
285
+ error (" Too few items following the @ tag \" %s\" line #%zu " , _line, lineno () );
290
286
return 0 ;
291
287
}
292
288
*ptr++ = ' \0 ' ;
@@ -304,7 +300,7 @@ bool ClassListParser::parse_at_tags() {
304
300
if (strcmp (_token, LAMBDA_PROXY_TAG) == 0 ) {
305
301
split_tokens_by_whitespace (offset);
306
302
if (_indy_items->length () < 2 ) {
307
- error (" Line with @ tag has too few items \" %s\" line #%d " , _token, _line_no );
303
+ error (" Line with @ tag has too few items \" %s\" line #%zu " , _token, lineno () );
308
304
return false ;
309
305
}
310
306
// set the class name
@@ -315,7 +311,7 @@ bool ClassListParser::parse_at_tags() {
315
311
_lambda_form_line = true ;
316
312
return true ;
317
313
} else {
318
- error (" Invalid @ tag at the beginning of line \" %s\" line #%d " , _token, _line_no );
314
+ error (" Invalid @ tag at the beginning of line \" %s\" line #%zu " , _token, lineno () );
319
315
return false ;
320
316
}
321
317
}
@@ -423,8 +419,8 @@ void ClassListParser::error(const char* msg, ...) {
423
419
}
424
420
425
421
jio_fprintf (defaultStream::error_stream (),
426
- " An error has occurred while processing class list file %s %d :%d.\n " ,
427
- _classlist_file, _line_no , (error_index + 1 ));
422
+ " An error has occurred while processing class list file %s %zu :%d.\n " ,
423
+ _classlist_file, lineno () , (error_index + 1 ));
428
424
jio_vfprintf (defaultStream::error_stream (), msg, ap);
429
425
430
426
if (_line_len <= 0 ) {
@@ -450,6 +446,25 @@ void ClassListParser::error(const char* msg, ...) {
450
446
va_end (ap);
451
447
}
452
448
449
+ void ClassListParser::check_class_name (const char * class_name) {
450
+ const char * err = nullptr ;
451
+ size_t len = strlen (class_name);
452
+ if (len > (size_t )Symbol::max_length ()) {
453
+ err = " class name too long" ;
454
+ } else {
455
+ assert (Symbol::max_length () < INT_MAX && len < INT_MAX, " must be" );
456
+ if (!UTF8::is_legal_utf8 ((const unsigned char *)class_name, (int )len, /* version_leq_47*/ false )) {
457
+ err = " class name is not valid UTF8" ;
458
+ }
459
+ }
460
+ if (err != nullptr ) {
461
+ jio_fprintf (defaultStream::error_stream (),
462
+ " An error has occurred while processing class list file %s:%zu %s\n " ,
463
+ _classlist_file, lineno (), err);
464
+ vm_exit_during_initialization (" class list format error." , nullptr );
465
+ }
466
+ }
467
+
453
468
// This function is used for loading classes for customized class loaders
454
469
// during archive dumping.
455
470
InstanceKlass* ClassListParser::load_class_from_source (Symbol* class_name, TRAPS) {
0 commit comments