-
Notifications
You must be signed in to change notification settings - Fork 145
8268524: nmethod::post_compiled_method_load_event racingly called on zombie #107
Conversation
👋 Welcome back eosterlund! A progress list of the required criteria for merging this PR into |
Webrevs
|
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.
seems reasonable
@fisk This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 9 new commits pushed to the
Please see this link for an up-to-date comparison between the source branch of this pull request and the ➡️ To integrate this PR with the above commit message to the |
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.
Looks good.
// release this lock, so we check that this is not going to be the case. | ||
if (is_not_entrant() && can_convert_to_zombie()) { | ||
return; | ||
} | ||
} |
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.
Can't we change state from alive -> not_entrant here? Should this have a mark_as_seen_on_stack somewhere?
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.
not_entrant() is also implicitly is_alive(). That's why we need to check if they are not_entrant() in addition to is_alive(), to see if we are in a scenario where after we release the locks, it may racingly flip to zombie. That only happens for not_entrant nmethods, and we filter out the ones that can happen to by checking can_convert_to_zombie() on those.
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.
Oh duh, yes, we don't have to mark them as seen if they can be converted to zombie here.
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.
Thank you for fixing this!
Could you remove this comment in jvmtiCodeBlobEvents.cpp also since it's wrong? |
Thanks Vladimir and Coleen, for the reviews. |
// Walk the CodeCache notifying for live nmethods. We hold the CodeCache_lock | ||
// to ensure the iteration is safe and nmethods are not concurrently freed. | ||
// However, they may still change states and become !is_alive(). Filtering | ||
// those out is done inside of nmethod::post_compiled_method_load_event(). |
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.
yes I like this.
Thanks Nils for the review. |
/integrate |
Going to push as commit 9ec7180.
Your commit was automatically rebased without conflicts. |
In the code exercised by JvmtiCodeBlobEvents::generate_compiled_method_load_events, we grab a code cache iterator with the NMethodIterator::only_alive_and_not_unloading mode, under the CodeCache_lock. The idea is to then call post_compiled_method_load_event() on each of these is_alive() nmethods. Surely none of them will be a zombie. Inside of post_compiled_method_load_event() we filter out nmethods that racingly can die, like this:
if (is_not_entrant() && can_convert_to_zombie()) {
return;
}
So if the nmethod was dead or is_unloading(), we wouldn't get it into the iterator, and here we explicitly filter out nmethods that can become zombies. Now we should have all bases covered, no way we can end up calling the subsequent code on a zombie!
Except... the code called by the sweeper that flips an nmethod to zombie, doesn't hold the CodeCache_lock. Instead it holds the CompiledMethod_lock, which this JVMTI code does not hold. So between it being alive in the iterator, and calling is_not_entrant(), the nmethod could have racingly already become zombie. So when we check is_not_entrant(), it will return false. Because it's a zombie. Therefore we are tricked into believing the nmethod is safe to post around these events, while in fact it is already dead.
After we have mistakenly grabbed a zombie nmethod, when we use ZGC, we call the nmethod entry barriers on it. It gets indigestion due to being called on a zombie. I'm sure there are more sources of indigestion as well.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk17 pull/107/head:pull/107
$ git checkout pull/107
Update a local copy of the PR:
$ git checkout pull/107
$ git pull https://git.openjdk.java.net/jdk17 pull/107/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 107
View PR using the GUI difftool:
$ git pr show -t 107
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk17/pull/107.diff