Repository navigation
[Fix] nvm use: handle regex-special characters in $NVM_DIR - #3939
Conversation
nvm_change_path interpolated `$NVM_DIR` and the new version dir unescaped into grep and sed expressions, so a path containing `&`, `#`, `[`, `*`, etc. corrupted `$PATH` (or made sed fail) when switching versions. Escape them before use.
hridhinvarkeyjoseph
left a comment
There was a problem hiding this comment.
I checked this out and ran the new test with sh — it passes. Separately, I confirmed that on master 4 of the 6 paths really do break (& garbles PATH, # crashes sed).
One more case worth a test: on master, with NVM_DIR=/tmp/a.b/.nvm, an unrelated PATH entry like /tmp/aXb/.nvm/versions/node/v4.5.0/bin gets replaced, because . matches any character. This PR fixes that, but nothing asserts it, so a future change could regress it silently.
Question: why switch the first two branches from basic to extended regex (grep -Eq, sed -E)? Was that needed for the escaping to work, or to share one escape set? I didn't follow that part.
|
Good catch, added a regression test for that: with On the So with a directory name containing a literal |
|
Thanks — checked out the latest commit and the special-characters test (including the new regression case) passes in sh, bash and zsh. The BRE vs ERE explanation makes sense; I hadn't realized One thing still open from my inline comment: |
This comment was marked as spam.
This comment was marked as spam.
|
Good catch, moved both into the |
ljharb
left a comment
There was a problem hiding this comment.
Thanks! The escaping itself looks right to me: the bracket expression covers every ERE metacharacter (and \ is literal inside it), switching all the greps to -E lets one escaping scheme serve every check, and the replacement escapes exactly \, &, and #. sed -E is already used elsewhere in nvm.sh, so that's not a new portability requirement.
Before this can land, nvm_sanitize_path has the same bug: it does sed -e "s#${NVM_DIR}#\${NVM_DIR}#g", so a # in $NVM_DIR breaks the substitution and regex characters can mis-match. Since it's the same class of problem, it'd be great to fix it here too.
Inline comments below.
|
Thanks for the review. Pushed 4e6d4a3:
Ran the new and related unit tests under sh, bash and dash. |
4e6d4a3 to
19755ea
Compare
19755ea to
906fb60
Compare
Problem
nvm_change_path(used bynvm useforPATHandMANPATH) interpolates${NVM_DIR}and the new version directory straight intogrepandsedexpressions. If$NVM_DIRcontains a regex or sed-special character, the resultingPATHis wrong:&(e.g./tmp/a&b/.nvm): sed expands it to the matched text, producing/opt/x:/tmp/a/tmp/a&b/.nvm/versions/node/v1.0.0/binb/.nvm/versions/node/v2.0.0/bin:/bin#: the sed command fails outright (bad flag in substitute command) andPATHis emptied[,*,\: the "already contains an nvm path" check silently fails, so the old version's directory stays onPATHnext to the new oneCause
Neither
${NVM_DIR}nor${3}is escaped before being used as a pattern / replacement.Fix
Escape
${NVM_DIR}for ERE (and for the#-delimited sed expression) and escape\,&and#in the replacement. Thegrepandsedcalls switch to-Eso a single escaping scheme applies to both.Testing
Added
test/fast/Unit tests/nvm_change_path special characters, which fails before the change and passes after it in sh, bash, dash and zsh. The existingnvm_change_pathandnvm_strip_pathtests still pass. In the fulltest/fastrun under bash, the same tests fail with and without this change (nvm ls-remote,nvm_get_arch_unofficial,nvm_install_no_progress_bar,nvm_print_implicit_alias success,nvm_process_nvmrc,nvm_stdout_is_terminal), so those failures are unrelated.