JDK 20 |
---|
20 masterFixed |
Duplicate :
|
|
Duplicate :
|
|
Relates :
|
|
Relates :
|
From JDK-8295969: I have been assuming that the result of is_unloading() is stable, but that might not be the case. Consider 3 threads, where one thread Patch is calling is_unloading() before patching a compiled call site, thread Clear is calling is_unloading() to see if it the call site should be cleared, and thread Compiler has just set the nmethod state to not_entrant. Now let's say the Patch thread sees the nmethod as is_use and not unloading and decides to patch the call site. The Clear thread sees the nmethod as unloading and decides to clear the call site. The Patch thread writes the cached is_unloading state first with "not unloading", then the Clear thread overwrites it with "is unloading". The call site is first cleared by thread Clear and then patched by thread Patch. The GC unlinks the nmethod, and soon it gets released and the memory recycled. Now we have a compiled call site calling into bad memory. That memory can get overwritten with a new nmethod, and then we have a call into the middle of an nmethod. If the above scenario is indeed possible, then I think the is_cold/make_not_entrant race can be fixed with memory barriers. There may be a similar race with the has_dead_oop path of is_unloading, because C1 patching can add new nmethod oops. It might be better to fix the race in is_unloading. When is_unloading writes the cached result, it could use a compare-and-swap so that the first value written always wins.
|