Skip to content

Commit df587c7

Browse files
Hui ShiRealCLanger
authored andcommitted
8264752: SIGFPE crash with option FlightRecorderOptions:threadbuffersize=30M
8266206: Build failure after JDK-8264752 with older GCCs Reviewed-by: clanger Backport-of: 377b346
1 parent c39f3f7 commit df587c7

File tree

5 files changed

+114
-13
lines changed

5 files changed

+114
-13
lines changed

src/hotspot/share/jfr/recorder/service/jfrMemorySizer.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -30,13 +30,15 @@
3030
const julong MAX_ADJUSTED_GLOBAL_BUFFER_SIZE = 1 * M;
3131
const julong MIN_ADJUSTED_GLOBAL_BUFFER_SIZE_CUTOFF = 512 * K;
3232
const julong MIN_GLOBAL_BUFFER_SIZE = 64 * K;
33+
const julong MAX_GLOBAL_BUFFER_SIZE = 2 * G;
3334
// implies at least 2 * MIN_GLOBAL_BUFFER SIZE
3435
const julong MIN_BUFFER_COUNT = 2;
3536
// MAX global buffer count open ended
3637
const julong DEFAULT_BUFFER_COUNT = 20;
3738
// MAX thread local buffer size == size of a single global buffer (runtime determined)
3839
// DEFAULT thread local buffer size = 2 * os page size (runtime determined)
3940
const julong MIN_THREAD_BUFFER_SIZE = 4 * K;
41+
const julong MAX_THREAD_BUFFER_SIZE = 2 * G;
4042
const julong MIN_MEMORY_SIZE = 1 * M;
4143
const julong DEFAULT_MEMORY_SIZE = 10 * M;
4244

@@ -305,6 +307,11 @@ static void thread_buffer_size(JfrMemoryOptions* options) {
305307
options->global_buffer_size = div_total_by_units(options->memory_size, options->buffer_count);
306308
if (options->thread_buffer_size > options->global_buffer_size) {
307309
options->global_buffer_size = options->thread_buffer_size;
310+
if (options->memory_size_configured) {
311+
options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
312+
} else {
313+
options->memory_size = multiply(options->global_buffer_size, options->buffer_count);
314+
}
308315
options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
309316
}
310317
assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
@@ -324,7 +331,8 @@ static void assert_post_condition(const JfrMemoryOptions* options) {
324331
assert(options->memory_size % os::vm_page_size() == 0, "invariant");
325332
assert(options->global_buffer_size % os::vm_page_size() == 0, "invariant");
326333
assert(options->thread_buffer_size % os::vm_page_size() == 0, "invariant");
327-
assert(options->buffer_count > 0, "invariant");
334+
assert(options->buffer_count >= MIN_BUFFER_COUNT, "invariant");
335+
assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
328336
}
329337
#endif
330338

@@ -429,6 +437,10 @@ bool JfrMemorySizer::adjust_options(JfrMemoryOptions* options) {
429437
default:
430438
default_size(options);
431439
}
440+
if (options->buffer_count < MIN_BUFFER_COUNT ||
441+
options->global_buffer_size < options->thread_buffer_size) {
442+
return false;
443+
}
432444
DEBUG_ONLY(assert_post_condition(options);)
433445
return true;
434446
}

src/hotspot/share/jfr/recorder/service/jfrMemorySizer.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,8 @@ extern const julong MIN_BUFFER_COUNT;
3232
extern const julong MIN_GLOBAL_BUFFER_SIZE;
3333
extern const julong MIN_MEMORY_SIZE;
3434
extern const julong MIN_THREAD_BUFFER_SIZE;
35+
extern const julong MAX_GLOBAL_BUFFER_SIZE;
36+
extern const julong MAX_THREAD_BUFFER_SIZE;
3537

3638
struct JfrMemoryOptions {
3739
julong memory_size;

src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -391,34 +391,41 @@ static julong divide_with_user_unit(Argument& memory_argument, julong value) {
391391
return value;
392392
}
393393

394-
template <typename Argument>
395-
static void log_lower_than_min_value(Argument& memory_argument, julong min_value) {
394+
static const char higher_than_msg[] = "This value is higher than the maximum size limited ";
395+
static const char lower_than_msg[] = "This value is lower than the minimum size required ";
396+
template <typename Argument, bool lower>
397+
static void log_out_of_range_value(Argument& memory_argument, julong min_value) {
398+
const char* msg = lower ? lower_than_msg : higher_than_msg;
396399
if (memory_argument.value()._size != memory_argument.value()._val) {
397400
// has multiplier
398401
log_error(arguments) (
399-
"This value is lower than the minimum size required " JULONG_FORMAT "%c",
402+
"%s" JULONG_FORMAT "%c", msg,
400403
divide_with_user_unit(memory_argument, min_value),
401404
memory_argument.value()._multiplier);
402405
return;
403406
}
404407
log_error(arguments) (
405-
"This value is lower than the minimum size required " JULONG_FORMAT,
408+
"%s" JULONG_FORMAT, msg,
406409
divide_with_user_unit(memory_argument, min_value));
407410
}
408411

412+
static const char default_val_msg[] = "Value default for option ";
413+
static const char specified_val_msg[] = "Value specified for option ";
409414
template <typename Argument>
410415
static void log_set_value(Argument& memory_argument) {
411416
if (memory_argument.value()._size != memory_argument.value()._val) {
412417
// has multiplier
413418
log_error(arguments) (
414-
"Value specified for option \"%s\" is " JULONG_FORMAT "%c",
419+
"%s\"%s\" is " JULONG_FORMAT "%c",
420+
memory_argument.is_set() ? specified_val_msg: default_val_msg,
415421
memory_argument.name(),
416422
memory_argument.value()._val,
417423
memory_argument.value()._multiplier);
418424
return;
419425
}
420426
log_error(arguments) (
421-
"Value specified for option \"%s\" is " JULONG_FORMAT,
427+
"%s\"%s\" is " JULONG_FORMAT,
428+
memory_argument.is_set() ? specified_val_msg: default_val_msg,
422429
memory_argument.name(), memory_argument.value()._val);
423430
}
424431

@@ -539,6 +546,10 @@ static bool valid_memory_relations(const JfrMemoryOptions& options) {
539546
return false;
540547
}
541548
}
549+
} else if (options.thread_buffer_size_configured && options.memory_size_configured) {
550+
if (!ensure_first_gteq_second(_dcmd_memorysize, _dcmd_threadbuffersize)) {
551+
return false;
552+
}
542553
}
543554
return true;
544555
}
@@ -607,7 +618,7 @@ template <typename Argument>
607618
static bool ensure_gteq(Argument& memory_argument, const jlong value) {
608619
if ((jlong)memory_argument.value()._size < value) {
609620
log_set_value(memory_argument);
610-
log_lower_than_min_value(memory_argument, value);
621+
log_out_of_range_value<Argument, true>(memory_argument, value);
611622
return false;
612623
}
613624
return true;
@@ -638,14 +649,38 @@ static bool ensure_valid_minimum_sizes() {
638649
return true;
639650
}
640651

652+
template <typename Argument>
653+
static bool ensure_lteq(Argument& memory_argument, const jlong value) {
654+
if ((jlong)memory_argument.value()._size > value) {
655+
log_set_value(memory_argument);
656+
log_out_of_range_value<Argument, false>(memory_argument, value);
657+
return false;
658+
}
659+
return true;
660+
}
661+
662+
static bool ensure_valid_maximum_sizes() {
663+
if (_dcmd_globalbuffersize.is_set()) {
664+
if (!ensure_lteq(_dcmd_globalbuffersize, MAX_GLOBAL_BUFFER_SIZE)) {
665+
return false;
666+
}
667+
}
668+
if (_dcmd_threadbuffersize.is_set()) {
669+
if (!ensure_lteq(_dcmd_threadbuffersize, MAX_THREAD_BUFFER_SIZE)) {
670+
return false;
671+
}
672+
}
673+
return true;
674+
}
675+
641676
/**
642677
* Starting with the initial set of memory values from the user,
643678
* sanitize, enforce min/max rules and adjust to a set of consistent options.
644679
*
645680
* Adjusted memory sizes will be page aligned.
646681
*/
647682
bool JfrOptionSet::adjust_memory_options() {
648-
if (!ensure_valid_minimum_sizes()) {
683+
if (!ensure_valid_minimum_sizes() || !ensure_valid_maximum_sizes()) {
649684
return false;
650685
}
651686
JfrMemoryOptions options;
@@ -654,6 +689,24 @@ bool JfrOptionSet::adjust_memory_options() {
654689
return false;
655690
}
656691
if (!JfrMemorySizer::adjust_options(&options)) {
692+
if (options.buffer_count < MIN_BUFFER_COUNT || options.global_buffer_size < options.thread_buffer_size) {
693+
log_set_value(_dcmd_memorysize);
694+
log_set_value(_dcmd_globalbuffersize);
695+
log_error(arguments) ("%s \"%s\" is " JLONG_FORMAT,
696+
_dcmd_numglobalbuffers.is_set() ? specified_val_msg: default_val_msg,
697+
_dcmd_numglobalbuffers.name(), _dcmd_numglobalbuffers.value());
698+
log_set_value(_dcmd_threadbuffersize);
699+
if (options.buffer_count < MIN_BUFFER_COUNT) {
700+
log_error(arguments) ("numglobalbuffers " JULONG_FORMAT " is less than minimal value " JULONG_FORMAT,
701+
options.buffer_count, MIN_BUFFER_COUNT);
702+
log_error(arguments) ("Decrease globalbuffersize/threadbuffersize or increase memorysize");
703+
} else {
704+
log_error(arguments) ("globalbuffersize " JULONG_FORMAT " is less than threadbuffersize" JULONG_FORMAT,
705+
options.global_buffer_size, options.thread_buffer_size);
706+
log_error(arguments) ("Decrease globalbuffersize or increase memorysize or adjust global/threadbuffersize");
707+
}
708+
return false;
709+
}
657710
if (!check_for_ambiguity(_dcmd_memorysize, _dcmd_globalbuffersize, _dcmd_numglobalbuffers)) {
658711
return false;
659712
}

test/jdk/jdk/jfr/startupargs/TestBadOptionValues.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import jdk.test.lib.Asserts;
2929
import jdk.test.lib.process.OutputAnalyzer;
3030
import jdk.test.lib.process.ProcessTools;
31+
import sun.hotspot.WhiteBox;
3132

3233
/**
3334
* @test
@@ -39,7 +40,10 @@
3940
* java.management
4041
* jdk.jfr
4142
*
42-
* @run main jdk.jfr.startupargs.TestBadOptionValues
43+
* @build ClassFileInstaller
44+
* @build sun.hotspot.WhiteBox
45+
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
46+
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI jdk.jfr.startupargs.TestBadOptionValues
4347
*/
4448
public class TestBadOptionValues {
4549

@@ -121,6 +125,31 @@ public static void main(String[] args) throws Exception {
121125
test(START_FLIGHT_RECORDING, "Parsing error memory size value: invalid value",
122126
"maxsize=");
123127

128+
// globalbuffersize exceeds limit
129+
test(FLIGHT_RECORDER_OPTIONS, "This value is higher than the maximum size limit",
130+
"globalbuffersize=4G");
131+
132+
// threadbuffersize exceeds limit
133+
test(FLIGHT_RECORDER_OPTIONS, "This value is higher than the maximum size limit",
134+
"threadbuffersize=4G");
135+
136+
// computed numglobalbuffers smaller than MIN_BUFFER_COUNT
137+
test(FLIGHT_RECORDER_OPTIONS, "Decrease globalbuffersize/threadbuffersize or increase memorysize",
138+
"memorysize=1m,globalbuffersize=1m");
139+
140+
// memorysize smaller than threadbuffersize
141+
test(FLIGHT_RECORDER_OPTIONS, "The value for option \"threadbuffersize\" should not be larger than the value specified for option \"memorysize\"",
142+
"memorysize=1m,threadbuffersize=2m");
143+
144+
// computed globalbuffersize smaller than threadbuffersize
145+
// test is on when vm page isn't larger than 4K, avoiding both buffer sizes align to vm page size
146+
WhiteBox wb = WhiteBox.getWhiteBox();
147+
long smallPageSize = wb.getVMPageSize();
148+
if (smallPageSize <= 4096) {
149+
test(FLIGHT_RECORDER_OPTIONS, "Decrease globalbuffersize or increase memorysize or adjust global/threadbuffersize",
150+
"memorysize=1m,numglobalbuffers=256");
151+
}
152+
124153
test(FLIGHT_RECORDER_OPTIONS, "Parsing error memory size value: invalid value",
125154
"threadbuffersize=a",
126155
"globalbuffersize=G",

test/jdk/jdk/jfr/startupargs/TestMemoryOptions.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,11 @@ public static void runTestCase(TestCase tc) throws Exception {
642642
tc.setGlobalBufferSizeTestParam(64, 'k');
643643
tc.setGlobalBufferCountTestParam(16, 'b');
644644
testCases.add(tc);
645+
646+
// threadbuffersize exceeds default memorysize
647+
tc = new TestCase("ThreadBufferSizeExceedMemorySize", false);
648+
tc.setThreadBufferSizeTestParam(30, 'm');
649+
testCases.add(tc);
645650
}
646651

647652
public static void main(String[] args) throws Exception {

0 commit comments

Comments
 (0)