8364501: Compiler shutdown crashes on access to deleted CompileTask

Reviewed-by: kvn, mhaessig
This commit is contained in:
Aleksey Shipilev 2025-08-11 18:49:37 +00:00
parent e9e331b2a9
commit 958383d69c
3 changed files with 18 additions and 8 deletions

View file

@ -371,6 +371,7 @@ void CompileQueue::delete_all() {
// Iterate over all tasks in the compile queue
while (current != nullptr) {
CompileTask* next = current->next();
if (!current->is_blocking()) {
// Non-blocking task. No one is waiting for it, delete it now.
delete current;
@ -379,7 +380,7 @@ void CompileQueue::delete_all() {
// to delete the task. We cannot delete it here, because we do not
// coordinate with waiters. We will notify the waiters later.
}
current = current->next();
current = next;
}
_first = nullptr;
_last = nullptr;
@ -504,6 +505,8 @@ void CompileQueue::remove(CompileTask* task) {
assert(task == _last, "Sanity");
_last = task->prev();
}
task->set_next(nullptr);
task->set_prev(nullptr);
--_size;
++_total_removed;
}
@ -1728,17 +1731,22 @@ void CompileBroker::wait_for_completion(CompileTask* task) {
// It is harmless to check this status without the lock, because
// completion is a stable property.
if (!task->is_complete() && is_compilation_disabled_forever()) {
// Task is not complete, and we are exiting for compilation shutdown.
// The task can still be executed by some compiler thread, therefore
// we cannot delete it. This will leave task allocated, which leaks it.
// At this (degraded) point, it is less risky to abandon the task,
// rather than attempting a more complicated deletion protocol.
if (!task->is_complete()) {
// Task is not complete, likely because we are exiting for compilation
// shutdown. The task can still be reached through the queue, or executed
// by some compiler thread. There is no coordination with either MCQ lock
// holders or compilers, therefore we cannot delete the task.
//
// This will leave task allocated, which leaks it. At this (degraded) point,
// it is less risky to abandon the task, rather than attempting a more
// complicated deletion protocol.
free_task = false;
}
if (free_task) {
assert(task->is_complete(), "Compilation should have completed");
assert(task->next() == nullptr && task->prev() == nullptr,
"Completed task should not be in the queue");
// By convention, the waiter is responsible for deleting a
// blocking CompileTask. Since there is only one waiter ever

View file

@ -74,6 +74,7 @@ CompileTask::CompileTask(int compile_id,
_arena_bytes = 0;
_next = nullptr;
_prev = nullptr;
Atomic::add(&_active_tasks, 1, memory_order_relaxed);
}

View file

@ -101,7 +101,8 @@ class CompileTask : public CHeapObj<mtCompiler> {
#endif
int _comp_level;
int _num_inlined_bytecodes;
CompileTask* _next, *_prev;
CompileTask* _next;
CompileTask* _prev;
// Fields used for logging why the compilation was initiated:
jlong _time_queued; // time when task was enqueued
jlong _time_started; // time when compilation started