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

net: handle normalized args in normalizeArgs() #13069

Merged
merged 1 commit into from
May 19, 2017

Conversation

cjihrig
Copy link
Contributor

@cjihrig cjihrig commented May 16, 2017

This commit allows normalizeArgs() to be called with its own previous output. Prior to this change, multiple calls to normalizeArgs() would create a nested structure that produced invalid arguments.

cc: @vdeturckheim @joyeecheung @mcollina @jasnell (from othiym23/async-listener#110)

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines
Affected core subsystem(s)

net

@nodejs-github-bot nodejs-github-bot added the net Issues and PRs related to the net subsystem. label May 16, 2017
lib/net.js Outdated
@@ -125,6 +125,10 @@ function normalizeArgs(args) {
const arg0 = args[0];
var options = {};
if (typeof arg0 === 'object' && arg0 !== null) {
// Handle the case where the arguments were already normalized.
if (Array.isArray(arg0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using instanceof Array should be faster.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, in my experiences Array.isArray is faster because of the difficult-to-optimize nature of the instanceof operator under ES2015+…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a benchmark that shows this on master?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious, wouldn't Array.isArray always be a safer choice? Or because we know how arg0 is created in this specific case we can safely use instanceof Array?

@refack
Copy link
Contributor

refack commented May 17, 2017

Just an idea, put a symbol on it, to distinguish from arbitrary Arrays

lib/net.js Outdated
@@ -125,6 +125,10 @@ function normalizeArgs(args) {
const arg0 = args[0];
var options = {};
if (typeof arg0 === 'object' && arg0 !== null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is doing the same thing as the if (arguments.length === 1 && Array.isArray(arguments[0])) block in Socket.prototype.connect, maybe remove the similar logic there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joyeecheung it is related, but not the same thing.

@vdeturckheim
Copy link
Member

LGTM!

@cjihrig
Copy link
Contributor Author

cjihrig commented May 17, 2017

Just an idea, put a symbol on it, to distinguish from arbitrary Arrays

I'm open to it if others are.

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cjihrig
Copy link
Contributor Author

cjihrig commented May 18, 2017

@watson
Copy link
Member

watson commented May 18, 2017

Out of curiosity, when is normalizeArgs() called recursively?

@cjihrig
Copy link
Contributor Author

cjihrig commented May 18, 2017

@watson for example in othiym23/async-listener#110. normalizeArgs() returns an array of length 2. Node's check in Socket.prototype.connect() explicitly checks for a length of 1. This could be fixed in a few ways (add more logic in async-listener, remove the length of 1 check). I think allowing normalizeArgs() to consume its own output is the most flexible solution.

@cjihrig
Copy link
Contributor Author

cjihrig commented May 18, 2017

Actually, the more I think about it, the more I like the idea of just dropping the arguments.length === 1 check in Socket.prototype.connect().

@watson
Copy link
Member

watson commented May 18, 2017

@cjihrig you mean the code I added? Weird, I thought we tested async-listener against that patch since that was the whole reason for the patch 😅

@watson
Copy link
Member

watson commented May 18, 2017

@cjihrig it was kind of an ugly hack. And allowing normalizeArgs to be called recursively would fix part of that. But we'll then still have to run these 3 lines twice: https://github.com/cjihrig/node-1/blob/27ae95a21958b3c7d91c688da6093e96fc167e5c/lib/net.js#L957-L959

@cjihrig
Copy link
Contributor Author

cjihrig commented May 18, 2017

I do indeed mean that code :-D

We tested it, but @vdeturckheim came to me with this script, which was still failing.

And allowing normalizeArgs to be called recursively would fix part of that. But we'll then still have to run these 3 lines twice

Yea, removing the arguments.length === 1 check should fix the problem. @refack's suggestion of attaching a symbol might be helpful as well, since we don't want to support arbitrary arrays.

@watson
Copy link
Member

watson commented May 18, 2017

Ah, ok got it now thanks for the explanation 😄

Yeah, the symbol trick might be ok

@cjihrig
Copy link
Contributor Author

cjihrig commented May 18, 2017

New commit (3564d322fd891dccc97e80c90f522412bad54da5) has the symbol approach.

@@ -10,5 +10,6 @@ function isLegalPort(port) {
}

module.exports = {
isLegalPort
isLegalPort,
kNormalizedConnectSymbol: Symbol('normalizedConnect')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also used by listen(). Perhaps we should just call it normalizedArgsSymbol with a 'normalizedArgs' symbol value? Keeping it generic may also help if we ever need/want it for other normalization functions, like the ones in child_process or something.

@cjihrig
Copy link
Contributor Author

cjihrig commented May 18, 2017

@mscdex renamed the symbol as you suggested.

@watson
Copy link
Member

watson commented May 18, 2017

LGTM 👍

@cjihrig
Copy link
Contributor Author

cjihrig commented May 19, 2017

New CI: https://ci.nodejs.org/job/node-test-pull-request/8173/

EDIT: Some platforms fail with EADDRNOTAVAIL. Others fail with ECONNREFUSED. Updated the test to handle both. CI: https://ci.nodejs.org/job/node-test-pull-request/8174/

This commit attaches a Symbol to the result of
net._normalizeArgs(). This prevents normal arrays from being
passed to the internal Socket.prototype.connect() bypass logic.

PR-URL: nodejs#13069
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
@cjihrig cjihrig merged commit 51664fc into nodejs:master May 19, 2017
@cjihrig cjihrig deleted the normalize branch May 19, 2017 15:25
@vdeturckheim
Copy link
Member

Awesome! Thank you @cjihrig !!

anchnk pushed a commit to anchnk/node that referenced this pull request May 19, 2017
This commit attaches a Symbol to the result of
net._normalizeArgs(). This prevents normal arrays from being
passed to the internal Socket.prototype.connect() bypass logic.

PR-URL: nodejs#13069
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: Joyee Cheung <[email protected]>
@jasnell jasnell mentioned this pull request May 28, 2017
@gibfahn gibfahn mentioned this pull request Jun 15, 2017
3 tasks
@MylesBorins
Copy link
Contributor

MylesBorins commented Jul 17, 2017

Should this land on v6.x?

If so it will need a manual backport

@mcollina
Copy link
Member

I'm 👎 to backport. This would need a lot of other changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
net Issues and PRs related to the net subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants