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

Avoid exporting incorrect PyInit_* symbols #12889

Merged
merged 1 commit into from
Aug 2, 2024

Conversation

jakelishman
Copy link
Member

Summary

Using the #[pymodule] derive macro in PyO3 0.21 always causes a PyInit_* symbol with a matching name to be exported in the output cdylib. This is required for the top-level module, in order for Python to import it---it needs to know which symbol in a shared library file it should call---but submodules must be manually initialised, so do not need it. Including it is typically harmless (and something we've been doing for a long time), but it is technically against the coding rules for CPython extensions1.

Recent versions of abi3audit (0.0.11+) have tightened their symbol checkers to better match the CPython guidelines, which causes our wheels to be rejected by their audits. This is, in theory, not a break of abi3 because CPython could never introduce an API-elvel PyInit_* function themselves without causing problems, so there ought to be no problems for our users, even with future Python versions. That said, we still want to pass the audit, because the coding guidelines are useful.

This commit is not the cleanest way of doing things. PyO3 0.22 includes a #[pymodule(submodule)] option on the attribute macro, which lets us use all the standard code generation while suppressing the unnecessary PyInit_* symbol. When we are ready to move to PyO3 0.22, we probably want to revert this commit to switch to that form.

Details and comments

We found this during the deployment of 1.2.0rc1, since that's the most recent PyPI release since abi3audit released version 0.0.11. This commit creates a wheel that passes the audit at its current version 0.0.14.

Footnotes

  1. https://docs.python.org/3/c-api/intro.html

Using the `#[pymodule]` derive macro in PyO3 0.21 always causes a
`PyInit_*` symbol with a matching name to be exported in the output
`cdylib`.  This is required for the top-level module, in order for
Python to import it---it needs to know which symbol in a shared library
file it should call---but submodules must be manually initialised, so do
not need it.  Including it is typically harmless (and something we've
been doing for a long time), but it is technically against the coding
rules for CPython extensions[^1].

Recent versions of `abi3audit` (0.0.11+) have tightened their symbol
checkers to better match the CPython guidelines, which causes our wheels
to be rejected by their audits.  This is, in theory, not a break of abi3
because CPython could never introduce an API-elvel `PyInit_*` function
themselves without causing problems, so there ought to be no problems
for our users, even with future Python versions. That said, we still
want to pass the audit, because the coding guidelines are useful.

This commit is not the cleanest way of doing things.  PyO3 0.22 includes
a `#[pymodule(submodule)]` option on the attribute macro, which lets us
use all the standard code generation while suppressing the unnecessary
`PyInit_*` symbol.  When we are ready to move to PyO3 0.22, we probably
want to revert this commit to switch to that form.

[^1]: https://docs.python.org/3/c-api/intro.html
@jakelishman jakelishman added type: qa Issues and PRs that relate to testing and code quality stable backport potential The bug might be minimal and/or import enough to be port to stable Changelog: None Do not include in changelog labels Aug 2, 2024
@jakelishman jakelishman added this to the 1.2.0 milestone Aug 2, 2024
@qiskit-bot
Copy link
Collaborator

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core
  • @kevinhartman
  • @levbishop
  • @mtreinish

@mtreinish mtreinish modified the milestones: 1.2.0, 1.1.2 Aug 2, 2024
@coveralls
Copy link

Pull Request Test Coverage Report for Build 10214478341

Details

  • 42 of 42 (100.0%) changed or added relevant lines in 4 files are covered.
  • 5 unchanged lines in 1 file lost coverage.
  • Overall coverage decreased (-0.004%) to 89.737%

Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 5 91.98%
Totals Coverage Status
Change from base Build 10213066424: -0.004%
Covered Lines: 67325
Relevant Lines: 75025

💛 - Coveralls

@mtreinish
Copy link
Member

We'll probably need to do this on stable/1.1 too so we can push out 1.1.2, but I think things between main/1.2 and 1.1 have diverged enough it's not worth attempting a backport and we should just do it manually there.

@jakelishman
Copy link
Member Author

Yeah, I can open another PR to do that there. It should be a smaller job.

Copy link
Member

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code LGTM, I haven't personally validated the symbols being exported in the shared library but I trust that you tested this locally and it matches the code change so I'm good with merging this now.

@mtreinish mtreinish added this pull request to the merge queue Aug 2, 2024
@jakelishman
Copy link
Member Author

Fwiw, what I did to test was to pull this commit into a Linux VM (needs to be Linux, since abi3audit only does this strictest check on ELF libraries), run pip wheel . on the library, then use abi3audit on the result Qiskit wheel. I verified that it fails the audit without the commit and passes with it.

Merged via the queue into Qiskit:main with commit 120b73d Aug 2, 2024
15 checks passed
mergify bot pushed a commit that referenced this pull request Aug 2, 2024
Using the `#[pymodule]` derive macro in PyO3 0.21 always causes a
`PyInit_*` symbol with a matching name to be exported in the output
`cdylib`.  This is required for the top-level module, in order for
Python to import it---it needs to know which symbol in a shared library
file it should call---but submodules must be manually initialised, so do
not need it.  Including it is typically harmless (and something we've
been doing for a long time), but it is technically against the coding
rules for CPython extensions[^1].

Recent versions of `abi3audit` (0.0.11+) have tightened their symbol
checkers to better match the CPython guidelines, which causes our wheels
to be rejected by their audits.  This is, in theory, not a break of abi3
because CPython could never introduce an API-elvel `PyInit_*` function
themselves without causing problems, so there ought to be no problems
for our users, even with future Python versions. That said, we still
want to pass the audit, because the coding guidelines are useful.

This commit is not the cleanest way of doing things.  PyO3 0.22 includes
a `#[pymodule(submodule)]` option on the attribute macro, which lets us
use all the standard code generation while suppressing the unnecessary
`PyInit_*` symbol.  When we are ready to move to PyO3 0.22, we probably
want to revert this commit to switch to that form.

[^1]: https://docs.python.org/3/c-api/intro.html

(cherry picked from commit 120b73d)

# Conflicts:
#	crates/accelerate/src/target_transpiler/mod.rs
#	crates/pyext/src/lib.rs
@jakelishman jakelishman deleted the no-unnecessary-pyinit branch August 2, 2024 15:28
jakelishman added a commit that referenced this pull request Aug 2, 2024
Using the `#[pymodule]` derive macro in PyO3 0.21 always causes a
`PyInit_*` symbol with a matching name to be exported in the output
`cdylib`.  This is required for the top-level module, in order for
Python to import it---it needs to know which symbol in a shared library
file it should call---but submodules must be manually initialised, so do
not need it.  Including it is typically harmless (and something we've
been doing for a long time), but it is technically against the coding
rules for CPython extensions[^1].

Recent versions of `abi3audit` (0.0.11+) have tightened their symbol
checkers to better match the CPython guidelines, which causes our wheels
to be rejected by their audits.  This is, in theory, not a break of abi3
because CPython could never introduce an API-elvel `PyInit_*` function
themselves without causing problems, so there ought to be no problems
for our users, even with future Python versions. That said, we still
want to pass the audit, because the coding guidelines are useful.

This commit is not the cleanest way of doing things.  PyO3 0.22 includes
a `#[pymodule(submodule)]` option on the attribute macro, which lets us
use all the standard code generation while suppressing the unnecessary
`PyInit_*` symbol.  When we are ready to move to PyO3 0.22, we probably
want to revert this commit to switch to that form.

[^1]: https://docs.python.org/3/c-api/intro.html

(cherry picked from commit 120b73d)
github-merge-queue bot pushed a commit that referenced this pull request Aug 2, 2024
Using the `#[pymodule]` derive macro in PyO3 0.21 always causes a
`PyInit_*` symbol with a matching name to be exported in the output
`cdylib`.  This is required for the top-level module, in order for
Python to import it---it needs to know which symbol in a shared library
file it should call---but submodules must be manually initialised, so do
not need it.  Including it is typically harmless (and something we've
been doing for a long time), but it is technically against the coding
rules for CPython extensions[^1].

Recent versions of `abi3audit` (0.0.11+) have tightened their symbol
checkers to better match the CPython guidelines, which causes our wheels
to be rejected by their audits.  This is, in theory, not a break of abi3
because CPython could never introduce an API-elvel `PyInit_*` function
themselves without causing problems, so there ought to be no problems
for our users, even with future Python versions. That said, we still
want to pass the audit, because the coding guidelines are useful.

This commit is not the cleanest way of doing things.  PyO3 0.22 includes
a `#[pymodule(submodule)]` option on the attribute macro, which lets us
use all the standard code generation while suppressing the unnecessary
`PyInit_*` symbol.  When we are ready to move to PyO3 0.22, we probably
want to revert this commit to switch to that form.

[^1]: https://docs.python.org/3/c-api/intro.html

(cherry picked from commit 120b73d)

Co-authored-by: Jake Lishman <[email protected]>
eliarbel added a commit to eliarbel/qiskit that referenced this pull request Sep 18, 2024
This is a manual backport of the change introduced in PR Qiskit#12889. It
is done manually since in 0.46 we are using PyO3 version 0.19.2 which
does not yet have the `Bound` concept PR Qiskit#12889 relies on in the
`add_submodule` helper function. In this branch we also need to
handle just a subset of submodule functions compared to the ones
in Qiskit#12899.
github-merge-queue bot pushed a commit that referenced this pull request Sep 20, 2024
This is a manual backport of the change introduced in PR #12889. It
is done manually since in 0.46 we are using PyO3 version 0.19.2 which
does not yet have the `Bound` concept PR #12889 relies on in the
`add_submodule` helper function. In this branch we also need to
handle just a subset of submodule functions compared to the ones
in #12899.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: None Do not include in changelog priority: high stable backport potential The bug might be minimal and/or import enough to be port to stable type: qa Issues and PRs that relate to testing and code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants