Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # 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
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants