Skip to content
Permalink
Browse files
8264752: SIGFPE crash with option FlightRecorderOptions:threadbuffers…
…ize=30M

8266206: Build failure after JDK-8264752 with older GCCs

Reviewed-by: clanger
Backport-of: 377b346
  • Loading branch information
Hui Shi authored and RealCLanger committed Jun 25, 2021
1 parent c39f3f7 commit df587c75bb436b40dd995e39ee0ed952a74b979b
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2021, 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
@@ -30,13 +30,15 @@
const julong MAX_ADJUSTED_GLOBAL_BUFFER_SIZE = 1 * M;
const julong MIN_ADJUSTED_GLOBAL_BUFFER_SIZE_CUTOFF = 512 * K;
const julong MIN_GLOBAL_BUFFER_SIZE = 64 * K;
const julong MAX_GLOBAL_BUFFER_SIZE = 2 * G;
// implies at least 2 * MIN_GLOBAL_BUFFER SIZE
const julong MIN_BUFFER_COUNT = 2;
// MAX global buffer count open ended
const julong DEFAULT_BUFFER_COUNT = 20;
// MAX thread local buffer size == size of a single global buffer (runtime determined)
// DEFAULT thread local buffer size = 2 * os page size (runtime determined)
const julong MIN_THREAD_BUFFER_SIZE = 4 * K;
const julong MAX_THREAD_BUFFER_SIZE = 2 * G;
const julong MIN_MEMORY_SIZE = 1 * M;
const julong DEFAULT_MEMORY_SIZE = 10 * M;

@@ -305,6 +307,11 @@ static void thread_buffer_size(JfrMemoryOptions* options) {
options->global_buffer_size = div_total_by_units(options->memory_size, options->buffer_count);
if (options->thread_buffer_size > options->global_buffer_size) {
options->global_buffer_size = options->thread_buffer_size;
if (options->memory_size_configured) {
options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
} else {
options->memory_size = multiply(options->global_buffer_size, options->buffer_count);
}
options->buffer_count = div_total_by_per_unit(options->memory_size, options->global_buffer_size);
}
assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
@@ -324,7 +331,8 @@ static void assert_post_condition(const JfrMemoryOptions* options) {
assert(options->memory_size % os::vm_page_size() == 0, "invariant");
assert(options->global_buffer_size % os::vm_page_size() == 0, "invariant");
assert(options->thread_buffer_size % os::vm_page_size() == 0, "invariant");
assert(options->buffer_count > 0, "invariant");
assert(options->buffer_count >= MIN_BUFFER_COUNT, "invariant");
assert(options->global_buffer_size >= options->thread_buffer_size, "invariant");
}
#endif

@@ -429,6 +437,10 @@ bool JfrMemorySizer::adjust_options(JfrMemoryOptions* options) {
default:
default_size(options);
}
if (options->buffer_count < MIN_BUFFER_COUNT ||
options->global_buffer_size < options->thread_buffer_size) {
return false;
}
DEBUG_ONLY(assert_post_condition(options);)
return true;
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021, 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
@@ -32,6 +32,8 @@ extern const julong MIN_BUFFER_COUNT;
extern const julong MIN_GLOBAL_BUFFER_SIZE;
extern const julong MIN_MEMORY_SIZE;
extern const julong MIN_THREAD_BUFFER_SIZE;
extern const julong MAX_GLOBAL_BUFFER_SIZE;
extern const julong MAX_THREAD_BUFFER_SIZE;

struct JfrMemoryOptions {
julong memory_size;
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2021, 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
@@ -391,34 +391,41 @@ static julong divide_with_user_unit(Argument& memory_argument, julong value) {
return value;
}

template <typename Argument>
static void log_lower_than_min_value(Argument& memory_argument, julong min_value) {
static const char higher_than_msg[] = "This value is higher than the maximum size limited ";
static const char lower_than_msg[] = "This value is lower than the minimum size required ";
template <typename Argument, bool lower>
static void log_out_of_range_value(Argument& memory_argument, julong min_value) {
const char* msg = lower ? lower_than_msg : higher_than_msg;
if (memory_argument.value()._size != memory_argument.value()._val) {
// has multiplier
log_error(arguments) (
"This value is lower than the minimum size required " JULONG_FORMAT "%c",
"%s" JULONG_FORMAT "%c", msg,
divide_with_user_unit(memory_argument, min_value),
memory_argument.value()._multiplier);
return;
}
log_error(arguments) (
"This value is lower than the minimum size required " JULONG_FORMAT,
"%s" JULONG_FORMAT, msg,
divide_with_user_unit(memory_argument, min_value));
}

static const char default_val_msg[] = "Value default for option ";
static const char specified_val_msg[] = "Value specified for option ";
template <typename Argument>
static void log_set_value(Argument& memory_argument) {
if (memory_argument.value()._size != memory_argument.value()._val) {
// has multiplier
log_error(arguments) (
"Value specified for option \"%s\" is " JULONG_FORMAT "%c",
"%s\"%s\" is " JULONG_FORMAT "%c",
memory_argument.is_set() ? specified_val_msg: default_val_msg,
memory_argument.name(),
memory_argument.value()._val,
memory_argument.value()._multiplier);
return;
}
log_error(arguments) (
"Value specified for option \"%s\" is " JULONG_FORMAT,
"%s\"%s\" is " JULONG_FORMAT,
memory_argument.is_set() ? specified_val_msg: default_val_msg,
memory_argument.name(), memory_argument.value()._val);
}

@@ -539,6 +546,10 @@ static bool valid_memory_relations(const JfrMemoryOptions& options) {
return false;
}
}
} else if (options.thread_buffer_size_configured && options.memory_size_configured) {
if (!ensure_first_gteq_second(_dcmd_memorysize, _dcmd_threadbuffersize)) {
return false;
}
}
return true;
}
@@ -607,7 +618,7 @@ template <typename Argument>
static bool ensure_gteq(Argument& memory_argument, const jlong value) {
if ((jlong)memory_argument.value()._size < value) {
log_set_value(memory_argument);
log_lower_than_min_value(memory_argument, value);
log_out_of_range_value<Argument, true>(memory_argument, value);
return false;
}
return true;
@@ -638,14 +649,38 @@ static bool ensure_valid_minimum_sizes() {
return true;
}

template <typename Argument>
static bool ensure_lteq(Argument& memory_argument, const jlong value) {
if ((jlong)memory_argument.value()._size > value) {
log_set_value(memory_argument);
log_out_of_range_value<Argument, false>(memory_argument, value);
return false;
}
return true;
}

static bool ensure_valid_maximum_sizes() {
if (_dcmd_globalbuffersize.is_set()) {
if (!ensure_lteq(_dcmd_globalbuffersize, MAX_GLOBAL_BUFFER_SIZE)) {
return false;
}
}
if (_dcmd_threadbuffersize.is_set()) {
if (!ensure_lteq(_dcmd_threadbuffersize, MAX_THREAD_BUFFER_SIZE)) {
return false;
}
}
return true;
}

/**
* Starting with the initial set of memory values from the user,
* sanitize, enforce min/max rules and adjust to a set of consistent options.
*
* Adjusted memory sizes will be page aligned.
*/
bool JfrOptionSet::adjust_memory_options() {
if (!ensure_valid_minimum_sizes()) {
if (!ensure_valid_minimum_sizes() || !ensure_valid_maximum_sizes()) {
return false;
}
JfrMemoryOptions options;
@@ -654,6 +689,24 @@ bool JfrOptionSet::adjust_memory_options() {
return false;
}
if (!JfrMemorySizer::adjust_options(&options)) {
if (options.buffer_count < MIN_BUFFER_COUNT || options.global_buffer_size < options.thread_buffer_size) {
log_set_value(_dcmd_memorysize);
log_set_value(_dcmd_globalbuffersize);
log_error(arguments) ("%s \"%s\" is " JLONG_FORMAT,
_dcmd_numglobalbuffers.is_set() ? specified_val_msg: default_val_msg,
_dcmd_numglobalbuffers.name(), _dcmd_numglobalbuffers.value());
log_set_value(_dcmd_threadbuffersize);
if (options.buffer_count < MIN_BUFFER_COUNT) {
log_error(arguments) ("numglobalbuffers " JULONG_FORMAT " is less than minimal value " JULONG_FORMAT,
options.buffer_count, MIN_BUFFER_COUNT);
log_error(arguments) ("Decrease globalbuffersize/threadbuffersize or increase memorysize");
} else {
log_error(arguments) ("globalbuffersize " JULONG_FORMAT " is less than threadbuffersize" JULONG_FORMAT,
options.global_buffer_size, options.thread_buffer_size);
log_error(arguments) ("Decrease globalbuffersize or increase memorysize or adjust global/threadbuffersize");
}
return false;
}
if (!check_for_ambiguity(_dcmd_memorysize, _dcmd_globalbuffersize, _dcmd_numglobalbuffers)) {
return false;
}
@@ -28,6 +28,7 @@
import jdk.test.lib.Asserts;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import sun.hotspot.WhiteBox;

/**
* @test
@@ -39,7 +40,10 @@
* java.management
* jdk.jfr
*
* @run main jdk.jfr.startupargs.TestBadOptionValues
* @build ClassFileInstaller
* @build sun.hotspot.WhiteBox
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI jdk.jfr.startupargs.TestBadOptionValues
*/
public class TestBadOptionValues {

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

// globalbuffersize exceeds limit
test(FLIGHT_RECORDER_OPTIONS, "This value is higher than the maximum size limit",
"globalbuffersize=4G");

// threadbuffersize exceeds limit
test(FLIGHT_RECORDER_OPTIONS, "This value is higher than the maximum size limit",
"threadbuffersize=4G");

// computed numglobalbuffers smaller than MIN_BUFFER_COUNT
test(FLIGHT_RECORDER_OPTIONS, "Decrease globalbuffersize/threadbuffersize or increase memorysize",
"memorysize=1m,globalbuffersize=1m");

// memorysize smaller than threadbuffersize
test(FLIGHT_RECORDER_OPTIONS, "The value for option \"threadbuffersize\" should not be larger than the value specified for option \"memorysize\"",
"memorysize=1m,threadbuffersize=2m");

// computed globalbuffersize smaller than threadbuffersize
// test is on when vm page isn't larger than 4K, avoiding both buffer sizes align to vm page size
WhiteBox wb = WhiteBox.getWhiteBox();
long smallPageSize = wb.getVMPageSize();
if (smallPageSize <= 4096) {
test(FLIGHT_RECORDER_OPTIONS, "Decrease globalbuffersize or increase memorysize or adjust global/threadbuffersize",
"memorysize=1m,numglobalbuffers=256");
}

test(FLIGHT_RECORDER_OPTIONS, "Parsing error memory size value: invalid value",
"threadbuffersize=a",
"globalbuffersize=G",
@@ -642,6 +642,11 @@ public static void runTestCase(TestCase tc) throws Exception {
tc.setGlobalBufferSizeTestParam(64, 'k');
tc.setGlobalBufferCountTestParam(16, 'b');
testCases.add(tc);

// threadbuffersize exceeds default memorysize
tc = new TestCase("ThreadBufferSizeExceedMemorySize", false);
tc.setThreadBufferSizeTestParam(30, 'm');
testCases.add(tc);
}

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

1 comment on commit df587c7

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on df587c7 Jun 25, 2021

Please sign in to comment.