aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml88
-rw-r--r--src/nvim/api/private/helpers.c5
-rw-r--r--src/nvim/ex_docmd.c33
-rw-r--r--test/functional/api/command_spec.lua22
4 files changed, 73 insertions, 75 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b650c5dd85..c84c9f0bbd 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -74,6 +74,11 @@ jobs:
- cc: clang
runner: macos-11.0
os: osx
+ - flavor: functionaltest-lua
+ cc: gcc
+ runner: ubuntu-20.04
+ os: linux
+ cmake: minimum_required
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
if: github.event.pull_request.draft == false
@@ -92,6 +97,24 @@ jobs:
sudo apt-get update
sudo apt-get install -y autoconf automake build-essential ccache cmake cpanminus cscope gcc-multilib gdb gettext gperf language-pack-tr libtool-bin locales ninja-build pkg-config python3 python3-pip python3-setuptools unzip valgrind xclip
+ - name: Install minimum required version of cmake
+ if: matrix.cmake == 'minimum_required'
+ env:
+ CMAKE_URL: 'https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.sh'
+ CMAKE_VERSION: '3.10.0'
+ shell: bash
+ run: |
+ curl --retry 5 --silent --show-error --fail -o /tmp/cmake-installer.sh "$CMAKE_URL"
+ mkdir -p "$HOME/.local/bin" /opt/cmake-custom
+ chmod a+x /tmp/cmake-installer.sh
+ /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license
+ ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake"
+ cmake_version="$(cmake --version | head -1)"
+ echo "$cmake_version" | grep -qF "cmake version $CMAKE_VERSION" || {
+ echo "Unexpected CMake version: $cmake_version"
+ exit 1
+ }
+
- name: Install new clang
if: matrix.flavor == 'asan' || matrix.flavor == 'tsan'
run: |
@@ -152,68 +175,3 @@ jobs:
run: powershell ci\build.ps1
env:
CONFIGURATION: ${{ matrix.config }}
-
- functionaltest:
- name: ${{ matrix.runner }} ${{ matrix.flavor }} (cc=${{ matrix.cc }})
- strategy:
- fail-fast: false
- matrix:
- include:
- - flavor: functionaltest-lua
- cc: gcc
- runner: ubuntu-20.04
- os: linux
- runs-on: ${{ matrix.runner }}
- timeout-minutes: 45
- env:
- CC: ${{ matrix.cc }}
- CI_OS_NAME: ${{ matrix.os }}
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup common environment variables
- run: ./.github/workflows/env.sh ${{ matrix.flavor }}
-
- - name: Install apt packages
- run: |
- sudo apt-get update
- sudo apt-get install -y autoconf automake build-essential ccache cmake cpanminus cscope gcc-multilib gdb gettext gperf language-pack-tr libtool-bin locales ninja-build pkg-config python3 python3-pip python3-setuptools unzip valgrind xclip
-
- - name: Install minimum required version of cmake
- env:
- CMAKE_URL: 'https://cmake.org/files/v3.10/cmake-3.10.0-Linux-x86_64.sh'
- CMAKE_VERSION: '3.10.0'
- shell: bash
- run: |
- curl --retry 5 --silent --show-error --fail -o /tmp/cmake-installer.sh "$CMAKE_URL"
- mkdir -p "$HOME/.local/bin" /opt/cmake-custom
- chmod a+x /tmp/cmake-installer.sh
- /tmp/cmake-installer.sh --prefix=/opt/cmake-custom --skip-license
- ln -sfn /opt/cmake-custom/bin/cmake "$HOME/.local/bin/cmake"
- cmake_version="$(cmake --version | head -1)"
- echo "$cmake_version" | grep -qF "cmake version $CMAKE_VERSION" || {
- echo "Unexpected CMake version: $cmake_version"
- exit 1
- }
-
- - name: Setup interpreter packages
- run: |
- ./ci/install.sh
-
- - name: Cache dependencies
- uses: actions/cache@v2
- with:
- path: |
- ${{ env.CACHE_NVIM_DEPS_DIR }}
- ~/.ccache
- key: ${{ matrix.runner }}-${{ matrix.flavor }}-${{ matrix.cc }}-${{ hashFiles('cmake/*', 'third-party/**', '**/CMakeLists.txt') }}-${{ github.base_ref }}
-
- - name: Build third-party
- run: ./ci/before_script.sh
-
- - name: Build and test
- run: ./ci/script.sh
-
- - name: Cache dependencies
- if: ${{ success() }}
- run: ./ci/before_cache.sh
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index ddcfff0097..2b107a3f27 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1384,6 +1384,11 @@ void add_user_command(String name, Object command, Dict(user_command) *opts, int
LuaRef luaref = LUA_NOREF;
LuaRef compl_luaref = LUA_NOREF;
+ if (!uc_validate_name(name.data)) {
+ api_set_error(err, kErrorTypeValidation, "Invalid command name");
+ goto err;
+ }
+
if (mb_islower(name.data[0])) {
api_set_error(err, kErrorTypeValidation, "'name' must begin with an uppercase letter");
goto err;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 4dba0b97ed..87f8865133 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -5164,6 +5164,24 @@ char_u *get_command_name(expand_T *xp, int idx)
return cmdnames[idx].cmd_name;
}
+/// Check for a valid user command name
+///
+/// If the given {name} is valid, then a pointer to the end of the valid name is returned.
+/// Otherwise, returns NULL.
+char *uc_validate_name(char *name)
+{
+ if (ASCII_ISALPHA(*name)) {
+ while (ASCII_ISALNUM(*name)) {
+ name++;
+ }
+ }
+ if (!ends_excmd(*name) && !ascii_iswhite(*name)) {
+ return NULL;
+ }
+
+ return name;
+}
+
int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def, int flags,
int compl, char_u *compl_arg, LuaRef compl_luaref, cmd_addr_T addr_type,
LuaRef luaref, bool force)
@@ -5679,23 +5697,18 @@ static void ex_command(exarg_T *eap)
// Get the name (if any) and skip to the following argument.
name = p;
- if (ASCII_ISALPHA(*p)) {
- while (ASCII_ISALNUM(*p)) {
- p++;
- }
- }
- if (!ends_excmd(*p) && !ascii_iswhite(*p)) {
+ end = (char_u *)uc_validate_name((char *)name);
+ if (!end) {
emsg(_("E182: Invalid command name"));
return;
}
- end = p;
- name_len = (int)(end - name);
+ name_len = (size_t)(end - name);
// If there is nothing after the name, and no attributes were specified,
// we are listing commands
p = skipwhite(end);
if (!has_attr && ends_excmd(*p)) {
- uc_list(name, end - name);
+ uc_list(name, name_len);
} else if (!ASCII_ISUPPER(*name)) {
emsg(_("E183: User defined commands must start with an uppercase letter"));
} else if (name_len <= 4 && STRNCMP(name, "Next", name_len) == 0) {
@@ -5703,7 +5716,7 @@ static void ex_command(exarg_T *eap)
} else if (compl > 0 && (argt & EX_EXTRA) == 0) {
emsg(_(e_complete_used_without_nargs));
} else {
- uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, LUA_NOREF,
+ uc_add_command(name, name_len, p, argt, def, flags, compl, compl_arg, LUA_NOREF,
addr_type_arg, LUA_NOREF, eap->forceit);
}
}
diff --git a/test/functional/api/command_spec.lua b/test/functional/api/command_spec.lua
index d64d324a88..de22c9078c 100644
--- a/test/functional/api/command_spec.lua
+++ b/test/functional/api/command_spec.lua
@@ -180,6 +180,28 @@ describe('nvim_add_user_command', function()
feed('<C-U>Test b<Tab>')
eq('Test bbb', funcs.getcmdline())
end)
+
+ it('does not allow invalid command names', function()
+ matches("'name' must begin with an uppercase letter", pcall_err(exec_lua, [[
+ vim.api.nvim_add_user_command('test', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_add_user_command('t@', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_add_user_command('T@st', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_add_user_command('Test!', 'echo "hi"', {})
+ ]]))
+
+ matches('Invalid command name', pcall_err(exec_lua, [[
+ vim.api.nvim_add_user_command('💩', 'echo "hi"', {})
+ ]]))
+ end)
end)
describe('nvim_del_user_command', function()