-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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-41295: Reimplement the Carlo Verre "hackcheck" #21528
Conversation
… backwards to find the type that originally defined the final tp_setattro, then make sure we are not jumping over intermediate C-level bases with the Python-level call.
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.
The algorithm looks good to me! Just some style nits.
Lib/test/test_descr.py
Outdated
@@ -4308,6 +4308,42 @@ def test_carloverre(self): | |||
else: | |||
self.fail("Carlo Verre __delattr__ succeeded!") | |||
|
|||
def test_carloverre_multiinherit_valid(self): |
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'd add a _
between multi and inherit.
Objects/typeobject.c
Outdated
|
||
/* Reject calls that jump over intermediate C-level overrides. */ | ||
PyTypeObject *base = defining_type; | ||
while (base && base->tp_setattro != func) { |
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 wonder if this would read better if you wrote it as
for (PyTypeObject *base = defining_type; base != NULL; base = base->tp_base) {
if (base->tp_setattro == func) {
/* appropriate comment (same as old code?) */
break;
}
...
(That for-loop is IMO a more idiomatic way to iterate over a linked list.)
Objects/typeobject.c
Outdated
@@ -5977,9 +5989,8 @@ hackcheck(PyObject *self, setattrofunc func, const char *what) | |||
type->tp_name); | |||
return 0; | |||
} | |||
base = base->tp_base; |
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.
(If you follow my suggestion this should go of course.)
Thanks for the review, works for me. |
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.
Thanks!
Do you expect this will require a manual 3.8 backport again? |
@scoder: Status check is done, and it's a success ✅ . |
Thanks @scoder for the PR 🌮🎉.. I'm working now to backport this PR to: 3.8, 3.9. |
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum (cherry picked from commit c53b310) Co-authored-by: scoder <stefan_ml@behnel.de>
GH-21540 is a backport of this pull request to the 3.9 branch. |
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum (cherry picked from commit c53b310) Co-authored-by: scoder <stefan_ml@behnel.de>
GH-21541 is a backport of this pull request to the 3.8 branch. |
The only issue was the test module in C last time. The algorithm and the Python tests applied cleanly to Py3.8. Miss Islington already did her job for this PR. |
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum (cherry picked from commit c53b310) Co-authored-by: scoder <stefan_ml@behnel.de>
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum (cherry picked from commit c53b310) Co-authored-by: scoder <stefan_ml@behnel.de>
|
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum
Python 3.8.4 had a regression on __setattr__ in multi inheritance with metaclasses, which causes jpype to crash on import. see: python/cpython#21528 (py39) which was backported to 3.8 This excludes python 3.8.4 from paquo's supported pythons.
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum
This change has broken some code for us, where we want to skip over a C level definition of It is probably not a super big deal for us, but wanted to have a trace here that this change has broken more stuff that is still "broken" (fixed?) in 3.8.5. |
Couldn’t you use |
Nope. Same error. And even if this solved it in this case, we do have general purpose code that tries |
Yes, that's exactly what the check prevents: reaching behind the back of a superclass implemented in C. Presumably you understand the reason why this is unsafe in general. I don't know why your framework was doing this (getting around an overly restrictive |
I don't really understand no. To me it's strange that classes with C code somewhere are now more different than before. If it's unsafe for C classes why is it safe for python classes? The release notes say this:
This sounds like it would be more allowing ("allow C implemented heap types"), while its actually more restrictive. |
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum
Read about it here: https://mail.python.org/pipermail/python-dev/2003-April/034535.html |
I've read that but it seems to me that the standard library and all C implemented classes are very different things? (Plus what about us being consenting adults?) Anyway, we'll work around this. I just wanted to give a heads up that there might be more projects that will hit this when they upgrade in months or even years. |
Consenting adults shouldn't be able to overwrite arbitrary memory (except through specific APIs intended to do so, i.e. ctypes). If a C type (whether a stdlib type or a user-define type) defines And even for Python classes it's bad style -- but by tradition we don't care enough to forbid it, since the worst you can get is a traceback. And yes, I understand that we're breaking a small amount of code. |
@boxed it looks to me like what you might have wanted at the time is something like |
Walk down the MRO backwards to find the type that originally defined the final `tp_setattro`, then make sure we are not jumping over intermediate C-level bases with the Python-level call. Automerge-Triggered-By: @gvanrossum
Walk down the MRO backwards to find the type that originally defined the final
tp_setattro
, then make sure we are not jumping over intermediate C-level bases with the Python-level call.https://bugs.python.org/issue41295
Automerge-Triggered-By: @gvanrossum