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
intern strings in deepfrozen modules #90588
Comments
Interns strings in deep-frozen modules. |
This speeds up comparison of strings by just comparing their pointers so it is much faster. |
I noticed that the new interning code lacks proper error reporting. There are only asserts. _PyCode_New() checks the return value of intern_strings. |
We discussed that and found that a lot of errors are ignored during interning anyway. But it's not too late to change if you want to (sending a PR would probably be quicker than arguing :-). |
I consider this done so closing it as improving the error handling of interning it out of scope of this issue. |
Please leave the ticket open until we have an agreement how to handle the missing error checks. |
It's regression related to bpo-1635741 which I fixed recently: |
_PyStaticCode_InternStrings() error handling is based on assert(): that's really bad. It can crash Python (exit with abort()) at the first memory allocation failure. Why not returning -1 on error? |
Well, you can check with your favorite memory debugger like Valgrind if you don't trust Python internal memory debugger :-) Not leaking memory at exit matters when Python is embedded in an application. I don't think that it's related to the error handling which is stripped in release mode. |
Sure, but "leaks" caused by deep-freezing cannot be solved by freeing up the deep-frozen memory -- the solution must be to update the accounting somewhere. Where is the existence of Py_None accounted for (since it's statically allocated, or at least used to be)? That's likely where we'd have to do something about the deep-frozen objects. |
Python allocates memory (ex: with PyObject_Malloc()) which is not released at exit. Two examples from Valgrind: ==196803== 50 bytes in 1 blocks are still reachable in loss record 1 of 87 and ==196803== 3,336 bytes in 60 blocks are still reachable in loss record 87 of 87 Before the commit c0a5ebe, Python didn't leak this memory. |
That's pretty mysterious. The deep-freeze code isn't on the stack for either of those, but allocation of new unicode string objects is. I'm guessing these are somehow leaked by the interning, but I don't follow yet how. |
PyUnicode_InternInPlace() in intern_strings() can convert an immortal string to a regular Python strong reference, whereas _PyStaticCode_Dealloc() doesn't bother with clearing co_names, co_consts and co_localsplusnames. |
I tried to hack _PyStaticCode_Dealloc() to free strings, but since immortal objects are half-baken today, calling Py_DECREF() does crash. Py_SETREF() should increase _Py_RefTotal if the old object is immortal and he new object is not. Maybe this change should be reverted until Eric's PEP-683 "Immortal Objects, Using a Fixed Refcount" is implemented. |
I have created a PR to fix the memory leak, See #31549 |
How it should be handled? Currently PyUnicode_InternInPlace ignores any errors and does not return it. It would be backwards-incompatible to change that, moreover as I explained in #30683 (comment) intern_strings only check if all the items are strings which will be always true in case of deep-freeze so I don't think anything needs to be changed here. I would be interested to know if I am missing something though. |
I wrote #31555 to make sure that Python doesn't leak at Python exit. |
The other functions you are calling *do* return errors. You should not ignore those. If any errors are reported the caller can decide what to do (e.g. call Py_FatalError(). |
commit 0d9b565
|
PEP-587 introduced PyStatus to Python startup code which let the Py_Initialize() caller to decide how to handle errors ;-) For example, you can open a graphical popup rather than killing the process with SIGABRT (Py_FatalError() behavior) which might be more user friendly :-D Or just log the error. |
That's up to pycore_interp_init() in pylifecycle.c now. Kumar called _PyStatus_ERR() there, so I think nothing more needs to be done. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: