https://bugs.winehq.org/show_bug.cgi?id=45749
Bug ID: 45749 Summary: Visual Studio 2017 Installer fails due to node.js/libuv listen(named pipe) error Product: Wine Version: 3.14 Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: -unknown Assignee: wine-bugs@winehq.org Reporter: jimbo1qaz@gmail.com Distribution: ---
Created attachment 62190 --> https://bugs.winehq.org/attachment.cgi?id=62190 Visual Studio Installer logs (mostly useless)
Running Kubuntu 18.04 64-bit. I created a 32-bit .wine32 prefix, installed dotnet46 via winetricks, then the Build Tools for Visual Studio installer (https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-... ) (which shares the core with VS2017 installer. It's written in node.js and involves multiple processes communicating via what the source describes as "pipe"s).
The error is "Hub Controller process exited prematurely with exit code 1 (NodeUncaughtFatalException)."
Interestingly, the installer's source is user-readable and located in WINEPREFIX / drive_c/Program Files/Microsoft Visual Studio/Installer/resources/app/node_modules/microsoft-servicehub/host/. I was able to edit the .js files to add control flow logging:
const fs = require('fs'); function logg(val, args){ fs.writeFileSync("C:\"+process.hrtime()[1] + '_'+val, ""+args, function(err) {}); }
Installer seems to be codenamed "microsoft-servicehub". Strangely, many of the Installer files appear to test for Windows and/or *nix, despite VS being Windows-only. It also references open-source VS Code, but I was unable to find any hits when Googling for quoted strings.
----------
The error message "Hub Controller process exited prematurely with exit code" is raised from within "drive_c/Program Files/Microsoft Visual Studio/Installer/resources/app/node_modules/microsoft-servicehub/controllerConnection.js":
ControllerConnection.prototype.startController `var connectPromise` fails, calling `function (err)` to spawn a process (which crashes).
ControllerConnection.prototype.onControllerProcessExited is responsible for noticing the process has terminated, and raising the exception.
---------
The actual crash originates from "drive_c/Program Files/Microsoft Visual Studio/Installer/resources/app/node_modules/microsoft-servicehub/host/HubController.js".
HubController.js is executed by several distinct processes, and `process.pid` is the same within `function HubController()` and the global scope.
I systematically replaced all calls to `logger.error()` (info, etc.) to `logg()` (since Logger.error() called within subprocess did not show up in Visual Studio's debug logs). I get two sequentially numbered files, 1 millisecond apart:
"429988399_Successfully started server on pipe 5d74f51d8cc5d690c261c26d3e9e3408e060bd352875558b9320be9c213e0610" "430873100_Terminating controller due to some unknown error: " with contents "listen EINVAL \?\pipe\5d74f51d8cc5d690c261c26d3e9e3408e060bd352875558b9320be9c213e0610"
This error is thrown by `function retryStartServer`. `e.code` is EINVAL, while the code only handles `e.code === ec.EADDRINUSE.code`.
Looking at https://stackoverflow.com/questions/11040460/get-the-listen-einval-when-star... suggests:
EINVAL The socket is already connected.
Make sure something isn't already listening on that port.
`man errno` suggests otherwise: > EINVAL Invalid argument (POSIX.1-2001).
Adding `|| e.code === ec.EINVAL.code` and commenting `process.platform === 'win32' ||` sends the installer into an endless "kill and restart HubController" loop, which isn't what we want.
Extra notes on control flow at https://gist.github.com/jimbo1qaz/1c972422fd5c31706920b9be5c2a0f42#server
--------
The `EINVAL` error comes with a node.js stack trace: https://gist.github.com/jimbo1qaz/1c972422fd5c31706920b9be5c2a0f42#file-netw...
(The hexadecimal path originates from https://gist.github.com/jimbo1qaz/1c972422fd5c31706920b9be5c2a0f42#determini... )
https://github.com/nodejs/node/blob/68dff4a67b7222770f90fc5d9bdd884f8db4a24b... `const ex = new Error(`${syscall} ${code}${details}`);` "listen EINVAL \?\pipe\5d74f51d8cc5d690c261c26d3e9e3408e060bd352875558b9320be9c213e0610"
I think the call which failed is `listen`, which returns EINVAL for some reason.
------------
Comparing my stack trace with node.js source code (node.dll 8.9.3):
`Server.listen (net.js:1487:5)` = https://github.com/nodejs/node/blob/v8.9.3/lib/net.js#L1487 - listenInCluster(server=this, address=pipeName, port=-1, addressType=-1, backlog=backlog, fd=undefined, exclusive=options.exclusive); `listenInCluster (net.js:1392:12)` = https://github.com/nodejs/node/blob/v8.9.3/lib/net.js#L1392 - server._listen2(=address, =port, =addressType, =backlog, =fd);
Unpeeling layers of abstraction on top of Windows named pipes:
`Server.setupListenHandle [as _listen2] (net.js:1351:14)` = https://github.com/nodejs/node/blob/v8.9.3/lib/net.js#L1351
(Bullet points are not in stack trace, but I assume they executed) - `handle = new Pipe(PipeConstants.SERVER);` https://github.com/nodejs/node/blob/v8.9.3/lib/net.js#L1267 - `const { Pipe } = process.binding('pipe_wrap');` which refers to C++ code at https://github.com/nodejs/node/blob/v8.9.3/src/pipe_wrap.cc - pipes are handled by https://github.com/libuv/libuv
- `var err = this._handle.listen(backlog || 511);` is the operation which fails = https://github.com/nodejs/node/blob/8a44289089a08b7b19fa3c4651b5f1f5d1edd71b... - Routes to https://github.com/nodejs/node/blob/v8.9.3/src/pipe_wrap.cc#L154 - which calls uv_listen(). `return uv_translate_sys_error(err);` and EINVAL is located at https://github.com/libuv/libuv/blob/v1.x/src/win/error.c#L101 ... There are 7 Win32 errors all mapping to UV_EINVAL==EINVAL, but only WSAEINVAL can happen. - uv_listen() either [assert(0) and sets err=ERROR_INVALID_PARAMETER] (I hope not), calls uv_tcp_listen (I hope not) - Most likely calls uv_pipe_listen() = https://github.com/libuv/libuv/blob/1391a3d9d0996fcf1a116a9c6c58e8b1c7303193... - It has 4 return paths, only `if (!(handle->flags & UV_HANDLE_BOUND)) { return WSAEINVAL;` is happening = https://github.com/libuv/libuv/blob/1391a3d9d0996fcf1a116a9c6c58e8b1c7303193... - What initializes `handle->flags` without |=UV_HANDLE_BOUND?
ok i'm getting a headache