-
-
Notifications
You must be signed in to change notification settings - Fork 35k
gh-142663: Fix use-after-free in memoryview comparison #143305
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
base: main
Are you sure you want to change the base?
Changes from all commits
edd566c
06846a9
0694b20
8a90934
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Fix use-after-free crashes when a :class:`memoryview` is mutated | ||
| during a comparison with another object. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -3243,7 +3243,8 @@ memory_richcompare(PyObject *v, PyObject *w, int op) | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| if (PyMemoryView_Check(w)) { | ||||||
| int w_is_mv = PyMemoryView_Check(w); | ||||||
| if (w_is_mv) { | ||||||
| if (BASE_INACCESSIBLE(w)) { | ||||||
| equal = (v == w); | ||||||
| goto result; | ||||||
|
|
@@ -3286,6 +3287,13 @@ memory_richcompare(PyObject *v, PyObject *w, int op) | |||||
| goto result; | ||||||
| } | ||||||
| } | ||||||
| /* Prevent memoryview object from being released and its underlying buffer | ||||||
| reshaped during a mixed format comparison loop. */ | ||||||
| // See https://github.com/python/cpython/issues/142663. | ||||||
|
Comment on lines
+3290
to
+3292
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not mix different types of comments, especially in such proximity. Drop the URL, the NEWS/PR already carry the issue link. |
||||||
| ((PyMemoryViewObject *)v)->exports++; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All other modifications of
Suggested change
|
||||||
| if (w_is_mv) { | ||||||
| ((PyMemoryViewObject *)w)->exports++; | ||||||
| } | ||||||
|
|
||||||
| if (vv->ndim == 0) { | ||||||
| equal = unpack_cmp(vv->buf, ww->buf, | ||||||
|
|
@@ -3304,6 +3312,11 @@ memory_richcompare(PyObject *v, PyObject *w, int op) | |||||
| vfmt, unpack_v, unpack_w); | ||||||
| } | ||||||
|
|
||||||
| ((PyMemoryViewObject *)v)->exports--; | ||||||
| if (w_is_mv) { | ||||||
| ((PyMemoryViewObject *)w)->exports--; | ||||||
| } | ||||||
|
|
||||||
| result: | ||||||
| if (equal < 0) { | ||||||
| if (equal == MV_COMPARE_NOT_IMPL) | ||||||
|
|
||||||
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.
This line puzzles me a little bit. When you swap classes in the stdlib, you can get unexpected results. Can we replicate this without monkeypatching?
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.
Hi @sobolevn I doubt the possibility of replicating this without monkeypatching. The issue stems from, during a mixed format buffer comparison,
memory_richcomparefunction calls a re-entrantstruct.Struct.unpack_fromthat is loaded by aPyImport_ImportModuleAttrString("struct", "Struct")call in the struct_get_unpacker. Is there anyway you would recommend to work around it ?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.
There are countless potential issues if we replace stdlib types with something else. Let's please first discuss in the issue whether this is even a valid bug report.
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 did consider it as a crash because we also fixed similar occurrences elsewhere. If we just had an exception it would have been ok, but here we have a crash. We do not want this.
Uh oh!
There was an error while loading. Please reload this page.
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 see there are many tests having monkey patch. Why does this case make difference? Is there any update regarding this pr or should we @ more core dev to take a look?
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.
struct_get_unpackerlooks inefficient. We may add a cache forstruct.Structin future. Or we can cache the boundunpack_from()methods. Anyway, monkey-patchingstruct.Structwill either not have any effect or will affect all following code. I suspect that after I wrote this, someone might take it as a challenge.I do not see a good solution for this. We might run the tests in a subprocess to reduce affect on other code, but this is too much hassle (and this is not 100% future proof). Perhaps it would be safer to not add a test.
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.
Drop the tests, future changes can make it unsafe. Add a simple reproducer script in the PR or in the issue, so we can test the fix manually.