From: Keith Thompson Date: Thu, 4 Jan 2024 20:19:04 +0000 (+0100) Subject: patch 9.1.0006: is*() and to*() function may be unsafe X-Git-Tag: v9.1.0006^0 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=184f71cc6868a240dc872ed2852542bbc1d43e28;p=thirdparty%2Fvim.git patch 9.1.0006: is*() and to*() function may be unsafe Problem: is*() and to*() function may be unsafe Solution: Add SAFE_* macros and start using those instead (Keith Thompson) Use SAFE_() macros for is*() and to*() functions The standard is*() and to*() functions declared in have undefined behavior for negative arguments other than EOF. If plain char is signed, passing an unchecked value from argv for from user input to one of these functions has undefined behavior. Solution: Add SAFE_*() macros that cast the argument to unsigned char. Most implementations behave sanely for negative arguments, and most character values in practice are non-negative, but it's still best to avoid undefined behavior. The change from #13347 has been omitted, as this has already been separately fixed in commit ac709e2fc0db6d31abb7da96f743c40956b60c3a (v9.0.2054) fixes: #13332 closes: #13347 Signed-off-by: Keith Thompson Signed-off-by: Christian Brabandt --- diff --git a/runtime/tools/ccfilter.c b/runtime/tools/ccfilter.c index 43489f16c2..ae1443e203 100644 --- a/runtime/tools/ccfilter.c +++ b/runtime/tools/ccfilter.c @@ -249,7 +249,7 @@ int main( int argc, char *argv[] ) stay = (echogets(Line2, echo) != NULL); while ( stay && (Line2[0] == '|') ) - { for (p=&Line2[2]; (*p) && (isspace(*p)); p++); + { for (p=&Line2[2]; (*p) && (isspace((unsigned char)*p)); p++); strcat( Reason, ": " ); strcat( Reason, p ); Line2[0] = 0; @@ -265,7 +265,7 @@ int main( int argc, char *argv[] ) ok = 0; if ( !strncmp(Line, "cfe: ", 5) ) { p = &Line[5]; - Severity = tolower(*p); + Severity = tolower((unsigned char)*p); p = strchr( &Line[5], ':' ); if (p == NULL) { ok = 0; @@ -313,7 +313,7 @@ int main( int argc, char *argv[] ) } else { - for (p=Reason; (*p) && (isspace(*p)); p++); + for (p=Reason; (*p) && (isspace((unsigned char)*p)); p++); if ( BasePath[CWDlen] == 0 ) printf( "%s:%lu:%lu:%c:%s\n", FileName, Row, Col, Severity, p ); else diff --git a/runtime/tools/xcmdsrv_client.c b/runtime/tools/xcmdsrv_client.c index e1aea10667..81ca66ceb9 100644 --- a/runtime/tools/xcmdsrv_client.c +++ b/runtime/tools/xcmdsrv_client.c @@ -336,7 +336,7 @@ LookupName( for (p = regProp; (p - regProp) < numItems; ) { entry = p; - while ((*p != 0) && (!isspace(*p))) + while ((*p != 0) && (!isspace((unsigned char)*p))) p++; if ((*p != 0) && (strcasecmp(name, p + 1) == 0)) { @@ -353,7 +353,7 @@ LookupName( for (p = regProp; (p - regProp) < numItems; ) { entry = p; - while ((*p != 0) && (!isspace(*p))) + while ((*p != 0) && (!isspace((unsigned char)*p))) p++; if ((*p != 0) && IsSerialName(p + 1) && (strncmp(name, p + 1, strlen(name)) == 0)) @@ -574,5 +574,5 @@ IsSerialName(char *str) { int len = strlen(str); - return (len > 1 && isdigit(str[len - 1])); + return (len > 1 && isdigit((unsigned char)str[len - 1])); } diff --git a/src/buffer.c b/src/buffer.c index 9ee74f54dd..64e4926475 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4022,7 +4022,7 @@ maketitle(void) buf + off, SPACE_FOR_DIR - off, TRUE); #ifdef BACKSLASH_IN_FILENAME // avoid "c:/name" to be reduced to "c" - if (isalpha(buf[off]) && buf[off + 1] == ':') + if (SAFE_isalpha(buf[off]) && buf[off + 1] == ':') off += 2; #endif // remove the file name @@ -5671,7 +5671,7 @@ chk_modeline( && (s[0] != 'V' || STRNCMP(skipwhite(e + 1), "set", 3) == 0) && (s[3] == ':' - || (VIM_VERSION_100 >= vers && isdigit(s[3])) + || (VIM_VERSION_100 >= vers && SAFE_isdigit(s[3])) || (VIM_VERSION_100 < vers && s[3] == '<') || (VIM_VERSION_100 > vers && s[3] == '>') || (VIM_VERSION_100 == vers && s[3] == '='))) diff --git a/src/charset.c b/src/charset.c index bda3f911b6..0e4dbbe1dc 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1958,7 +1958,7 @@ vim_islower(int c) if (enc_latin1like) return (latin1flags[c] & LATIN1LOWER) == LATIN1LOWER; } - return islower(c); + return SAFE_islower(c); } int @@ -1982,7 +1982,7 @@ vim_isupper(int c) if (enc_latin1like) return (latin1flags[c] & LATIN1UPPER) == LATIN1UPPER; } - return isupper(c); + return SAFE_isupper(c); } int diff --git a/src/cmdhist.c b/src/cmdhist.c index 96a9b3e95b..6342f02bdd 100644 --- a/src/cmdhist.c +++ b/src/cmdhist.c @@ -674,7 +674,7 @@ remove_key_from_history(void) return; for ( ; *p; ++p) - if (STRNCMP(p, "key", 3) == 0 && !isalpha(p[3])) + if (STRNCMP(p, "key", 3) == 0 && !SAFE_isalpha(p[3])) { p = vim_strchr(p + 3, '='); if (p == NULL) diff --git a/src/diff.c b/src/diff.c index 158870402b..9b8c816b5b 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1712,7 +1712,7 @@ diff_read( // --- file1 2018-03-20 13:23:35.783153140 +0100 // +++ file2 2018-03-20 13:23:41.183156066 +0100 // @@ -1,3 +1,5 @@ - if (isdigit(*line)) + if (SAFE_isdigit(*line)) diffstyle = DIFF_ED; else if ((STRNCMP(line, "@@ ", 3) == 0)) diffstyle = DIFF_UNIFIED; @@ -1730,7 +1730,7 @@ diff_read( if (diffstyle == DIFF_ED) { - if (!isdigit(*line)) + if (!SAFE_isdigit(*line)) continue; // not the start of a diff block if (parse_diff_ed(line, hunk) == FAIL) continue; diff --git a/src/dosinst.c b/src/dosinst.c index 4eae5aadc4..35625a7946 100644 --- a/src/dosinst.c +++ b/src/dosinst.c @@ -2760,7 +2760,7 @@ main(int argc, char **argv) rewind(stdin); if (scanf("%99s", buf) == 1) { - if (isdigit(buf[0])) + if (isdigit((unsigned char)buf[0])) { // Change a choice. i = atoi(buf); diff --git a/src/edit.c b/src/edit.c index 9435fd6fc7..f89d43eec6 100644 --- a/src/edit.c +++ b/src/edit.c @@ -5318,7 +5318,7 @@ ins_ctrl_ey(int tc) // was typed after a CTRL-V, and pretend 'textwidth' // wasn't set. Digits, 'o' and 'x' are special after a // CTRL-V, don't use it for these. - if (c < 256 && !isalnum(c)) + if (c < 256 && !SAFE_isalnum(c)) AppendToRedobuff((char_u *)CTRL_V_STR); // CTRL-V tw_save = curbuf->b_p_tw; curbuf->b_p_tw = -1; diff --git a/src/eval.c b/src/eval.c index 8563aa6d79..815d13d42a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4276,7 +4276,7 @@ eval9( return FAIL; end_leader = *arg; - if (**arg == '.' && (!isdigit(*(*arg + 1)) || in_old_script(2))) + if (**arg == '.' && (!SAFE_isdigit(*(*arg + 1)) || in_old_script(2))) { semsg(_(e_invalid_expression_str), *arg); ++*arg; diff --git a/src/evalfunc.c b/src/evalfunc.c index f87c08ffc5..513ddccdbe 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6744,7 +6744,7 @@ f_has(typval_T *argvars, typval_T *rettv) && has_patch(atoi(end + 3)))))); } } - else if (isdigit(name[5])) + else if (SAFE_isdigit(name[5])) n = has_patch(atoi((char *)name + 5)); } else if (STRICMP(name, "vim_starting") == 0) diff --git a/src/evalvars.c b/src/evalvars.c index ea039cbed1..8e42c5a307 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -3332,7 +3332,7 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload) dictitem_T * find_var_also_in_script(char_u *name, hashtab_T **htp, int no_autoload) { - if (STRNCMP(name, "", 5) == 0 && isdigit(name[5])) + if (STRNCMP(name, "", 5) == 0 && SAFE_isdigit(name[5])) { char_u *p = name + 5; int sid = getdigits(&p); @@ -4975,7 +4975,7 @@ get_callback(typval_T *arg) else { if (arg->v_type == VAR_STRING && arg->vval.v_string != NULL - && isdigit(*arg->vval.v_string)) + && SAFE_isdigit(*arg->vval.v_string)) r = FAIL; else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) { diff --git a/src/ex_cmds.c b/src/ex_cmds.c index d214933626..d8e891c2ba 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -3707,7 +3707,7 @@ skip_substitute(char_u *start, int delimiter) static int check_regexp_delim(int c) { - if (isalpha(c)) + if (SAFE_isalpha(c)) { emsg(_(e_regular_expressions_cant_be_delimited_by_letters)); return FAIL; diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 534cd7e038..c18a9107ec 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7996,7 +7996,7 @@ ex_winsize(exarg_T *eap) char_u *arg = eap->arg; char_u *p; - if (!isdigit(*arg)) + if (!SAFE_isdigit(*arg)) { semsg(_(e_invalid_argument_str), arg); return; @@ -8387,7 +8387,7 @@ ex_later(exarg_T *eap) if (*p == NUL) count = 1; - else if (isdigit(*p)) + else if (SAFE_isdigit(*p)) { count = getdigits(&p); switch (*p) @@ -8490,7 +8490,7 @@ ex_redir(exarg_T *eap) arg++; // Make register empty when not using @A-@Z and the // command is valid. - if (*arg == NUL && !isupper(redir_reg)) + if (*arg == NUL && !SAFE_isupper(redir_reg)) write_reg_contents(redir_reg, (char_u *)"", -1, FALSE); } } diff --git a/src/filepath.c b/src/filepath.c index 1ea0623867..cbf2da4136 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -2953,7 +2953,7 @@ get_past_head(char_u *path) #if defined(MSWIN) // may skip "c:" - if (isalpha(path[0]) && path[1] == ':') + if (SAFE_isalpha(path[0]) && path[1] == ':') retval = path + 2; else retval = path; diff --git a/src/findfile.c b/src/findfile.c index 246a81898a..2636609250 100644 --- a/src/findfile.c +++ b/src/findfile.c @@ -1847,7 +1847,7 @@ grab_file_name(long count, linenr_T *file_lnum) if (get_visual_text(NULL, &ptr, &len) == FAIL) return NULL; // Only recognize ":123" here - if (file_lnum != NULL && ptr[len] == ':' && isdigit(ptr[len + 1])) + if (file_lnum != NULL && ptr[len] == ':' && SAFE_isdigit(ptr[len + 1])) { char_u *p = ptr + len + 1; @@ -1981,10 +1981,10 @@ file_name_in_line( p = skipwhite(p); if (*p != NUL) { - if (!isdigit(*p)) + if (!SAFE_isdigit(*p)) ++p; // skip the separator p = skipwhite(p); - if (isdigit(*p)) + if (SAFE_isdigit(*p)) *file_lnum = (int)getdigits(&p); } } diff --git a/src/getchar.c b/src/getchar.c index da05033709..3427a9f8da 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -870,7 +870,7 @@ start_redo(long count, int old_redo) { c = read_redo(FALSE, old_redo); add_char_buff(&readbuf2, c); - if (!isdigit(c)) + if (!SAFE_isdigit(c)) break; } c = read_redo(FALSE, old_redo); @@ -1873,7 +1873,7 @@ vgetc(void) // Handle {sid}; Do up to 20 digits for safety. last_used_sid = 0; - for (j = 0; j < 20 && isdigit(c = vgetorpeek(TRUE)); ++j) + for (j = 0; j < 20 && SAFE_isdigit(c = vgetorpeek(TRUE)); ++j) last_used_sid = last_used_sid * 10 + (c - '0'); last_used_map = NULL; continue; diff --git a/src/gui.c b/src/gui.c index 9c9aa3cbec..16c1b54c67 100644 --- a/src/gui.c +++ b/src/gui.c @@ -5030,7 +5030,7 @@ display_errors(void) // avoid putting up a message box with blanks only for (p = (char_u *)error_ga.ga_data; *p != NUL; ++p) - if (!isspace(*p)) + if (!SAFE_isspace(*p)) { // Truncate a very long message, it will go off-screen. if (STRLEN(p) > 2000) diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index c8b05e1be2..d083226547 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -4031,17 +4031,6 @@ gui_mch_mousehide(int hide) // TODO } - static int -hex_digit(int c) -{ - if (isdigit(c)) - return c - '0'; - c = TOLOWER_ASC(c); - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return -1000; -} - /* * This function has been lifted from gui_w32.c and extended a bit. * diff --git a/src/gui_photon.c b/src/gui_photon.c index b987e9b8a8..9bce94ddfa 100644 --- a/src/gui_photon.c +++ b/src/gui_photon.c @@ -977,7 +977,7 @@ gui_ph_is_buffer_item(vimmenu_T *menu, vimmenu_T *parent) if (mark != NULL) { mark++; - while (isdigit(*mark)) + while (SAFE_isdigit(*mark)) mark++; if (*mark == ')') @@ -2545,7 +2545,7 @@ gui_mch_add_menu(vimmenu_T *menu, int index) if (menu->mnemonic != 0) { - PtAddHotkeyHandler(gui.vimWindow, tolower(menu->mnemonic), + PtAddHotkeyHandler(gui.vimWindow, SAFE_tolower(menu->mnemonic), Pk_KM_Alt, 0, menu, gui_ph_handle_pulldown_menu); } } @@ -2829,7 +2829,7 @@ gui_ph_parse_font_name( { while (*mark != NUL && *mark++ == ':') { - switch (tolower(*mark++)) + switch (SAFE_tolower(*mark++)) { case 'a': *font_flags |= PF_STYLE_ANTIALIAS; break; case 'b': *font_flags |= PF_STYLE_BOLD; break; diff --git a/src/gui_xim.c b/src/gui_xim.c index 88de7a4e98..c9b1c6cb4d 100644 --- a/src/gui_xim.c +++ b/src/gui_xim.c @@ -1471,7 +1471,7 @@ xim_real_init(Window x11_window, Display *x11_display) break; if ((ns = end = strchr(s, ',')) == NULL) end = s + strlen(s); - while (isspace(((char_u *)end)[-1])) + while (SAFE_isspace(end[-1])) end--; *end = NUL; @@ -1533,7 +1533,7 @@ xim_real_init(Window x11_window, Display *x11_display) strcpy(tmp, gui.rsrc_preedit_type_name); for (s = tmp; s && !found; ) { - while (*s && isspace((unsigned char)*s)) + while (*s && SAFE_isspace(*s)) s++; if (!*s) break; @@ -1541,7 +1541,7 @@ xim_real_init(Window x11_window, Display *x11_display) ns++; else end = s + strlen(s); - while (isspace((unsigned char)*end)) + while (SAFE_isspace(*end)) end--; *end = '\0'; diff --git a/src/hardcopy.c b/src/hardcopy.c index e91a7dc2d7..8abfff2107 100644 --- a/src/hardcopy.c +++ b/src/hardcopy.c @@ -1745,7 +1745,7 @@ prt_resfile_skip_nonws(int offset) idx = prt_resfile.line_start + offset; while (idx < prt_resfile.line_end) { - if (isspace(prt_resfile.buffer[idx])) + if (SAFE_isspace(prt_resfile.buffer[idx])) return idx - prt_resfile.line_start; idx++; } @@ -1760,7 +1760,7 @@ prt_resfile_skip_ws(int offset) idx = prt_resfile.line_start + offset; while (idx < prt_resfile.line_end) { - if (!isspace(prt_resfile.buffer[idx])) + if (!SAFE_isspace(prt_resfile.buffer[idx])) return idx - prt_resfile.line_start; idx++; } diff --git a/src/highlight.c b/src/highlight.c index 31c3280e85..318564c74b 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -2307,7 +2307,7 @@ gui_adjust_rgb(guicolor_T c) static int hex_digit(int c) { - if (isdigit(c)) + if (SAFE_isdigit(c)) return c - '0'; c = TOLOWER_ASC(c); if (c >= 'a' && c <= 'f') diff --git a/src/if_py_both.h b/src/if_py_both.h index f8438639e6..42db5101d8 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -3240,7 +3240,7 @@ FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv, if (self == NULL) return NULL; - if (isdigit(*name)) + if (isdigit((unsigned char)*name)) { if (!translated_function_exists(name, FALSE)) { diff --git a/src/if_xcmdsrv.c b/src/if_xcmdsrv.c index d9408398d9..716665a7be 100644 --- a/src/if_xcmdsrv.c +++ b/src/if_xcmdsrv.c @@ -657,7 +657,7 @@ serverGetVimNames(Display *dpy) for (p = regProp; (long_u)(p - regProp) < numItems; p++) { entry = p; - while (*p != 0 && !isspace(*p)) + while (*p != 0 && !SAFE_isspace(*p)) p++; if (*p != 0) { @@ -928,7 +928,7 @@ LookupName( for (p = regProp; (long_u)(p - regProp) < numItems; ) { entry = p; - while (*p != 0 && !isspace(*p)) + while (*p != 0 && !SAFE_isspace(*p)) p++; if (*p != 0 && STRICMP(name, p + 1) == 0) { @@ -945,7 +945,7 @@ LookupName( for (p = regProp; (long_u)(p - regProp) < numItems; ) { entry = p; - while (*p != 0 && !isspace(*p)) + while (*p != 0 && !SAFE_isspace(*p)) p++; if (*p != 0 && IsSerialName(p + 1) && STRNICMP(name, p + 1, STRLEN(name)) == 0) diff --git a/src/macros.h b/src/macros.h index cc2d11fdd1..190778eca3 100644 --- a/src/macros.h +++ b/src/macros.h @@ -50,6 +50,28 @@ */ #define BUFEMPTY() (curbuf->b_ml.ml_line_count == 1 && *ml_get((linenr_T)1) == NUL) +// The is*() and to*() functions declared in have +// undefined behavior for values other than EOF outside the range of +// unsigned char. If plain char is signed, a call with a negative +// value has undefined behavior. These macros cast the argument to +// unsigned char. (Most implementations behave more or less sanely +// with negative values, and most character values in practice are +// positive, but we want to avoid undefined behavior anyway.) +#define SAFE_isalnum(c) (isalnum ((unsigned char)(c))) +#define SAFE_isalpha(c) (isalpha ((unsigned char)(c))) +#define SAFE_isblank(c) (isblank ((unsigned char)(c))) +#define SAFE_iscntrl(c) (iscntrl ((unsigned char)(c))) +#define SAFE_isdigit(c) (isdigit ((unsigned char)(c))) +#define SAFE_isgraph(c) (isgraph ((unsigned char)(c))) +#define SAFE_islower(c) (islower ((unsigned char)(c))) +#define SAFE_isprint(c) (isprint ((unsigned char)(c))) +#define SAFE_ispunct(c) (ispunct ((unsigned char)(c))) +#define SAFE_isspace(c) (isspace ((unsigned char)(c))) +#define SAFE_isupper(c) (isupper ((unsigned char)(c))) +#define SAFE_isxdigit(c) (isxdigit((unsigned char)(c))) +#define SAFE_tolower(c) (tolower ((unsigned char)(c))) +#define SAFE_toupper(c) (toupper ((unsigned char)(c))) + /* * toupper() and tolower() that use the current locale. * On some systems toupper()/tolower() only work on lower/uppercase @@ -64,11 +86,11 @@ # define TOLOWER_LOC(c) tolower_tab[(c) & 255] #else # ifdef BROKEN_TOUPPER -# define TOUPPER_LOC(c) (islower(c) ? toupper(c) : (c)) -# define TOLOWER_LOC(c) (isupper(c) ? tolower(c) : (c)) +# define TOUPPER_LOC(c) (SAFE_islower(c) ? SAFE_toupper(c) : (c)) +# define TOLOWER_LOC(c) (SAFE_isupper(c) ? SAFE_tolower(c) : (c)) # else -# define TOUPPER_LOC toupper -# define TOLOWER_LOC tolower +# define TOUPPER_LOC SAFE_toupper +# define TOLOWER_LOC SAFE_tolower # endif #endif diff --git a/src/mbyte.c b/src/mbyte.c index 34592bd56c..ee2834cf42 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4628,7 +4628,7 @@ enc_canonize(char_u *enc) } // "iso-8859n" -> "iso-8859-n" - if (STRNCMP(p, "iso-8859", 8) == 0 && isdigit(p[8])) + if (STRNCMP(p, "iso-8859", 8) == 0 && SAFE_isdigit(p[8])) { STRMOVE(p + 9, p + 8); p[8] = '-'; @@ -4705,7 +4705,7 @@ enc_locale_env(char *locale) if ((p = (char *)vim_strchr((char_u *)s, '.')) != NULL) { if (p > s + 2 && STRNICMP(p + 1, "EUC", 3) == 0 - && !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_') + && !SAFE_isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_') { // copy "XY.EUC" to "euc-XY" to buf[10] STRCPY(buf + 10, "euc-"); @@ -4721,7 +4721,7 @@ enc_locale_env(char *locale) { if (s[i] == '_' || s[i] == '-') buf[i] = '-'; - else if (isalnum((int)s[i])) + else if (SAFE_isalnum(s[i])) buf[i] = TOLOWER_ASC(s[i]); else break; diff --git a/src/normal.c b/src/normal.c index 61a19c13a4..fd89b00fd4 100644 --- a/src/normal.c +++ b/src/normal.c @@ -4470,11 +4470,11 @@ nv_brackets(cmdarg_T *cap) return; find_pattern_in_path(ptr, 0, len, TRUE, - cap->count0 == 0 ? !isupper(cap->nchar) : FALSE, + cap->count0 == 0 ? !SAFE_isupper(cap->nchar) : FALSE, ((cap->nchar & 0xf) == ('d' & 0xf)) ? FIND_DEFINE : FIND_ANY, cap->count1, - isupper(cap->nchar) ? ACTION_SHOW_ALL : - islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO, + SAFE_isupper(cap->nchar) ? ACTION_SHOW_ALL : + SAFE_islower(cap->nchar) ? ACTION_SHOW : ACTION_GOTO, cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : (linenr_T)1, (linenr_T)MAXLNUM); vim_free(ptr); @@ -5217,7 +5217,7 @@ v_visop(cmdarg_T *cap) // Uppercase means linewise, except in block mode, then "D" deletes till // the end of the line, and "C" replaces till EOL - if (isupper(cap->cmdchar)) + if (SAFE_isupper(cap->cmdchar)) { if (VIsual_mode != Ctrl_V) { diff --git a/src/ops.c b/src/ops.c index 46101a4359..f6d765bd71 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2734,7 +2734,7 @@ do_addsub( { if (CharOrd(firstdigit) < Prenum1) { - if (isupper(firstdigit)) + if (SAFE_isupper(firstdigit)) firstdigit = 'A'; else firstdigit = 'a'; @@ -2746,7 +2746,7 @@ do_addsub( { if (26 - CharOrd(firstdigit) - 1 < Prenum1) { - if (isupper(firstdigit)) + if (SAFE_isupper(firstdigit)) firstdigit = 'Z'; else firstdigit = 'z'; @@ -2875,9 +2875,9 @@ do_addsub( save_pos = curwin->w_cursor; for (i = 0; i < todel; ++i) { - if (c < 0x100 && isalpha(c)) + if (c < 0x100 && SAFE_isalpha(c)) { - if (isupper(c)) + if (SAFE_isupper(c)) hexupper = TRUE; else hexupper = FALSE; diff --git a/src/option.c b/src/option.c index 4d12834f2e..7cac89e5cf 100644 --- a/src/option.c +++ b/src/option.c @@ -7697,7 +7697,7 @@ ExpandSettings( { for (opt_idx = 0; (str = get_termcode(opt_idx)) != NULL; opt_idx++) { - if (!isprint(str[0]) || !isprint(str[1])) + if (!SAFE_isprint(str[0]) || !SAFE_isprint(str[1])) continue; name_buf[0] = 't'; diff --git a/src/os_mswin.c b/src/os_mswin.c index 46f73752f9..21b7db31f3 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -675,7 +675,7 @@ display_errors(void) { // avoid putting up a message box with blanks only for (p = (char_u *)error_ga.ga_data; *p; ++p) - if (!isspace(*p)) + if (!SAFE_isspace(*p)) { // Only use a dialog when not using --gui-dialog-file: // write text to a file. @@ -759,7 +759,7 @@ mch_chdir(char *path) smsg("chdir(%s)", path); verbose_leave(); } - if (isalpha(path[0]) && path[1] == ':') // has a drive name + if (SAFE_isalpha(path[0]) && path[1] == ':') // has a drive name { // If we can change to the drive, skip that part of the path. If we // can't then the current directory may be invalid, try using chdir() @@ -1751,7 +1751,7 @@ is_reparse_point_included(LPCWSTR fname) WCHAR buf[MAX_PATH]; DWORD attr; - if (isalpha(p[0]) && p[1] == L':' && is_path_sep(p[2])) + if (SAFE_isalpha(p[0]) && p[1] == L':' && is_path_sep(p[2])) p += 3; else if (is_path_sep(p[0]) && is_path_sep(p[1])) p += 2; diff --git a/src/os_unix.c b/src/os_unix.c index 11448c5c62..af8f00604c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -6171,7 +6171,7 @@ mch_signal_job(job_T *job, char_u *how) else if (STRCMP(how, "winch") == 0) sig = SIGWINCH; #endif - else if (isdigit(*how)) + else if (SAFE_isdigit(*how)) sig = atoi((char *)how); else return FAIL; diff --git a/src/os_win32.c b/src/os_win32.c index e5cfac7294..dbfc4eeca7 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -7443,7 +7443,7 @@ notsgr: { int l = 2; - if (isdigit(s[l])) + if (SAFE_isdigit(s[l])) l++; if (s[l] == ' ' && s[l + 1] == 'q') { diff --git a/src/spellfile.c b/src/spellfile.c index d3351ef23a..24df042b76 100644 --- a/src/spellfile.c +++ b/src/spellfile.c @@ -2890,7 +2890,7 @@ spell_read_aff(spellinfo_T *spin, char_u *fname) || is_aff_rule(items, itemcnt, "REPSAL", 2)) { // Ignore REP/REPSAL count - if (!isdigit(*items[1])) + if (!SAFE_isdigit(*items[1])) smsg(_("Expected REP(SAL) count in %s line %d"), fname, lnum); } @@ -2925,7 +2925,7 @@ spell_read_aff(spellinfo_T *spin, char_u *fname) { // First line contains the count. found_map = TRUE; - if (!isdigit(*items[1])) + if (!SAFE_isdigit(*items[1])) smsg(_("Expected MAP count in %s line %d"), fname, lnum); } diff --git a/src/tag.c b/src/tag.c index 8003156f0f..893415f699 100644 --- a/src/tag.c +++ b/src/tag.c @@ -1194,7 +1194,7 @@ add_llist_tags( // Get the line number or the search pattern used to locate // the tag. lnum = 0; - if (isdigit(*tagp.command)) + if (SAFE_isdigit(*tagp.command)) // Line number is used to locate the tag lnum = atol((char *)tagp.command); else diff --git a/src/term.c b/src/term.c index 0fdb33e6d7..dd59fdf65d 100644 --- a/src/term.c +++ b/src/term.c @@ -3434,7 +3434,7 @@ ttest(int pairs) #endif { env_colors = mch_getenv((char_u *)"COLORS"); - if (env_colors != NULL && isdigit(*env_colors)) + if (env_colors != NULL && SAFE_isdigit(*env_colors)) { int colors = atoi((char *)env_colors); @@ -5849,7 +5849,7 @@ handle_dcs(char_u *tp, char_u *argp, int len, char_u *key_name, int *slen) // characters. for (i = j + 3; i < len; ++i) { - if (i - j == 3 && !isdigit(tp[i])) + if (i - j == 3 && !SAFE_isdigit(tp[i])) break; if (i - j == 4 && tp[i] != ' ') break; @@ -6083,7 +6083,7 @@ check_termcode( // The mouse termcode "ESC [" is also the prefix of // "ESC [ I" (focus gained) and other keys. Check some // more bytes to find out. - if (!isdigit(tp[2])) + if (!SAFE_isdigit(tp[2])) { // ESC [ without number following: Only use it when // there is no other match. @@ -6166,7 +6166,7 @@ check_termcode( // Skip over the digits, the final char must // follow. URXVT can use a negative value, thus // also accept '-'. - for (j = slen - 2; j < len && (isdigit(tp[j]) + for (j = slen - 2; j < len && (SAFE_isdigit(tp[j]) || tp[j] == '-' || tp[j] == ';'); ++j) ; ++j; diff --git a/src/terminal.c b/src/terminal.c index f79d102e8c..a641a850b0 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -853,13 +853,13 @@ ex_terminal(exarg_T *eap) else opt.jo_term_api = NULL; } - else if (OPTARG_HAS("rows") && ep != NULL && isdigit(ep[1])) + else if (OPTARG_HAS("rows") && ep != NULL && SAFE_isdigit(ep[1])) { opt.jo_set2 |= JO2_TERM_ROWS; opt.jo_term_rows = atoi((char *)ep + 1); p = skiptowhite(cmd); } - else if (OPTARG_HAS("cols") && ep != NULL && isdigit(ep[1])) + else if (OPTARG_HAS("cols") && ep != NULL && SAFE_isdigit(ep[1])) { opt.jo_set2 |= JO2_TERM_COLS; opt.jo_term_cols = atoi((char *)ep + 1); @@ -5463,11 +5463,11 @@ read_dump_file(FILE *fd, VTermPos *cursor_pos) // use same attr as previous cell c = fgetc(fd); } - else if (isdigit(c)) + else if (SAFE_isdigit(c)) { // get the decimal attribute attr = 0; - while (isdigit(c)) + while (SAFE_isdigit(c)) { attr = attr * 10 + (c - '0'); c = fgetc(fd); @@ -5499,9 +5499,9 @@ read_dump_file(FILE *fd, VTermPos *cursor_pos) c = fgetc(fd); blue = (blue << 4) + hex2nr(c); c = fgetc(fd); - if (!isdigit(c)) + if (!SAFE_isdigit(c)) dump_is_corrupt(&ga_text); - while (isdigit(c)) + while (SAFE_isdigit(c)) { index = index * 10 + (c - '0'); c = fgetc(fd); @@ -5565,7 +5565,7 @@ read_dump_file(FILE *fd, VTermPos *cursor_pos) for (;;) { c = fgetc(fd); - if (!isdigit(c)) + if (!SAFE_isdigit(c)) break; count = count * 10 + (c - '0'); } diff --git a/src/typval.c b/src/typval.c index 35c9e24eb8..af96b3170b 100644 --- a/src/typval.c +++ b/src/typval.c @@ -2425,7 +2425,7 @@ eval_string(char_u **arg, typval_T *rettv, int evaluate, int interpolate) if (vim_isxdigit(p[1])) { int n, nr; - int c = toupper(*p); + int c = SAFE_toupper(*p); if (c == 'X') n = 2; diff --git a/src/uninstall.c b/src/uninstall.c index 78b2b7d3cf..907ed37976 100644 --- a/src/uninstall.c +++ b/src/uninstall.c @@ -29,7 +29,7 @@ confirm(void) char answer[10]; fflush(stdout); - return (scanf(" %c", answer) == 1 && toupper(answer[0]) == 'Y'); + return (scanf(" %c", answer) == 1 && toupper((unsigned char)answer[0]) == 'Y'); } static int diff --git a/src/userfunc.c b/src/userfunc.c index c0a2487b46..64761ecdb7 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -77,7 +77,7 @@ one_function_arg( while (ASCII_ISALNUM(*p) || *p == '_') ++p; - if (arg == p || isdigit(*arg) + if (arg == p || SAFE_isdigit(*arg) || (argtypes == NULL && ((p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0) || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0)))) @@ -2272,7 +2272,7 @@ func_requires_g_prefix(ufunc_T *ufunc) return ufunc->uf_name[0] != K_SPECIAL && (ufunc->uf_flags & FC_LAMBDA) == 0 && vim_strchr(ufunc->uf_name, AUTOLOAD_CHAR) == NULL - && !isdigit(ufunc->uf_name[0]); + && !SAFE_isdigit(ufunc->uf_name[0]); } /* @@ -2448,8 +2448,8 @@ cleanup_function_call(funccall_T *fc) static int numbered_function(char_u *name) { - return isdigit(*name) - || (name[0] == 'g' && name[1] == ':' && isdigit(name[2])); + return SAFE_isdigit(*name) + || (name[0] == 'g' && name[1] == ':' && SAFE_isdigit(name[2])); } /* @@ -4653,7 +4653,7 @@ list_functions(regmatch_T *regmatch) && (regmatch == NULL ? !message_filtered(fp->uf_name) && !func_name_refcount(fp->uf_name) - : !isdigit(*fp->uf_name) + : !SAFE_isdigit(*fp->uf_name) && vim_regexec(regmatch, fp->uf_name, 0))) { if (list_func_head(fp, FALSE) == FAIL) diff --git a/src/version.c b/src/version.c index 42d58897e5..3dc537d180 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 6, /**/ 5, /**/ @@ -1328,9 +1330,9 @@ do_intro_line( if (highest_patch()) { // Check for 9.9x or 9.9xx, alpha/beta version - if (isalpha((int)vers[3])) + if (SAFE_isalpha((int)vers[3])) { - int len = (isalpha((int)vers[4])) ? 5 : 4; + int len = (SAFE_isalpha((int)vers[4])) ? 5 : 4; sprintf((char *)vers + len, ".%d%s", highest_patch(), mediumVersion + len); } diff --git a/src/vim9compile.c b/src/vim9compile.c index ad1f6b4aa8..d6faa7bb97 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3159,7 +3159,7 @@ get_cmd_count(char_u *line, exarg_T *eap) // skip over colons and white space for (p = line; *p == ':' || VIM_ISWHITE(*p); ++p) ; - if (!isdigit(*p)) + if (!SAFE_isdigit(*p)) { // The command or modifiers must be following. Assume a lower case // character means there is a modifier. diff --git a/src/vim9expr.c b/src/vim9expr.c index 31fa824a7b..38a65d4424 100644 --- a/src/vim9expr.c +++ b/src/vim9expr.c @@ -1950,7 +1950,7 @@ get_compare_type(char_u *p, int *len, int *type_is) if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') *len = 5; i = p[*len]; - if (!isalnum(i) && i != '_') + if (!SAFE_isalnum(i) && i != '_') { type = *len == 2 ? EXPR_IS : EXPR_ISNOT; *type_is = TRUE; diff --git a/src/viminfo.c b/src/viminfo.c index 58bf419194..540422c8ca 100644 --- a/src/viminfo.c +++ b/src/viminfo.c @@ -1068,7 +1068,7 @@ barline_parse(vir_T *virp, char_u *text, garray_T *values) } } - if (isdigit(*p)) + if (SAFE_isdigit(*p)) { value->bv_type = BVAL_NR; value->bv_nr = getdigits(&p); @@ -2485,7 +2485,7 @@ read_viminfo_filemark(vir_T *virp, int force) str = virp->vir_line + 1; if (*str <= 127 && ((*virp->vir_line == '\'' - && (VIM_ISDIGIT(*str) || isupper(*str))) + && (VIM_ISDIGIT(*str) || SAFE_isupper(*str))) || (*virp->vir_line == '-' && *str == '\''))) { if (*str == '\'') diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c index c90bc027e8..26f8d8365d 100644 --- a/src/xxd/xxd.c +++ b/src/xxd/xxd.c @@ -96,8 +96,8 @@ # include #endif #include -#include /* for strncmp() */ -#include /* for isalnum() */ +#include +#include #include #if __MWERKS__ && !defined(BEBOX) # include /* for fdopen() on MAC */ @@ -208,7 +208,7 @@ char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa; #define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */ #define HEX_LITTLEENDIAN 4 -#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c) +#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c)) #define COLOR_PROLOGUE \ l[c++] = '\033'; \ @@ -952,9 +952,9 @@ main(int argc, char *argv[]) if (varname != NULL) { - FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((int)varname[0]) ? "__" : "")); + FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((unsigned char)varname[0]) ? "__" : "")); for (e = 0; (c = varname[e]) != 0; e++) - putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo); + putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo); fputs_or_die("[] = {\n", fpo); } @@ -972,9 +972,9 @@ main(int argc, char *argv[]) if (varname != NULL) { fputs_or_die("};\n", fpo); - FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((int)varname[0]) ? "__" : "")); + FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : "")); for (e = 0; (c = varname[e]) != 0; e++) - putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo); + putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo); FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p)); }