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

only set a new random seed if _the last_ Generator gets destruct'ed #871

Open
wants to merge 2 commits into
base: 2.0
Choose a base branch
from

Conversation

themasch
Copy link

What is the reason for this PR?

In cases where multiple Generator instances might be created, a gc cycle collection run can trigger at any time, potentially removing "old" Generator instances, which then calls __destruct and thus seed, which reset the global mt_rand seed, impacting everyone else.

If another, still live instance of Generator gets used after that, its output is no longer deterministic, since a new random seed was set.

Author's checklist

Summary of changes

I added a new static class property to Faker\Generator which counts the number of currently existing Generator instances: It gets incremented in __construct, and decremented in __destruct. Only if this counter reaches 0 does __destruct also call seed to restore the system to a "properly random" state.

Using a global counter is, imho, quite ugly, but since Generator::seed already modifies global state anyway I think its like fighting fire with fire.
Other than that, I think its a quite minimal change that does not impact any other use of Faker. Cases that "properly" only ever use exactly one instance of the Generator will not see any difference in behaviour.

It's not a perfect solution by any means. But I think it is a reasonable one.

Review checklist

  • All checks have passed
  • Changes are added to the CHANGELOG.md
  • Changes are approved by maintainer

In cases where multiple Generator instances might be created, a gc cycle collection run can trigger at any time, potentially removing "old" Generator instances, which then calls __destruct and thus seed, which reset the *global* mt_rand seed, impacting everyone else.

If another, still live instance of Generator gets used after that, its output is no longer deterministic, since a new random seed was set.
Comment on lines 564 to 566
* In order top prevent resetting the seed while another Generator instance is still alive, we keep track of the
* total, global number of Generator being "active". Incremented in __construct, decremented in __destruct.
* This is necessary, because __destruct modified global state (`mt_srand`).
Copy link

Choose a reason for hiding this comment

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

A couple of typos here:

Suggested change
* In order top prevent resetting the seed while another Generator instance is still alive, we keep track of the
* total, global number of Generator being "active". Incremented in __construct, decremented in __destruct.
* This is necessary, because __destruct modified global state (`mt_srand`).
* In order to prevent resetting the seed while another Generator instance is still alive, we keep track of the
* total, global number of Generators being "active". Incremented in __construct, decremented in __destruct.
* This is necessary, because __destruct modifies global state (`mt_srand`).

Copy link
Author

Choose a reason for hiding this comment

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

Thanks a lot. Fixed them.

Copy link

stale bot commented Apr 22, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 1 week if no further activity occurs. Thank you for your contributions.

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.

Generator::seed in Generator::__destruct may break determinism
2 participants