Skip to content

BUG: preserve BitGenerator state after failed reinitialization - #32787

Open
Johnny-Kao wants to merge 1 commit into
numpy:mainfrom
Johnny-Kao:bug/gh-28784-bitgenerator-reinit
Open

Johnny-Kao wants to merge 1 commit into
numpy:mainfrom
Johnny-Kao:bug/gh-28784-bitgenerator-reinit

Conversation

@Johnny-Kao

@Johnny-Kao Johnny-Kao commented Sep 25, 2026 •

Copy link
Copy Markdown

PR summary

Closes #28784

This PR fixes a segmentation fault that can occur when an existing NumPy random BitGenerator is reinitialized with invalid input and the reinitialization fails.

Previously, BitGenerator.__init__() could reset parts of the existing instance before the new seed had been fully validated. As a result, a failed reinitialization could raise the expected Python exception while still leaving the existing BitGenerator with an invalid internal state. A subsequent call to random_raw() could then dereference that invalid state and crash the interpreter.

This PR changes initialization so that seed validation is completed before the existing BitGenerator state is mutated. If reinitialization fails, the exception is raised while the previously valid generator state is preserved.

Philox requires additional handling because its counter and key arguments are validated separately from the base seed. Their conversion and validation are therefore also performed before calling BitGenerator.__init__(), preventing an invalid counter or key from partially reinitializing an existing Philox instance.

Regression tests verify that failed reinitialization preserves the previous random stream for:

  • MT19937
  • PCG64
  • PCG64DXSM
  • SFC64
  • Philox

Additional tests cover failed Philox reinitialization with invalid counter and key values.

Before the fix:

>>> import numpy.random
>>> p = numpy.random.PCG64DXSM()
>>> try:
...     p.__init__(("",))
... except ValueError:
...     pass
...
>>> p.random_raw()
Segmentation fault (core dumped)

After the fix:

>>> import numpy.random
>>> p = numpy.random.PCG64DXSM(123)
>>> try:
...     p.__init__(("",))
... except ValueError:
...     pass
...
>>> p.random_raw()
# Returns normally using the previously valid generator state.

Standard successful initialization behavior is unchanged. The additional validation occurs during initialization/reinitialization and does not add checks to the random-number generation hot path.

First time contributor introduction

This is my first contribution to NumPy. I have previously contributed to SciPy and Python-Blosc2, and I am interested in continuing to contribute to the Scientific Python ecosystem.

AI Disclosure

Tool used: Anthropic's Claude Code
I used AI-assisted tooling to investigate and draft this fix; I've reviewed, tested, and can explain every change above.

Validate seed inputs before mutating BitGenerator state so a failed
reinitialization cannot leave a valid generator with a NULL state pointer.
Validate Philox counter/key inputs before calling the base initializer for the
same reason.

Closes numpygh-28784.
@Johnny-Kao

Copy link
Copy Markdown
Author

The only failing check is Build wheel cp313-win_amd64-. It failed in _core/tests/test_limited_api.py because a Cython subprocess exited with Windows RPC_NT_INTERNAL_ERROR (0xC0020043), with no test assertion or compiler diagnostic.

This PR does not modify the limited-API test or wheel CI configuration, and all other checks pass. Could a maintainer please rerun this failed job?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: segfault from random_raw from instance initialized from invalid value

1 participant