8304684: Memory leak in DirectivesParser::set_option_flag

Reviewed-by: kvn, dlong
This commit is contained in:
Justin King 2023-10-20 11:02:38 +00:00 committed by Tobias Hartmann
parent a03767cf88
commit deadb9c8d7
3 changed files with 90 additions and 24 deletions

View File

@ -287,11 +287,12 @@ void DirectiveSet::init_control_intrinsic() {
}
DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(nullptr), _directive(d) {
#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue;
_ideal_phase_name_mask = 0;
#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue;
compilerdirectives_common_flags(init_defaults_definition)
compilerdirectives_c2_flags(init_defaults_definition)
compilerdirectives_c1_flags(init_defaults_definition)
#undef init_defaults_definition
memset(_modified, 0, sizeof(_modified));
_intrinsic_control_words.fill_in(/*default value*/TriBool());
}
@ -304,6 +305,12 @@ DirectiveSet::~DirectiveSet() {
delete tmp;
tmp = next;
}
#define free_string_flags(name, type, dvalue, cc_flag) if (_modified[name##Index]) os::free(const_cast<char*>(name##Option));
compilerdirectives_common_string_flags(free_string_flags)
compilerdirectives_c2_string_flags(free_string_flags)
compilerdirectives_c1_string_flags(free_string_flags)
#undef free_string_flags
}
// A smart pointer of DirectiveSet. It uses Copy-on-Write strategy to avoid cloning.
@ -407,6 +414,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle
compilerdirectives_common_flags(init_default_cc)
compilerdirectives_c2_flags(init_default_cc)
compilerdirectives_c1_flags(init_default_cc)
#undef init_default_cc
// Parse PrintIdealPhaseName and create an efficient lookup mask
#ifndef PRODUCT
@ -585,9 +593,21 @@ DirectiveSet* DirectiveSet::clone(DirectiveSet const* src) {
}
#define copy_members_definition(name, type, dvalue, cc_flag) set->name##Option = src->name##Option;
compilerdirectives_common_flags(copy_members_definition)
compilerdirectives_c2_flags(copy_members_definition)
compilerdirectives_c1_flags(copy_members_definition)
compilerdirectives_common_other_flags(copy_members_definition)
compilerdirectives_c2_other_flags(copy_members_definition)
compilerdirectives_c1_other_flags(copy_members_definition)
#undef copy_members_definition
#define copy_string_members_definition(name, type, dvalue, cc_flag) \
if (src->_modified[name##Index]) { \
set->name##Option = os::strdup_check_oom(src->name##Option, mtCompiler); \
} else { \
set->name##Option = src->name##Option; \
}
compilerdirectives_common_string_flags(copy_string_members_definition)
compilerdirectives_c2_string_flags(copy_string_members_definition)
compilerdirectives_c1_string_flags(copy_string_members_definition)
#undef copy_string_members_definition
set->_intrinsic_control_words = src->_intrinsic_control_words;
set->_ideal_phase_name_mask = src->_ideal_phase_name_mask;

View File

@ -35,7 +35,7 @@
#include "utilities/tribool.hpp"
// Directives flag name, type, default value, compile command name
#define compilerdirectives_common_flags(cflags) \
#define compilerdirectives_common_other_flags(cflags) \
cflags(Enable, bool, false, Unknown) \
cflags(Exclude, bool, false, Unknown) \
cflags(BreakAtExecute, bool, false, BreakAtExecute) \
@ -51,18 +51,28 @@
cflags(DumpReplay, bool, false, DumpReplay) \
cflags(DumpInline, bool, false, DumpInline) \
cflags(CompilerDirectivesIgnoreCompileCommands, bool, CompilerDirectivesIgnoreCompileCommands, Unknown) \
cflags(DisableIntrinsic, ccstrlist, DisableIntrinsic, DisableIntrinsic) \
cflags(ControlIntrinsic, ccstrlist, ControlIntrinsic, ControlIntrinsic) \
cflags(RepeatCompilation, intx, RepeatCompilation, RepeatCompilation)
#define compilerdirectives_common_string_flags(cflags) \
cflags(DisableIntrinsic, ccstrlist, DisableIntrinsic, DisableIntrinsic) \
cflags(ControlIntrinsic, ccstrlist, ControlIntrinsic, ControlIntrinsic)
#define compilerdirectives_common_flags(cflags) \
compilerdirectives_common_other_flags(cflags) \
compilerdirectives_common_string_flags(cflags)
#ifdef COMPILER1
#define compilerdirectives_c1_flags(cflags)
#define compilerdirectives_c1_other_flags(cflags)
#define compilerdirectives_c1_string_flags(cflags)
#else
#define compilerdirectives_c1_flags(cflags)
#define compilerdirectives_c1_other_flags(cflags)
#define compilerdirectives_c1_string_flags(cflags)
#endif
#define compilerdirectives_c1_flags(cflags) \
compilerdirectives_c1_other_flags(cflags) \
compilerdirectives_c1_string_flags(cflags)
#ifdef COMPILER2
#define compilerdirectives_c2_flags(cflags) \
#define compilerdirectives_c2_other_flags(cflags) \
cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \
cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \
cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \
@ -70,7 +80,6 @@ NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipe
NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \
NOT_PRODUCT(cflags(TraceEscapeAnalysis, bool, false, TraceEscapeAnalysis)) \
NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \
NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) \
cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \
cflags(Vectorize, bool, false, Vectorize) \
cflags(CloneMapDebug, bool, false, CloneMapDebug) \
@ -78,10 +87,17 @@ NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLeve
cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \
cflags(IncrementalInlineForceCleanup, bool, IncrementalInlineForceCleanup, IncrementalInlineForceCleanup) \
cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit)
#define compilerdirectives_c2_string_flags(cflags) \
NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase))
#else
#define compilerdirectives_c2_flags(cflags)
#define compilerdirectives_c2_other_flags(cflags)
#define compilerdirectives_c2_string_flags(cflags)
#endif
#define compilerdirectives_c2_flags(cflags) \
compilerdirectives_c2_other_flags(cflags) \
compilerdirectives_c2_string_flags(cflags)
class AbstractCompiler;
class CompilerDirectives;
class DirectiveSet;
@ -140,6 +156,7 @@ public:
compilerdirectives_common_flags(enum_of_flags)
compilerdirectives_c2_flags(enum_of_flags)
compilerdirectives_c1_flags(enum_of_flags)
#undef enum_of_flags
number_of_flags
} flags;
@ -150,12 +167,32 @@ public:
compilerdirectives_common_flags(flag_store_definition)
compilerdirectives_c2_flags(flag_store_definition)
compilerdirectives_c1_flags(flag_store_definition)
#undef flag_store_definition
// Casting to get the same function signature for all setters. Used from parser.
#define set_function_definition(name, type, dvalue, cc_flag) void set_##name(void* value) { type val = *(type*)value; name##Option = val; _modified[name##Index] = true; }
compilerdirectives_common_flags(set_function_definition)
compilerdirectives_c2_flags(set_function_definition)
compilerdirectives_c1_flags(set_function_definition)
compilerdirectives_common_other_flags(set_function_definition)
compilerdirectives_c2_other_flags(set_function_definition)
compilerdirectives_c1_other_flags(set_function_definition)
#undef set_function_definition
// Casting to get the same function signature for all setters. Used from parser.
//
// IMPORTANT: Takes ownership, will use os::free. Ensure the memory was dynamically allocated on the
// C heap.
#define set_string_function_definition(name, type, dvalue, cc_flag) \
void set_##name(void* value) { \
if (_modified[name##Index]) { \
os::free(const_cast<char*>(name##Option)); \
} \
type val = *(type*)value; \
name##Option = val; \
_modified[name##Index] = true; \
}
compilerdirectives_common_string_flags(set_string_function_definition)
compilerdirectives_c2_string_flags(set_string_function_definition)
compilerdirectives_c1_string_flags(set_string_function_definition)
#undef set_string_function_definition
void set_ideal_phase_mask(uint64_t mask) { _ideal_phase_name_mask = mask; };
uint64_t ideal_phase_mask() { return _ideal_phase_name_mask; };
@ -174,6 +211,7 @@ void print(outputStream* st) {
compilerdirectives_common_flags(print_function_definition)
compilerdirectives_c2_flags(print_function_definition)
compilerdirectives_c1_flags(print_function_definition)
#undef print_function_definition
st->cr();
}
};

View File

@ -315,35 +315,43 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti
error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]);
return false;
} else {
char* s = NEW_C_HEAP_ARRAY(char, v->str.length+1, mtCompiler);
char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler);
strncpy(s, v->str.start, v->str.length + 1);
s[v->str.length] = '\0';
(set->*test)((void *)&s);
bool valid = true;
if (strncmp(option_key->name, "ControlIntrinsic", 16) == 0) {
ControlIntrinsicValidator validator(s, false/*disabled_all*/);
if (!validator.is_valid()) {
valid = validator.is_valid();
if (!valid) {
error(VALUE_ERROR, "Unrecognized intrinsic detected in ControlIntrinsic: %s", validator.what());
return false;
}
} else if (strncmp(option_key->name, "DisableIntrinsic", 16) == 0) {
ControlIntrinsicValidator validator(s, true/*disabled_all*/);
if (!validator.is_valid()) {
valid = validator.is_valid();
if (!valid) {
error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what());
return false;
}
} else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) {
uint64_t mask = 0;
PhaseNameValidator validator(s, mask);
if (!validator.is_valid()) {
valid = validator.is_valid();
if (valid) {
set->set_ideal_phase_mask(mask);
} else {
error(VALUE_ERROR, "Unrecognized phase name detected in PrintIdealPhase: %s", validator.what());
return false;
}
set->set_ideal_phase_mask(mask);
}
if (!valid) {
FREE_C_HEAP_ARRAY(char, s);
return false;
}
(set->*test)((void *)&s); // Takes ownership.
}
break;