Skip to content

allocUnsafe is useless since 24 #60423

Description

@ChALkeR

See #60399 (comment)

What happed to allocUnsafe - does that work at all in 24+?

Since 24.0.0, there is no observable perf difference between alloc and allocUnsafe on large arrays, and allocUnsafe always appears to be zero-filled

In that case places relying on allocUnsafe and then fill would be ~2x faster (or more) if they just used alloc instead of allocUnsafe in the first place

E.g. Buffer.concat([Buffer.alloc(0)], 1e6) is ~10x faster with .alloc instead of .allocUnsafe + .fill, and there appears to be no regression from that change on other Buffer.concat usage

allocUnsafe should be either fixed to be faster than alloc or should be replaced with alloc everywhere (that will simplify things) and deprecated whatsoever

Activity

  1. ChALkeR commented on Oct 26, 2025

    @ChALkeR
    MemberAuthor

    Seems like GetZeroFillToggle is never called outside of snapshots?

  2. ChALkeR commented on Oct 26, 2025

    @ChALkeR
    MemberAuthor

    Note: since 24 is entering LTS tomorrow per schedule, I don't think the current behavior (i.e. zero-filling allocUnsafe) should be ever changed there

  3. ChALkeR commented on Oct 26, 2025

    @ChALkeR
    MemberAuthor

    This logic does not work:

    node/lib/internal/buffer.js

    Lines 1097 to 1102 in 3c8c1ef

    if (isBuildingSnapshot()) {
    // Reset the toggle so that after serialization, we'll re-create a real
    // toggle connected to the C++ one via getZeroFillToggle().
    addAfterUserSerializeCallback(() => {
    zeroFill = undefined;
    });

    Manually ensuring that createUnsafeBuffer in fact calls getZeroFillToggle on the first time makes allocUnsafe actually work

    Upd: b2405e9 (#55337) seems to be the first commit where the issue surfaced

  4. ChALkeR commented on Oct 26, 2025

    @ChALkeR
    MemberAuthor

    cc @nodejs/buffer and @nodejs/performance perhaps

  5. ChALkeR commented on Oct 27, 2025

    @ChALkeR
    MemberAuthor

    I'm starting to think that allocUnsafe should be just kept as zero-fill (officially, as de-facto it already is), given that no one apparently even noticed it was zero-filling for half a year (i.e. there seem to be no reports)

    Is restoring/maintaining it even worth the whole complexity and security concerns?

    There are already two full major version branches of Node.js (24.x and 25.x) where on each version allocUnsafe is zero-filled

    At this point reverting that might be a semver-major

    Upd: the observable difference between alloc and allocUnsafe currently is that alloc is not pooled while allocUnsafe is pooled

  6. anonrig commented on Oct 27, 2025

    @anonrig
    Member

    cc @nodejs/tsc

  7. ronag commented on Oct 27, 2025

    @ronag
    Member

    We should fix this. In what node version did it break?

  8. ronag commented on Oct 27, 2025

    @ronag
    Member
  9. mcollina commented on Oct 27, 2025

    @mcollina
    SponsorMember

    I think we should fix whatever happened to allocUnsafe.

    No one noticed because no one upgraded yet any production load. We got regression 18->20 when 18 went out of LTS.

  10. ChALkeR commented on Oct 27, 2025

    @ChALkeR
    MemberAuthor

    We should fix this. In what node version did it break?

    As mentioned in the issue, 24.0.0
    More specifically, #55337

  11. ChALkeR commented on Oct 27, 2025

    @ChALkeR
    MemberAuthor

    I think we should fix whatever happened to allocUnsafe.

    That should happen at least before it's labeled as LTS then
    It might have significant security and stability implications as code might already start depending on it zero-filling

    Consumers don't read the docs if code appears to work (e.g.: the memcpy/memmove fallout, memcmp vuln in MySQL/MariaDB)

    There are people who started using Node.js on 24.x and never dealt with previous branches with unsafe memory behavior
    Removing zero-filling would be a breaking change for them

    There are libs and apps which were developed and tested entirely on 24.x with zero-filling

    It might be the lesser evil though if perf impact is significant and reintroducing unsafe memory lands before LTS

  12. ChALkeR commented on Oct 27, 2025

    @ChALkeR
    MemberAuthor

    There seems to be no significant usage of allocUnsafe introduced internally since that change, so at least all internal usage should be already tested without zero-filling enabled:

    % grep -rl allocUnsafe lib | xargs -n1 git blame | grep allocUnsafe | grep 2025
    5335c101a96b (James M Snell 2025-06-29 19:36:38 -0700  50) const kEmptyBuffer = Buffer.allocUnsafe(0);
  13. ChALkeR commented on Oct 27, 2025

    @ChALkeR
    MemberAuthor

    No one noticed because no one upgraded yet any production load.

    Are there download metrics available for 2025?
    https://nodejs.org/metrics/ (and the top link from it) seems to be last updated in 2024

    Upd: Ah, I found https://nodedownloads.nodeland.dev/, nice (thanks to @mcollina for https://github.com/mcollina/nodejs-download-stats)

    Image

    Yes, it looks 24 is currently the least used and patching before LTS is the least evil here

    This is what 22 looked like immediately after becoming LTS in 2024-10 though:
    Image

  14. ChALkeR commented on Oct 27, 2025

    @ChALkeR
    MemberAuthor

    i.e.:

    • Reverting zero-filling by default after LTS is released and users update is a security/stability disaster
    • Leaving it as-is in 24 could be a performance disaster (atm judging from simple benchmarks, I haven't checked realistic usecases)
    • Reverting it before LTS seems acceptable from the numbers, but it should be at least mentioned as a significant change

    Another, non-breaking option is to introduce a flag which reverts this behavior.
    I.e. --no-zero-fill-buffers (as we already have --zero-fill-buffers)

    That could be done at any point, but likely is a bad choice to keep, as dependencies might not be aware and not tested under the --no-zero-fill-buffers condition which is controlled by the top-level app only


    Another option is reverting it for internal Node.js usage only, which should have no visible side-effects and should likely (needs to be tested) fix most of performance impact while being non-breaking (@mcollina - wdyt?)


    ... another option is to reintroduce it under a different name or adding a second arg to it like allocUnsafe(20, false) which has to be specified to opt out of zero-filling

  15. aduh95 commented on Oct 27, 2025

    @aduh95
    Contributor
    • Reverting zero-filling by default after LTS is released and users update is a security/stability disaster

    I would be surprised if it was, my bet would be that folks using allowUnsafe do not care what values they get, they either overwrite the content later and/or accept the security tradeoff for speed. If someone is using a method with "unsafe" in its name, I feel like they are not going to complain about the function being back to unsafe.

  16. 85 remaining items

  17. ChALkeR commented on Dec 22, 2025

    @ChALkeR
    MemberAuthor

    @santigimeno @RafaelGSS could this be reopened please? It's still useful for tracking, not all issues are resolved

  18. reopened this on Dec 22, 2025
  19. anonrig commented on Dec 22, 2025

    @anonrig
    Member

    Why does a commit (nodesource/nsolid@13b6879) from nodesource repository close an issue in node.js organization? @nodejs/tsc

  20. aduh95 commented on Dec 22, 2025

    @aduh95
    Contributor

    Why are you pinging the TSC? We are not maintaining GitHub

  21. ljharb commented on Dec 22, 2025

    @ljharb
    SponsorMember

    A commit (with a magic "closes x" phrase) in any repo on github by someone who can close an issue anywhere on github has always closed it.

  22. panva commented on Dec 23, 2025

    @panva
    Member

    It's still useful for tracking, not all issues are resolved

    @ChALkeR

    I can say with confidence that this issue is not useful for tracking anything anymore. If you wish to have it remain open please post a summary or (actually that'd be better) add a tracking list of outstanding issues and todos to the first post and update the title to be more descriptive.

    Thank you.

  23. ChALkeR commented on Dec 23, 2025

    @ChALkeR
    MemberAuthor

    @panva It is not yet possible at this point, blocked on another thing for the time being
    I will return to this a bit later

  24. ChALkeR commented on Jan 13, 2026

    @ChALkeR
    MemberAuthor

    It is not yet possible at this point, blocked on another thing for the time being

    Unblocked, see https://nodejs.org/en/blog/vulnerability/december-2025-security-releases#timeout-based-race-conditions-make-uint8arraybufferalloc-non-zerofilled-cve-2025-55131---high


    Citing myself from https://github.com/nodejs-private/node-private/pull/798#discussion_r2668111138:

    My long-term expectation is that we could just completely deprecate/remove the Unsafe mechanism, but after investigation of perf and minimizing the negative effects there

    When that is done, it has to be clearly messaged as all the considerations from #4682 / #4660 rechecked

    On a separate note, buffer pooling is another security-riskish behavior that perhaps could be moved to native (which would mitigate all the downsides), but so far my quick attempts failed because it looks like the backing ArrayBuffer creation is slow itself, not the alloc


    Also #61362 / #61372 is related


    I think this really needs closer investigation if we can
    (1) move allocation pooling to native
    and
    (2) make everything just zero-filled by improving zero-filling perf.

    And deprecate both pooling and *Unsafe.

    An argument for that being possible is that for large enough buffers, they are already zero-filled by the system (as @joyeecheung noted in #60423 (comment))

    Which kinda makes the perf point moot in a sense that it's just unoptimal behavior of zero-filling, not zero-filling being inherently slow.

    Likely. Definitely needs investigation.

  25. ChALkeR commented on Apr 19, 2026

    @ChALkeR
    MemberAuthor

    Will file a new issue about path to hardening buffer instead

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions