RFC: redefine PyTypeObjects as heap types for Limited API compliance#154
Conversation
|
maybe the rabbit hole goes a lot deeper. I think this is just the first symptom of a much broader issue: |
|
FWIW I doubt that this change can be handled simply without dropping Python 2.7 too, but I also don't have a simple way to check. |
|
... which might not be a problem since, IIUC, the extension is only ever compiled for Python 3 anyway |
7124b3e to
dc0a5ac
Compare
|
I got it to compile locally. Hopefully it runs smoothly in CI too. |
dc0a5ac to
d96ef3f
Compare
d96ef3f to
2210fd6
Compare
|
failure is real. I'll probably need to iterate a bit if I cannot reproduce this locally (which remains to be seen) |
|
I can reproduce, this shouldn't take long |
|
shotgun debugging: it seems that this is the block that errors out within the Limited API build if (!PyObject_IsInstance(item, (PyObject*) &SatrecType)) {
PyErr_Format(PyExc_ValueError, "every item must be a Satrec,"
" but element %d is: %R", i, item);
Py_DECREF(item);
return -1;
}from |
2210fd6 to
570c2e8
Compare
406d027 to
02e0e6d
Compare
37685d9 to
8d1c87b
Compare
brandon-rhodes
left a comment
There was a problem hiding this comment.
Thanks again for all of these PRs, which I'll try to make better progress through in May than I did in April. Here are a few questions about this one. Once they're answered, I think it will be ready to merge! This was interesting to read, as it's my first introduction to the new mechanisms for defining types.
| Py_INCREF(&SatrecType); | ||
| if (PyModule_AddObject(m, "Satrec", (PyObject *) &SatrecType) < 0) { | ||
| if (PyModule_AddObject(m, "Satrec", SatrecType) < 0) { | ||
| Py_DECREF(&SatrecType); |
There was a problem hiding this comment.
I think you also need a Py_DECREF(&SatrecArrayType); here, since otherwise you will leak that object by losing the only pointer to it?
There was a problem hiding this comment.
I think that's correct. I also conclude that I can collapse two now-identical blocks.
| extra_compile_args=['-ffloat-store'], | ||
| extra_compile_args=[ | ||
| '-ffloat-store', | ||
| "-std=c++20" if get_default_compiler() != "msvc" else "/std:c++20", |
There was a problem hiding this comment.
Let's add a comment explaining why this is necessary, and why both compilers wouldn't choose the most recent C++ automatically.
There was a problem hiding this comment.
Sure. I'll probably need to revert this part just refresh the logs, because I don't recall the specifics now.
There was a problem hiding this comment.
see this log: https://github.com/brandon-rhodes/python-sgp4/actions/runs/25109895590/job/73581108136?pr=154
extension/wrapper.cpp(22): warning C4200: nonstandard extension used: zero-sized array in struct/union
extension/wrapper.cpp(22): note: This member will be ignored by a defaulted constructor or copy/move assignment operator
extension/wrapper.cpp(202): warning C4244: 'initializing': conversion from 'long' to 'char', possible loss of data
extension/wrapper.cpp(565): error C7555: use of designated initializers requires at least '/std:c++20'
extension/wrapper.cpp(583): error C7555: use of designated initializers requires at least '/std:c++20'
error: command 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Tools\\MSVC\\14.44.35207\\bin\\HostX86\\x86\\cl.exe' failed with exit code 2
I don't know why msvc doesn't pick c++20 on its own though.
There was a problem hiding this comment.
(I added this line back on my latest push so that you can merge this if you want)
There was a problem hiding this comment.
- If
-std=c++20doesn't seem to be needed, then it would be nice to adjust this so that it's not supplied; I'd rather not introduce arguments that aren't necessary. - If you could, adjust the
ifto be positive rather than negative; that's a Raymond Hettinger piece of advice (if I recall?) that does tend to make things more readable for me in the future. - Thanks for digging out those logs! I can add a comment after merging to explain to myself why we have to adjust the MS compile argument.
There was a problem hiding this comment.
Ah, a fellow Hettinbro !
hat tip
|
Answering from my phone right now. 3/4 of your questions require my double-checking. I'll try to squeeze this into my afternoon work session ! |
a355508 to
f919e72
Compare
87a55b1 to
212ce31
Compare
| extra_compile_args=['-ffloat-store'], | ||
| extra_compile_args=[ | ||
| '-ffloat-store', | ||
| "-std=c++20" if get_default_compiler() != "msvc" else "/std:c++20", |
There was a problem hiding this comment.
- If
-std=c++20doesn't seem to be needed, then it would be nice to adjust this so that it's not supplied; I'd rather not introduce arguments that aren't necessary. - If you could, adjust the
ifto be positive rather than negative; that's a Raymond Hettinger piece of advice (if I recall?) that does tend to make things more readable for me in the future. - Thanks for digging out those logs! I can add a comment after merging to explain to myself why we have to adjust the MS compile argument.
| Py_INCREF(&SatrecArrayType); | ||
| if (PyModule_AddObject(m, "SatrecArray", (PyObject *) &SatrecArrayType) < 0) { | ||
| if ((PyModule_AddObject(m, "Satrec", SatrecType) < 0) | ||
| || (PyModule_AddObject(m, "SatrecArray", SatrecArrayType) < 0)) { |
There was a problem hiding this comment.
Alas, I think this introduces an error in the case that the first PyModule_AddObject() succeeds but the second fails: in that case, we wind up calling Py_DECREF(&SatrecType); with the result that SatrecType is freed, even though it's still a member of the module with the name "Satrec". When the module is the finalized and discarded, I think it would experience a double-free?
There was a problem hiding this comment.
Ah, that makes sense. Sorry I didn't think of that.
| if ((PyModule_AddObject(m, "Satrec", SatrecType) < 0) | ||
| || (PyModule_AddObject(m, "SatrecArray", SatrecArrayType) < 0)) { | ||
| Py_DECREF(&SatrecArrayType); | ||
| Py_DECREF(&SatrecType); |
There was a problem hiding this comment.
As I re-read all these decref's, I'm confused about why they say things like Py_DECREF(&SatrecType); rather than Py_DECREF(SatrecType);. Isn't SatrecType already a pointer? With the & added, it looks like it would be trying to free the pointer rather than the object?
There was a problem hiding this comment.
you're right. I don't know where this mistake came from. I probably was thinking compilation would just fail if I passed the wrong type. I'm actually not sure why it didn't. How is PyObject** acceptable where a PyObject* is expected ? (curious to know if you got an explanation for this, but I'll fix this in any case)
There was a problem hiding this comment.
I was asking myself exactly the same question as I was reading it! 🙂 I don't know why the compiler didn't flag it.
|
Thanks so much for the forward progress on this! I've made three final comments which I think should resolve the remaining snags that I might see in the code. |
212ce31 to
18395c0
Compare
|
Great, thank you so much for you careful review. I think all problems you spotted should be addressed now ! |
based off #153
needed for #151
At the time of opening, I'm getting a single compilation error:
I don't have experience with "sub slots", which seem needed for defining the
tp_as_sequenceslot correctly. Hopefully I can crack it soon but in the mean time, any help would be appreciated.