Skip to content

gh-130030: Fix crash on 32-bit Linux with free threading #130043

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

Merged
merged 2 commits into from
Feb 12, 2025

Conversation

colesbury
Copy link
Contributor

@colesbury colesbury commented Feb 12, 2025

The gc_get_refs assertion needs to be after we check the alive and unreachable bits. Otherwise, ob_tid may store the actual thread id instead of the computed gc_refs, which may trigger the assertion if the ob_tid looks like a negative value.

Also fix a few type warnings on 32-bit systems.

The `gc_get_refs` assertion needs to be after we check the alive and
unreachable bits. Otherwise, `ob_tid` may store the actual thread id
instead of the computed `gc_refs`, which may trigger the assertion if
the `ob_tid` looks like a negative value.

Also fix a few type warnings on 32-bit systems.
Copy link
Member

@nascheme nascheme left a comment

Choose a reason for hiding this comment

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

Other than my preference of leaving "in" and "out" unsigned, this LGTM.

The fix by moving the assert looks correct. With the "mark alive" pass, objects that are marked alive don't have gc_maybe_init_refs() called on them. So ob_tid doesn't contain a refcount.

unsigned int in;
unsigned int out;
Py_ssize_t in;
Py_ssize_t out;
Copy link
Member

Choose a reason for hiding this comment

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

Warnings could also be fixed by changing this line:

Py_ssize_t space = BUFFER_HI - gc_mark_buffer_len(args);

to

unsigned int space = BUFFER_HI - gc_mark_buffer_len(args);

The assert should be changed in that case, since size can't be negative.

assert(space <= gc_mark_buffer_avail(args));
assert(space <= BUFFER_HI);

Performance wise I would doubt that using Py_ssize_t makes any difference. On 32-bit platforms maybe a little since it would use a 64-bit int rather than a 32-bit one?

I would still prefer to use the unsigned integer types since my understanding is that the C standard defines overflow behavior for unsigned integers but not signed ones. The buffer "in" and "out" calculations depend on the overflow behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes sense -- I switched back to unsigned int.

On 32-bit platforms maybe a little since it would use a 64-bit int rather than a 32-bit one?

Py_ssize_t is the same size as size_t, so typically 32-bits on a 32-bit platform.

@colesbury colesbury merged commit e094420 into python:main Feb 12, 2025
45 checks passed
@colesbury colesbury deleted the gh-130030-32bit branch February 12, 2025 23:09
befeleme pushed a commit to fedora-python/cpython that referenced this pull request Mar 17, 2025
…pythongh-130043)

The `gc_get_refs` assertion needs to be after we check the alive and
unreachable bits. Otherwise, `ob_tid` may store the actual thread id
instead of the computed `gc_refs`, which may trigger the assertion if
the `ob_tid` looks like a negative value.

Also fix a few type warnings on 32-bit systems.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants