Skip to content

[BUG] Stack overflow for recursive directory structures #1556

Closed
@Alhadis

Description

@Alhadis

I've a few project folders linked globally to /usr/local/lib/node_modules (hereafter referred to as $NPM). Some of the links point to projects whose node_modules is a symlink back to $NPM. Running npm --global upgrade causes a stack overflow:

(Click to show contents of ~/.npm/_logs/2020-07-23T01_44_06_392Z-debug.log)
0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   '/usr/local/Cellar/node/14.5.0/bin/node',
1 verbose cli   '/usr/local/bin/npm',
1 verbose cli   '--global',
1 verbose cli   'upgrade',
1 verbose cli   'c8',
1 verbose cli   'cson',
1 verbose cli   'electron',
1 verbose cli   'jsdoc',
1 verbose cli   'jsvu',
1 verbose cli   'npm',
1 verbose cli   'rollup',
1 verbose cli   'typescript'
1 verbose cli ]
2 info using npm@6.14.5
3 info using node@v14.5.0
4 verbose npm-session 693c3b480696055c
5 verbose update computing outdated modules to update
6 verbose stack RangeError: Maximum call stack size exceeded
6 verbose stack     at validate (/usr/local/lib/node_modules/npm/node_modules/aproba/index.js:25:19)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:37:3)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack     at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
7 verbose cwd /Users/john/Labs/Mono
8 verbose Darwin 17.7.0
9 verbose argv "/usr/local/Cellar/node/14.5.0/bin/node" "/usr/local/bin/npm" "--global" "upgrade" "c8" "cson" "electron" "jsdoc" "jsvu" "npm" "rollup" "typescript"
10 verbose node v14.5.0
11 verbose npm  v6.14.5
12 error Maximum call stack size exceeded
13 verbose exit [ 1, true ]

Environment

My directory structures are laid out like this:

λ tree $NPM ~/Labs/JG/node_modules
/usr/local/lib/node_modules
├── @alhadis -> /Users/john/Labs/JG/node_modules/@alhadis
├── jg -> /Users/john/Labs/JG
└── vtt -> /Users/john/Labs/VTT

/Users/john/Labs/JG/node_modules
├── @alhadis
│   └── eslint-config -> ../../eslint
├── alhadis.utils -> ../../Utils
├── babel-eslint -> /usr/local/lib/node_modules/babel-eslint
├── eslint-plugin-import -> /usr/local/lib/node_modules/eslint-plugin-import
└── get-options -> ../../GetOptions

My ~/.npmrc file is temporarily moved to /tmp each time I run npm globally (see #1346 for reasons why).

When / where

When running npm -g upgrade or npm -g outdated. Other subcommands are probably affected, but I only use symlinks to simplify management of globally-installed modules/projects.

Note that these symlinks were not produced by npm link, but rather ln -s. In all honesty, I'm not sure I get the point of npm link

Expected behaviour

NPM should keep track of directories it's already scanned, including those stipulated by the working directory and NPM's --global switch.

Actual behaviour

The flatNameFromTree function doesn't track resolved paths it traverses during recursion, inevitably resulting in a stack overflow:

RangeError: Maximum call stack size exceeded
	at validate (/usr/local/lib/node_modules/npm/node_modules/aproba/index.js:25:19)
	at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:37:3)
	at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
	at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
	at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
	…

The problem disappears if I move symlinked entries out of $NPM to /tmp before running npm.

Steps to reproduce

Hopefully self-explanatory, but if the exact structure is needed, well… this should more-or-less establish the basic layout.

cd && rm -rf /tmp/dummy-project-directory && mkdir $_ && cd $_
git clone --depth=1 https://github.com/Alhadis/Utils.git alhadis.utils
git clone --depth=1 https://github.com/Alhadis/JG.git jg
git clone --depth=1 https://github.com/Alhadis/VTT.git vtt
(cd alhadis.utils && ln -s "$OLDPWD/jg/node_modules" .)
mkdir jg/node_modules && cd $_
mkdir \@alhadis && ln -s ../../eslint "$_/eslint-config" && ln -s ../../alhadis.utils .
cd "`npm root -g`" && mv -i "$OLDPWD"/{jg,vtt} . && ln -s "$OLDPWD/jg/node_modules/@alhadis" \@alhadis
npm --global outdated

Sidenotes you probably don't care about:

  • I haven't actually tested the code above, since it's intended to be illustrative rather than informative.
  • Some of these projects are unfinished, hence the use of git clone instead of npm install.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bugthing that needs fixingRelease 6.xwork is associated with a specific npm 6 release

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions