-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
GH-118095: Make invalidating and clearing executors memory safe #118459
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
Conversation
There are no new tests as I can't see a way to test this, especially the out-of-memory checks. |
const _PyExecutorObject *side = executor->exits[i].executor; | ||
executor->exits[i].temperature = initial_unreachable_backoff_counter(); | ||
if (side != cold) { | ||
executor->exits[i].executor = cold; |
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 like the executor owns the reference to exits[i].executor when that is not equal to the cold exit, but not when it is equal. That is potentially confusing.
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.
It owns a reference in both cases, it is just that cold exit executors are immortal, so we can be lose with the refcounting.
_Py_ExecutorClear(exec); | ||
unlink_executor(exec); | ||
if (no_memory) { | ||
exec->vm_data.valid = 0; |
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.
It's really ok to just skip clearing exec in this case?
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.
We never execute an executor with valid == 0
, so it does what says and invalidates the dependent executor.
It might delay later re-optimizations and defer reclaiming some objects.
We've hit a memory error at this point, so the program is probably dying anyway.
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.
We've hit a memory error at this point, so the program is probably dying anyway.
That feels like a dangerous assumption -- an app may have a gigabyte array of temp data somewhere that it can free and retry.
The 32 bit Windows Jit build failure is probably unrelated as it has been flaky lately. |
|
no_memory = true; | ||
exec->vm_data.valid = 0; | ||
} | ||
} | ||
if (is_invalidation) { |
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.
I don't see any calls where this flag is passed as 0, so maybe the flag argument is no longer needed?
This fixes a crash when an executor forms a reference cycle with itself.
This bug has been present for a while, but was only exposed by #118420.
Also fixes another latent bug in
_Py_Executors_InvalidateDependency
, where clearing one executor could clear another leaving the iteration variable pointing to freed memory.The
three main changesamongst the main changes are:_Py_Executors_InvalidateDependency
RESUME
toRESUME_CHECK
: ConvertingENTER_EXECUTOR
toRESUME_CHECK
would loose the executor.