Skip to content
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

bpo-44184: Fix subtype_dealloc() for freed type #26274

Merged
merged 4 commits into from
May 21, 2021
Merged

bpo-44184: Fix subtype_dealloc() for freed type #26274

merged 4 commits into from
May 21, 2021

Conversation

vstinner
Copy link
Member

@vstinner vstinner commented May 20, 2021

Fix a crash at Python exit when a deallocator function removes the
last strong reference to a heap type.

Don't read type memory after calling basedealloc() since
basedealloc() can deallocate the type and free its memory.

https://bugs.python.org/issue44184

@vstinner
Copy link
Member Author

cc @pablogsal @erlend-aasland

Copy link
Member

@pablogsal pablogsal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix makes no sense to me, if what you say in the comment was actually the root cause, we would be seeing this under vallgrind or the address sanitizer and I could not reproduce it

@bedevere-bot
Copy link

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

@pablogsal
Copy link
Member

pablogsal commented May 21, 2021

This is enough to crash it:

import ast
import builtins
import sys
import os

tree = ast.parse("pass")
x = [tree]
x.append(x)

# Put the cycle somewhere to survive until the *last* GC collection
def callback(*args):
    pass
callback.a = x
os.register_at_fork(after_in_child=callback)

can we maybe add a test based on this?

@vstinner
Copy link
Member Author

I would prefer to not rely directly on os.register_at_fork() to ensure that the object will survive until the last GC collection. I would prefer an abstraction function in the test.support module. I will try to add a test.

@erlend-aasland
Copy link
Contributor

I can reproduce the bug on macOS using the address sanitiser. The patch also fixes the buildbot problems on #24203 (comment)

Fix a crash at Python exit when a deallocator function removes the
last strong reference to a heap type.

Don't read type memory after calling basedealloc() since
basedealloc() can deallocate the type and free its memory.
@vstinner
Copy link
Member Author

@pablogsal: I added an unit test, would you mind to review the updated PR?

I was too lazy to add an abstraction. Since the test is in test_gc, IMO it's ok. First, I wanted to add the test to test_ast.

@vstinner
Copy link
Member Author

Ah, register_at_fork() is not available on Windows. I modified my test to use codecs.register() instead.

You can test manually that the unit test fails as expected with this change:

diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index af99ab79d1..acbedc64e6 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -5,6 +5,7 @@
 #include "pycore_compile.h"       // _Py_Mangle()
 #include "pycore_initconfig.h"
 #include "pycore_moduleobject.h"  // _PyModule_GetDef()
+#include "pycore_pymem.h"  // _PyModule_GetDef()
 #include "pycore_object.h"
 #include "pycore_pyerrors.h"
 #include "pycore_pystate.h"       // _PyThreadState_GET()
@@ -1459,6 +1460,7 @@ subtype_dealloc(PyObject *self)
        our type from a HEAPTYPE to a non-HEAPTYPE, so be careful about
        reference counting. Only decref if the base type is not already a heap
        allocated type. Otherwise, basedealloc should have decref'd it already */
+    assert(!_PyMem_IsPtrFreed(type->tp_name));
     if (type_needs_decref) {
         Py_DECREF(type);
     }

Copy link
Contributor

@erlend-aasland erlend-aasland left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@vstinner vstinner merged commit 615069e into python:main May 21, 2021
@vstinner vstinner deleted the subtype_dealloc branch May 21, 2021 17:19
@vstinner vstinner added the needs backport to 3.10 only security fixes label May 21, 2021
@miss-islington
Copy link
Contributor

Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.10.
🐍🍒⛏🤖

@bedevere-bot bedevere-bot removed the needs backport to 3.10 only security fixes label May 21, 2021
@bedevere-bot
Copy link

GH-26290 is a backport of this pull request to the 3.10 branch.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request May 21, 2021
Fix a crash at Python exit when a deallocator function removes the
last strong reference to a heap type.

Don't read type memory after calling basedealloc() since
basedealloc() can deallocate the type and free its memory.

_PyMem_IsPtrFreed() argument is now constant.
(cherry picked from commit 615069e)

Co-authored-by: Victor Stinner <vstinner@python.org>
@vstinner
Copy link
Member Author

Thanks for reviews @pablogsal and @erlend-aasland!

vstinner added a commit that referenced this pull request May 21, 2021
Fix a crash at Python exit when a deallocator function removes the
last strong reference to a heap type.

Don't read type memory after calling basedealloc() since
basedealloc() can deallocate the type and free its memory.

_PyMem_IsPtrFreed() argument is now constant.
(cherry picked from commit 615069e)

Co-authored-by: Victor Stinner <vstinner@python.org>

Co-authored-by: Victor Stinner <vstinner@python.org>
Yhg1s added a commit to Yhg1s/cpython that referenced this pull request Jul 15, 2021
… it is also

trying to use a type after it's potentially been freed.
Yhg1s added a commit that referenced this pull request Jul 15, 2021
GH-27165)

The non-GC-type branch of subtype_dealloc is using the type of an object after freeing in the same unsafe way as GH-26274 fixes. (I believe the old news entry covers this change well enough.)

https://bugs.python.org/issue44184
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jul 15, 2021
…dealloc (pythonGH-27165)

The non-GC-type branch of subtype_dealloc is using the type of an object after freeing in the same unsafe way as pythonGH-26274 fixes. (I believe the old news entry covers this change well enough.)

https://bugs.python.org/issue44184
(cherry picked from commit 074e765)

Co-authored-by: T. Wouters <thomas@python.org>
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jul 15, 2021
…dealloc (pythonGH-27165)

The non-GC-type branch of subtype_dealloc is using the type of an object after freeing in the same unsafe way as pythonGH-26274 fixes. (I believe the old news entry covers this change well enough.)

https://bugs.python.org/issue44184
(cherry picked from commit 074e765)

Co-authored-by: T. Wouters <thomas@python.org>
@Yhg1s Yhg1s added the needs backport to 3.9 only security fixes label Jul 15, 2021
@miss-islington
Copy link
Contributor

Thanks @vstinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.9.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jul 15, 2021
Fix a crash at Python exit when a deallocator function removes the
last strong reference to a heap type.

Don't read type memory after calling basedealloc() since
basedealloc() can deallocate the type and free its memory.

_PyMem_IsPtrFreed() argument is now constant.
(cherry picked from commit 615069e)

Co-authored-by: Victor Stinner <vstinner@python.org>
@bedevere-bot bedevere-bot removed the needs backport to 3.9 only security fixes label Jul 15, 2021
@bedevere-bot
Copy link

GH-27176 is a backport of this pull request to the 3.9 branch.

Yhg1s added a commit that referenced this pull request Jul 15, 2021
GH-27165) (GH-27174)

The non-GC-type branch of subtype_dealloc is using the type of an object after freeing in the same unsafe way as GH-26274 fixes. (I believe the old news entry covers this change well enough.)

https://bugs.python.org/issue44184
(cherry picked from commit 074e765)

Co-authored-by: T. Wouters <thomas@python.org>
Yhg1s added a commit that referenced this pull request Jul 15, 2021
GH-27165) (GH-27175)

The non-GC-type branch of subtype_dealloc is using the type of an object after freeing in the same unsafe way as GH-26274 fixes. (I believe the old news entry covers this change well enough.)

https://bugs.python.org/issue44184
(cherry picked from commit 074e765)

Co-authored-by: T. Wouters <thomas@python.org>
miss-islington added a commit that referenced this pull request Jul 15, 2021
Fix a crash at Python exit when a deallocator function removes the
last strong reference to a heap type.

Don't read type memory after calling basedealloc() since
basedealloc() can deallocate the type and free its memory.

_PyMem_IsPtrFreed() argument is now constant.
(cherry picked from commit 615069e)

Co-authored-by: Victor Stinner <vstinner@python.org>
@encukou
Copy link
Member

encukou commented Oct 21, 2021

For posterity: bpo-42961 reports the same issue and has a nice reproducer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants