mirror of
https://github.com/neovim/neovim.git
synced 2026-07-09 10:59:38 +00:00
build: lint "strtol" #40442
Problem: No lint for strtol(). Solution: Add lint, and update existing usages. Callers that previously got a (garbage) large positive value: - `indent.c`: use getdigits() (intmax, no int truncation) with def=1 so overflow/too-large values stay positive and fall through to the existing "too big" check (E475). - `file_search.c`: use getdigits() with def=255 so overflow/too-large values keep the "max expand" (else) branch. The other conversions (api/command.c, eval/window.c, highlight_group.c, tui/tui.c) only diverge on pathological overflow inputs where strtol's result was already garbage and the observable outcome is unchanged.
This commit is contained in:
@@ -1088,6 +1088,20 @@ local function check_language(filename, clean_lines, linenum, error)
|
||||
)
|
||||
end
|
||||
|
||||
-- Check for strtol: it silently overflows/truncates and needs error-prone boilerplate.
|
||||
-- TODO: also flag atoi, atol, atoll, strtoul, strtoll, strtoull.
|
||||
local strtol_regex = vim.regex([[\<strtol\>]])
|
||||
if strtol_regex:match_str(line) then
|
||||
error(
|
||||
filename,
|
||||
linenum,
|
||||
'runtime/deprecated',
|
||||
4,
|
||||
'Use getdigits()/getdigits_int() (or vim_str2nr() for non-decimal bases) instead of strtol, '
|
||||
.. 'which overflows silently. See src/nvim/charset.c.'
|
||||
)
|
||||
end
|
||||
|
||||
-- Check for memset with wrong argument order: memset(buf, sizeof(buf), 0)
|
||||
-- Pattern: memset(arg1, arg2, 0) where arg2 is NOT a valid fill value
|
||||
local memset_start = line:find('memset%s*%([^)]*,%s*[^,]*,%s*0%s*%)')
|
||||
|
||||
@@ -463,8 +463,8 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
|
||||
count_value = first_arg.data.integer;
|
||||
} else if (first_arg.type == kObjectTypeString) {
|
||||
// Try to parse string as a number Example: vim.api.nvim_cmd({cmd = 'copen', args = {'10'}}, {})
|
||||
char *endptr;
|
||||
long val = strtol(first_arg.data.string.data, &endptr, 10);
|
||||
char *endptr = first_arg.data.string.data;
|
||||
long val = getdigits_long(&endptr, false, 0);
|
||||
// Check if entire string was consumed (valid number) and string is not empty
|
||||
if (*endptr == '\0' && first_arg.data.string.size > 0) {
|
||||
is_numeric = true;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/autocmd.h"
|
||||
#include "nvim/buffer.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/cursor.h"
|
||||
#include "nvim/errors.h"
|
||||
#include "nvim/eval/funcs.h"
|
||||
@@ -277,8 +278,8 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar)
|
||||
}
|
||||
} else {
|
||||
// Extract the window count (if specified). e.g. winnr('3j')
|
||||
char *endp;
|
||||
int count = (int)strtol(arg, &endp, 10);
|
||||
char *endp = (char *)arg;
|
||||
int count = getdigits_int(&endp, false, 0);
|
||||
if (count <= 0) {
|
||||
// if count is not specified, default to 1
|
||||
count = 1;
|
||||
|
||||
@@ -407,7 +407,9 @@ void *vim_findfile_init(char *path, char *filename, size_t filenamelen, char *st
|
||||
ff_expand_buffer.data[ff_expand_buffer.size++] = *wc_part++;
|
||||
ff_expand_buffer.data[ff_expand_buffer.size++] = *wc_part++;
|
||||
|
||||
llevel = strtol(wc_part, &errpt, 10);
|
||||
errpt = wc_part;
|
||||
// Use def=255 so that overflow/too-large values keep the "max expand" behavior.
|
||||
llevel = getdigits(&errpt, false, 255);
|
||||
if (errpt != wc_part && llevel > 0 && llevel < 255) {
|
||||
ff_expand_buffer.data[ff_expand_buffer.size++] = (char)llevel;
|
||||
} else if (errpt != wc_part && llevel == 0) {
|
||||
|
||||
@@ -1478,7 +1478,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
|
||||
// Ignored for now
|
||||
} else if (strcmp(key, "BLEND") == 0) {
|
||||
if (strcmp(arg, "NONE") != 0) {
|
||||
hl_table[idx].sg_blend = (int)strtol(arg, NULL, 10);
|
||||
char *arg_end = arg;
|
||||
hl_table[idx].sg_blend = getdigits_int(&arg_end, false, 0);
|
||||
} else {
|
||||
hl_table[idx].sg_blend = -1;
|
||||
}
|
||||
@@ -3182,7 +3183,7 @@ RgbValue name_to_color(const char *name, int *idx)
|
||||
&& isxdigit((uint8_t)name[6]) && name[7] == NUL) {
|
||||
// rgb hex string
|
||||
*idx = kColorIdxHex;
|
||||
return (RgbValue)strtol(name + 1, NULL, 16);
|
||||
return (RgbValue)strtol(name + 1, NULL, 16); // NOLINT(runtime/deprecated)
|
||||
} else if (!STRICMP(name, "bg") || !STRICMP(name, "background")) {
|
||||
*idx = kColorIdxBg;
|
||||
return normal_bg;
|
||||
|
||||
@@ -67,9 +67,11 @@ bool tabstop_set(char *var, colnr_T **array)
|
||||
|
||||
for (char *cp = var; *cp != NUL; cp++) {
|
||||
if (cp == var || cp[-1] == ',') {
|
||||
char *end;
|
||||
char *end = cp;
|
||||
|
||||
if (strtol(cp, &end, 10) <= 0) {
|
||||
// Use def=1 so that overflow/too-large values pass this check and are
|
||||
// instead rejected by the "n > TABSTOP_MAX" check in the loop below.
|
||||
if (getdigits(&end, false, 1) <= 0) {
|
||||
if (cp != end) {
|
||||
emsg(_(e_positive));
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/helpers.h"
|
||||
#include "nvim/ascii_defs.h"
|
||||
#include "nvim/charset.h"
|
||||
#include "nvim/cursor_shape.h"
|
||||
#include "nvim/event/defs.h"
|
||||
#include "nvim/event/loop.h"
|
||||
@@ -525,14 +526,16 @@ static void terminfo_start(TUIData *tui)
|
||||
char *konsolev_env = os_getenv("KONSOLE_VERSION");
|
||||
char *term_program_version_env = os_getenv("TERM_PROGRAM_VERSION");
|
||||
|
||||
int vtev = vte_version_env ? (int)strtol(vte_version_env, NULL, 10) : 0;
|
||||
char *vte_version_end = vte_version_env;
|
||||
int vtev = vte_version_env ? getdigits_int(&vte_version_end, false, 0) : 0;
|
||||
bool iterm_env = termprg && strstr(termprg, "iTerm.app");
|
||||
bool nsterm = (termprg && strstr(termprg, "Apple_Terminal"))
|
||||
|| terminfo_is_term_family(term, "nsterm");
|
||||
bool konsole = terminfo_is_term_family(term, "konsole")
|
||||
|| os_env_exists("KONSOLE_PROFILE_NAME", true)
|
||||
|| os_env_exists("KONSOLE_DBUS_SESSION", true);
|
||||
int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10)
|
||||
char *konsolev_end = konsolev_env;
|
||||
int konsolev = konsolev_env ? getdigits_int(&konsolev_end, false, 0)
|
||||
: (konsole ? 1 : 0);
|
||||
bool wezterm = strequal(termprg, "WezTerm");
|
||||
const char *weztermv = wezterm ? term_program_version_env : NULL;
|
||||
|
||||
@@ -140,6 +140,7 @@ void test_more()
|
||||
// Try getenv and setenv
|
||||
char *env = getenv("HOME"); // Should trigger runtime/os_fn
|
||||
setenv("TEST", "value", 1); // Should trigger runtime/os_fn
|
||||
long n = strtol(env, NULL, 10); // Should trigger runtime/deprecated
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
@@ -43,7 +43,8 @@ describe('clint.lua', function()
|
||||
'test/functional/fixtures/clint_test.c:138: Use xfree(...) instead of free(...). [runtime/memory_fn] [2]',
|
||||
'test/functional/fixtures/clint_test.c:141: Use os_getenv(...) instead of getenv(...). [runtime/os_fn] [2]',
|
||||
'test/functional/fixtures/clint_test.c:142: Use os_setenv(...) instead of setenv(...). [runtime/os_fn] [2]',
|
||||
'Total errors found: 28',
|
||||
'test/functional/fixtures/clint_test.c:143: Use getdigits()/getdigits_int() (or vim_str2nr() for non-decimal bases) instead of strtol, which overflows silently. See src/nvim/charset.c. [runtime/deprecated] [4]',
|
||||
'Total errors found: 29',
|
||||
}
|
||||
t.eq(expected, output_lines)
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user