Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34.3k
buffer: auto random fill Buffer(num) and new Buffer(num)#11808
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
Conversation
jasnell commented Mar 12, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
ChALkeR commented Mar 12, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
ChALkeR left a comment • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seishun commented Mar 12, 2017
@jasnell Could you clarify what makes this less disruptive than the other one? |
jasnell commented Mar 12, 2017
@ChALkeR ... thanks for the pointer on that, I had remembered seeing it before but couldn't remember where. I've incorporated the workaround and the test. PTAL @seishun rightfully mentioned in the other alternate PR (which I've closed in favor of this one) that is is a breaking change for performance critical apps that are still using the @seishun ... it's less disruptive in terms of the code changes for the zero-fill (only touches buffer.js, should only give perf impact to |
seishun commented Mar 12, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
Benchmark results so far: (Command line: IMO unless we can make the results significantly better (and on every supported platform), this warrants a full deprecation cycle. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: it won't hurt to test other methods here, e.g. Buffer.alloc(10).filter(() => true), which also would have been affected if not for the fix above.
ChALkeR commented Mar 14, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@jasnell Could I ask you to split this into two separate PRs for a separate review? Opt-in |
jasnell commented Mar 14, 2017
Yes, splitting it into two separate PRs is fine. Just to make sure I'm clear, that's:
Correct? |
ChALkeR commented Mar 14, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@jasnell, No, I meant the other way around:
The opt-in flag for |
Selects a random byte and fills Buffer(num) and new Buffer(num) automatically using the randomly selected value. Why random-fill vs. zero-fill? Prior to this commit, the uninitialized Buffer allocation would be potentially filled with non-zeroed data. By filling with a randomly selected value, we eliminate the possibility of leaking uninitialized data but we preserve the need for users to completely over-write the Buffer contents in order for it to be useful. Zero-filling by default would *potentially* put users at risk if module developers assume that the Buffer instance will always be zero-filled (which will not be the case on older versions of Node.js). The cost, however, is that filling with a randomly selected value is a bit less performant than zero-filling on allocation. Note that Buffer.allocUnsafe() and Buffer.alloc() are *not* affected by this change. Buffer.allocUnsafe() will returns a Buffer with uninitialized data and Buffer.alloc() returns *zero-filled* data.
jasnell commented Mar 21, 2017
The PRs have been split |
jasnell commented Mar 23, 2017
For the record, I will say that I am definitely not yet convinced that random-fill is the right approach to take here. It may be easier and better just to zero-fill from 8.0.0 and on. |
ChALkeR commented Mar 25, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
I'm not convinced about this for reasons that I already mentioned. Currently, I'm -1 on this in its default form (just landing this without any additional actions). I'm +0 on this if this would be paired with a strong commitment to runtime-deprecating without a flag in the next version after the random/zero-fill lands. That is for the case if this won't get backported. I'm also -1 to a partial backport, without landing a runtime deprecation at the same time. I'm +1 to landing zero/randomfill at the time when a runtime deprecation is landed, with or without partial or full backport at the time the version that will contain the deprecation will be released. Given the current situation, I propose to just postpone the zero/randomfill decision to 9.0 (because we probably won't land a runtime deprecation by default in 9.0) and observe the ecosystem usage. To explain: I am afraid that this could make things worse if we come to a situaton when most current releases that people would care about (e.g. |
jasnell commented Mar 25, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
@nodejs/ctc ... Given that we have not been able to reach consensus on this, I'm going to call for an official vote at the next CTC meeting. The vote options are:
Please weigh in here in advance of the CTC meeting if possible. I'd like to have a vote on the next call. |
jasnell commented Mar 25, 2017 • edited
Loading Uh oh!
There was an error while loading. Please reload this page.
edited
Uh oh!
There was an error while loading. Please reload this page.
My first choice is 1. Second choice would be 3. |
mscdex commented Mar 25, 2017
Why no runtime deprecation vote option? |
jasnell commented Mar 25, 2017
Trott commented Mar 25, 2017
@jasnell I'm generally onboard with that approach but in this case @ChALkeR (and maybe others?) on CTC have made it explicit that they can only support zero-filling if there is a commitment to deprecation. Maybe a good approach is to resolve the "are we going to commit to a deprecation timeline or not" issue first, and then based on that outcome, people can make an informed vote on this? |
seishun commented Mar 26, 2017
My humble proposal: start the vote from the question whether a ~50% performance hit to an API should be preceded by a full deprecation cycle. (I think it should be because that way practically everyone is warned about the impending change and has time to migrate, rather than having their application suddenly get slower after upgrading Node.js) |
| constbindingObj={}; | ||
| constinternalUtil=require('internal/util'); | ||
| constzeroFillBuffers=!!config.zeroFillBuffers; | ||
| constrandomFill=zeroFillBuffers ? 0 : Math.floor(Math.random()*256); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not gather crypto.randomBytes() if crypto is available?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we only need a single byte.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and there's no need for it to be cryptographically safe)
| ); | ||
| } | ||
| returnBuffer.allocUnsafe(arg); | ||
| returnBuffer.allocUnsafe(arg).fill(randomFill); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this seems... slow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, it is. I went with this approach here because it requires the least amount of code. It is more performant to do a memset in the Allocator inside node.cc, but doing so is a bit more intrusive and introduces a branch that impacts all Allocations (albeit, an extremely minor one).
I maintain that the best thing to do would be to just use calloc and zero-fill instead.
sam-github commented Mar 29, 2017
I don't have an opinion on whether doing this at all is a good idea, but I've had nightmarish experiences debugging systems where someone had the clever idea of randomizing uninitialized memory "so no one would rely on its value". It made bugs manifest randomly. When something is buggy, it should ideally bug out all the time, every run, same place. Not randomly. Please don't make it random. |
jasnell commented Mar 31, 2017
The @nodejs/ctc has voted against the random fill approach in nodejs/CTC#90, |

@addaleax @nodejs/ctc
This is an alternate approach for #11806 that uses
fill()to fill thenew Buffer(num)/Buffer(num)after allocation. The changes are less disruptive but occur in two steps. The performance profile is a bit better.This also includes the sameThe--pending-deprecationaddition that is in #11806 and the conditionally-emitted deprecationwarning that is off by default.--pending-deprecationstuff has been separated out into a separate PR: #11968Again, this is a work in progress
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
buffer