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

Fix pool pollution, infinite loop #508

Merged
merged 1 commit into from
Nov 25, 2024
Merged

Conversation

myndzi
Copy link
Contributor

@myndzi myndzi commented Nov 25, 2024

When nanoid is called with a fractional value, there were a number of undesirable effects:

  • in browser and non-secure, the code infinite loops on while (size--)
  • in node, the value of poolOffset becomes fractional, causing calls to nanoid to return zeroes until the pool is next filled: when i is initialized to poolOffset, pool[i] & 63 -> undefined & 63 -> 0
  • if the first call in node is a fractional argument, the initial buffer allocation fails with an error

I chose |0 to cast to a signed integer primarily because that has a slightly better outcome in the third case above: if the first call is negative (e.g. nanoid(-1)) then Node will throw an error for an invalid Buffer size, rather than attempting to allocate a buffer of size 2**32-1. It's also more compact than >>>0, which would be necessary to cast to an unsigned integer. I don't think there is a use case for generating ids longer than 2**31-1 :)

When nanoid is called with a fractional value, there were a number
of undesirable effects:
- in browser and non-secure, the code infinite loops on `while (size--)`
- in node, the value of poolOffset becomes fractional, causing calls to
  nanoid to return zeroes until the pool is next filled: when `i` is
  initialized to `poolOffset`, `pool[i] & 63` -> `undefined & 63` -> `0`
- if the first call in node is a fractional argument, the initial buffer
  allocation fails with an error

I chose `|0` to cast to a signed integer primarily because that has a
slightly better outcome in the third case above: if the first call is
negative (e.g. `nanoid(-1)`) then Node will throw an error for an
invalid Buffer size, rather than attempting to allocate a buffer of
size `2**32-1`. It's also more compact than `>>>0`, which would be
necessary to cast to an unsigned integer. I don't _think_ there is
a use case for generating ids longer than `2**31-1` :)
@ai ai merged commit 9da8f60 into ai:main Nov 25, 2024
4 of 5 checks passed
myndzi added a commit to myndzi/nanoid that referenced this pull request Nov 26, 2024
I didn't fully understand the project and test structure, but while
preparing the backport for v3 I gained a fuller understanding.

The tests now exercise the customAlphabet code and the non-secure
variant, and fix the infinite loop case in `customRandom` on both
node and the browser.
myndzi added a commit to myndzi/nanoid that referenced this pull request Nov 26, 2024
I didn't fully understand the project and test structure, but while
preparing the backport for v3 I gained a fuller understanding.

The tests now exercise the customAlphabet code and the non-secure
variant, and fix the infinite loop case in `customRandom` on both
node and the browser.
ai pushed a commit that referenced this pull request Nov 26, 2024
* Additional fixes and tests for #508

I didn't fully understand the project and test structure, but while
preparing the backport for v3 I gained a fuller understanding.

The tests now exercise the customAlphabet code and the non-secure
variant, and fix the infinite loop case in `customRandom` on both
node and the browser.

* `const` -> `let`

* lint
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants