Repository navigation
allocUnsafe is useless since 24 #60423
Description
Activity
Seems like
GetZeroFillToggleis never called outside of snapshots?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 thereThis logic does not work:
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
createUnsafeBufferin fact callsgetZeroFillToggleon the first time makesallocUnsafeactually workUpd: b2405e9 (#55337) seems to be the first commit where the issue surfaced
cc @nodejs/buffer and @nodejs/performance perhaps
I'm starting to think that
allocUnsafeshould 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
allocUnsafeis zero-filledAt this point reverting that might be a semver-major
Upd: the observable difference between
allocandallocUnsafecurrently is thatallocis not pooled whileallocUnsafeis pooledcc @nodejs/tsc
Reacted by Nikita SkovorodaWe should fix this. In what node version did it break?
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.
Reacted by Marco Ippolito, Nikita Skovoroda, Gürgün Dayıoğlu and Denis YakovenkoReacted by Nikita SkovorodaWe should fix this. In what node version did it break?
As mentioned in the issue, 24.0.0
More specifically, #55337I 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-fillingConsumers 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 themThere 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
There seems to be no significant usage of
allocUnsafeintroduced 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);
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 2024Upd: Ah, I found https://nodedownloads.nodeland.dev/, nice (thanks to @mcollina for https://github.com/mcollina/nodejs-download-stats)
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:

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-bufferscondition 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- 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
allowUnsafedo 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.Reacted by Gürgün Dayıoğlu, Marco Ippolito, Vinicius Lourenço and Richard LauReacted by Nikita Skovoroda85 remaining items
@santigimeno @RafaelGSS could this be reopened please? It's still useful for tracking, not all issues are resolved
Why does a commit (nodesource/nsolid@13b6879) from nodesource repository close an issue in node.js organization? @nodejs/tsc
Why are you pinging the TSC? We are not maintaining GitHub
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.
Reacted by Nikita SkovorodaIt's still useful for tracking, not all issues are resolved
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.
@panva It is not yet possible at this point, blocked on another thing for the time being
I will return to this a bit laterIt is not yet possible at this point, blocked on another thing for the time being
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.
Will file a new issue about path to hardening buffer instead
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
allocandallocUnsafeon large arrays, andallocUnsafealways appears to be zero-filledIn that case places relying on
allocUnsafeand thenfillwould be ~2x faster (or more) if they just usedallocinstead ofallocUnsafein the first placeE.g.
Buffer.concat([Buffer.alloc(0)], 1e6)is ~10x faster with.allocinstead of.allocUnsafe+.fill, and there appears to be no regression from that change on otherBuffer.concatusageallocUnsafeshould be either fixed to be faster thanallocor should be replaced withalloceverywhere (that will simplify things) and deprecated whatsoever