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

gh-103333: Pickle the keyword attributes of AttributeError #103352

Merged
merged 7 commits into from
May 12, 2023

Conversation

csm10495
Copy link
Contributor

@csm10495 csm10495 commented Apr 7, 2023

gh-103333: Pickle the keyword attributes of AttributeError

This should fix the case where pickling/unpickling an AttributeError loses the name/obj fields.

If this looks ok, I'd be happy to add a unit test, blurb, etc.

@Eclips4
Copy link
Member

Eclips4 commented Apr 7, 2023

Hello!
There's would be nice to have a tests for it case.

@csm10495
Copy link
Contributor Author

csm10495 commented Apr 7, 2023

Sure, I'll write tests, update blurb once I know that this approach is likely to be accepted :)

@gaogaotiantian
Copy link
Member

It won't be a rare case when the object is not picklable right? Won't that make a picklable Exception non-picklable with this change?

@csm10495
Copy link
Contributor Author

csm10495 commented Apr 7, 2023

In theory yeah, if the object isn't picklable it would not work well here. Though this format follows in line with how other exceptions are made to be picklable (like OSError). Is there a way to somehow check if the obj, etc. are picklable and set them in that case (and if not, just leave as None (as it is now))?

@csm10495
Copy link
Contributor Author

csm10495 commented Apr 7, 2023

I wonder if there should be some sort of pickle mode that pickles all it can and for the fields it couldn't pickle: set to None or something else. Maybe even it could recurse and make a new object with 'as many fields as it could serialize' again.

@gaogaotiantian
Copy link
Member

I think OSError guarantees that all the arguments are picklable(at least when used correctly). I'm not 100% sure but I believe that some of the standard libraries rely on the fact that all the built-in Exceptions are picklable - multiprocesing is one of them if I remember correctly. Not sure if making a built-in Exception unpicklable is an option here. I think @iritkatriel has been working on Exceptions a lot and must have a much better understanding than I do.

@csm10495
Copy link
Contributor Author

csm10495 commented Apr 7, 2023

The original issue came from a user using AttributeError via multiprocessing and the .name attribute was lost via the pickle. .. maybe a middle ground is to just serialize .name and postpone the conversation on .obj?

@gaogaotiantian
Copy link
Member

Having an Exception that loses attributes after pickling is definitely better than having one that is not picklable sometimes. Supporting pickling the name attribute seems reasonable to me, but the core devs are the final decision makers.

@csm10495
Copy link
Contributor Author

csm10495 commented Apr 9, 2023

Updated PR to not pickle obj. Also updated a test to hit this change as well.

@iritkatriel
Copy link
Member

CC @serhiy-storchaka re pickle.

@csm10495
Copy link
Contributor Author

@iritkatriel @serhiy-storchaka any chance for a merge or feedback?

@csm10495
Copy link
Contributor Author

@iritkatriel @serhiy-storchaka please provide feedback and/merge. Thanks.

@arhadthedev arhadthedev added 3.11 only security fixes 3.12 bugs and security fixes labels Apr 21, 2023
Lib/test/test_exceptions.py Outdated Show resolved Hide resolved
Objects/exceptions.c Outdated Show resolved Hide resolved
Objects/exceptions.c Outdated Show resolved Hide resolved
@bedevere-bot
Copy link

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@gpshead
Copy link
Member

gpshead commented May 10, 2023

I left some comments, but I don't feel confident judging what changes to something that gets pickled are valid compatibility wise as I generally avoid use of pickle outside of tightly controlled scenarios.

Will there be any compatibility issue with an AttributeError pickled by this PR being loaded in a Python process running an older Python version without this PR?

@csm10495
Copy link
Contributor Author

csm10495 commented May 11, 2023

@gpshead I updated based off your feedback. In terms of pickle-ability it works out well:

Python 3.12.0a7+ (heads/attributeerror_pickling-dirty:0ee8b8cb, May 10 2023, 19:09:08) [MSC v.1932 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = AttributeError(name='test123')
>>> print(a.name)
test123
>>> import pickle
>>> pickle.dumps(a)
b'\x80\x04\x95@\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x0eAttributeError\x94\x93\x94)R\x94}\x94(\x8c\x04name\x94\x8c\x07test123\x94\x8c\x04args\x94)ub.'
>>> pickle.loads(_).name
'test123'
>>>

Then in Python 3.11 I try to use the dumped pickle bytes:

Python 3.11.0 (main, Oct 24 2022, 18:26:48) [MSC v.1933 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> a = pickle.loads(b'\x80\x04\x95@\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x0eAttributeError\x94\x93\x94)R
>>> a.name
'test123'
>>> pickle.dumps(AttributeError(name='hello'))
b'\x80\x04\x95"\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x0eAttributeError\x94\x93\x94)R\x94.'

Then back in 3.12.0a7, using that pickle data works, albeit without the name field (which makes sense since the old Python doesn't pickle the field):

>>> pickle.loads(b'\x80\x04\x95"\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x0eAttributeError\x94\x93\x94)R\x94.')
AttributeError()
>>> pickle.loads(b'\x80\x04\x95"\x00\x00\x00\x00\x00\x00\x00\x8c\x08builtins\x94\x8c\x0eAttributeError\x94\x93\x94)R\x94.').name

Does this seem ok for merge now?

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.

PEP-7 nits

Objects/exceptions.c Outdated Show resolved Hide resolved
Objects/exceptions.c Outdated Show resolved Hide resolved
Objects/exceptions.c Outdated Show resolved Hide resolved
Co-authored-by: Erlend E. Aasland <[email protected]>
@csm10495
Copy link
Contributor Author

Fixed nits. Thanks!

@gpshead gpshead added type-feature A feature request or enhancement and removed 3.11 only security fixes labels May 12, 2023
@gpshead gpshead merged commit 79b17f2 into python:main May 12, 2023
@iritkatriel
Copy link
Member

There is a refleak now in this test, could it be this PR?

% ./python.exe -m test -R3:3 test_exceptions -m testAttributes 
Raised RLIMIT_NOFILE: 256 -> 1024
0:00:00 load avg: 3.46 Run tests sequentially
0:00:00 load avg: 3.46 [1/1] test_exceptions
beginning 6 repetitions
123456
......
test_exceptions leaked [18, 18, 18] references, sum=54
test_exceptions leaked [12, 12, 12] memory blocks, sum=36
test_exceptions failed (reference leak)

== Tests result: FAILURE ==

1 test failed:
    test_exceptions

Total duration: 256 ms
Tests result: FAILURE

@iritkatriel
Copy link
Member

See #104454

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.12 bugs and security fixes type-feature A feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants