From b1b3a0038c0666c7436cb5d383608b4b72c8300b Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Fri, 9 Oct 2026 21:16:17 -0700 Subject: [PATCH] [Fix] `nvm_cd`: bypass a user-defined `cd` function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `\cd` only bypasses aliases, so a user-defined `cd` function (eg, cdhist's) still ran, and broke `NVM_DIR` auto-detection when it rejected zsh's `-q`. Use `command cd`, which skips functions in POSIX shells. zsh's `command` runs `/usr/bin/cd` instead of the builtin, so use `builtin cd` there, as `nvm_echo` does for `printf`. `nvm_die_on_prefix` also now uses `nvm_cd` instead of a bare `cd`. Fixes #3835. See #3836. Co-authored-by: Elan Ruusamäe --- nvm.sh | 10 ++++++++-- test/fast/Unit tests/nvm_cd | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100755 test/fast/Unit tests/nvm_cd diff --git a/nvm.sh b/nvm.sh index ce84b0ea..6b1d6eaf 100755 --- a/nvm.sh +++ b/nvm.sh @@ -41,7 +41,13 @@ nvm_echo_with_colors() { } nvm_cd() { - \cd "$@" + # `\cd` still runs a user-defined `cd` function; in zsh, `command cd` runs `/usr/bin/cd` instead of the builtin + if [ -n "${ZSH_VERSION-}" ]; then + # shellcheck disable=SC3044 + builtin cd "$@" + else + command cd "$@" + fi } # a caller that closed stderr, rather than redirecting it to /dev/null, makes @@ -3516,7 +3522,7 @@ nvm_die_on_prefix() { local NVM_CONFIG_VALUE eval "NVM_CONFIG_VALUE=\"\$${NVM_NPM_CONFIG_x_PREFIX_ENV}\"" if [ -n "${NVM_CONFIG_VALUE-}" ] && [ "_${NVM_OS}" = "_win" ]; then - NVM_CONFIG_VALUE="$(cd "$NVM_CONFIG_VALUE" 2>/dev/null && pwd)" + NVM_CONFIG_VALUE="$(nvm_cd "$NVM_CONFIG_VALUE" 2>/dev/null && pwd)" fi if [ -n "${NVM_CONFIG_VALUE-}" ] && ! nvm_tree_contains_path "${NVM_DIR}" "${NVM_CONFIG_VALUE}"; then nvm deactivate >/dev/null 2>&1 diff --git a/test/fast/Unit tests/nvm_cd b/test/fast/Unit tests/nvm_cd new file mode 100755 index 00000000..aa7f457d --- /dev/null +++ b/test/fast/Unit tests/nvm_cd @@ -0,0 +1,23 @@ +#!/bin/sh + +die () { echo "$@" ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +EXPECTED="$(\cd .. && pwd)" + +# a user-defined `cd` function that rejects nvm's arguments, like cdhist's (#3835) +cd() { + echo 'user-defined cd function was called' >&2 + return 1 +} + +OUTPUT="$(nvm_cd .. 2>&1 && pwd)" +[ "${OUTPUT}" = "${EXPECTED}" ] || die "expected '${EXPECTED}', got '${OUTPUT}'" + +# shellcheck disable=SC2086 +OUTPUT="$(nvm_cd ${NVM_CD_FLAGS} .. 2>&1 && pwd)" +[ "${OUTPUT}" = "${EXPECTED}" ] || die "with NVM_CD_FLAGS '${NVM_CD_FLAGS}', expected '${EXPECTED}', got '${OUTPUT}'" + +unset -f cd