-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8365526: Crash with null Symbol passed to SystemDictionary::resolve_or_null #28438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
6123316
8e7be57
8d30c17
c959cfe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1864,14 +1864,17 @@ void SystemDictionary::add_nest_host_error(const constantPoolHandle& pool, | |
| { | ||
| MutexLocker ml(Thread::current(), SystemDictionary_lock); | ||
| ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which); | ||
| if (entry != nullptr && entry->nest_host_error() == nullptr) { | ||
| if (entry == nullptr) { | ||
| // Only add a new resolution error if one hasn't been found for this constant pool index. In this case, | ||
| // resolution succeeded but there's an error in this nest host. | ||
| assert(pool->resolved_klass_at(which) != nullptr, "klass should be resolved if there is no entry"); | ||
| ResolutionErrorTable::add_entry(pool, which, message); | ||
| } else { | ||
| // An existing entry means we had a true resolution failure (LinkageError) with our nest host, but we | ||
| // still want to add the error message for the higher-level access checks to report. We should | ||
| // only reach here under the same error condition, so we can ignore the potential race with setting | ||
| // the message. If we see it is already set then we can ignore it. | ||
| // the message, and set it again. | ||
| entry->set_nest_host_error(message); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Existing -- shouldn't we free the old Also, there's a related memory leak here:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the const char* msg = ss.as_string(true /* on C-heap */);
constantPoolHandle cph(THREAD, constants());
SystemDictionary::add_nest_host_error(cph, _nest_host_index, msg);
// ... down the callstack we go, reaching the constructor call:
ResolutionErrorEntry *entry = new ResolutionErrorEntry(message);
ResolutionErrorEntry(const char* message):
_error(nullptr),
_message(nullptr),
_cause(nullptr),
_cause_msg(nullptr),
_nest_host_error(message) {} // <-- NooooAs opposed to the other constructor, which looks like this: // This is the call to the constructor this time:
ResolutionErrorEntry *entry = new ResolutionErrorEntry(error, message, cause, cause_msg);
ResolutionErrorEntry::ResolutionErrorEntry(Symbol* error, const char* message,
Symbol* cause, const char* cause_msg):
_error(error),
_message(message != nullptr ? os::strdup(message) : nullptr),
_cause(cause),
_cause_msg(cause_msg != nullptr ? os::strdup(cause_msg) : nullptr),
_nest_host_error(nullptr) {
Symbol::maybe_increment_refcount(_error);
Symbol::maybe_increment_refcount(_cause);
}This is actually pretty bad :-/, I'd really appreciate it if we could make these types of bugs a bit more shallow at the time of writing them. Maybe it'd be nice to have a type that tells the reader that an object doesn't intend to free a received pointer on its destruction? This is a very small sketch of something illustrating kind of what I mean: template<typename T>
using Borrow = T*;
template<typename T>
using Own = T*;
// "I'll take a string, but I don't intend to be responsible for freeing it"
const char* os::strdup(Borrow<const char>, MemTag) { /* ... */}
class SystemDictionary {
Own<const char> _message; // I own this, and so I intend to free it when I'm destroyed
Own<const char> _cause_msg; // Same here
// "I'll take a message and a cause_msg, and I won't be responsible for freeing it"
void SystemDictionary::add_resolution_error(const constantPoolHandle& pool, int which,
Symbol* error, Borrow<const char> message,
Symbol* cause, Borrow<const char> cause_msg) :
// Reader meant to think: Wait, we're assigning a Borrow to an Own directly? Seems wrong.
_message(message),
// Reader meant to think: Aah, we're making a copy to get ownership
_cause_msg(os::strdup(cause_msg))
{
/* ... */
}
};This will make no compiler errors for us in case of incorrect usage, but it will be a sign to the reader that I'm not suggesting this is what we add, I'm just saying that clearly we can communicate more in the code than we currently do.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made a ticket for this: 8372373
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As Johan said in the first case, the message and cause are resource allocated so not owned by the ResolvedErrorEntry, so that's not a leak. I have to read the code around the nest host error again to comment. I would not like this strange template around ownership. Also, set_nest_host_error() does not need to free the existing error because it's only set if it's null. So nothing to free.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my change, the case that ignores setting the nest_host_error should free it for now. Yes, I think this should be improved further. |
||
| } else { | ||
| ResolutionErrorTable::add_entry(pool, which, message); | ||
| } | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The above 3 lines can be replaced with
_resolution_error_table->put_when_absent(key, entry).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I use that, I lose the ability to assert that the new entry was created and not already found, which I really want.