charset: Do not call strlen() from vim_str2nr

This commit is contained in:
ZyX
2017-10-16 00:19:02 +03:00
parent 1a3635304b
commit 5e92ee6565
2 changed files with 24 additions and 26 deletions

View File

@@ -1620,14 +1620,12 @@ bool vim_isblankline(char_u *lbuf)
/// @param maxlen Max length of string to check. /// @param maxlen Max length of string to check.
void vim_str2nr(const char_u *const start, int *const prep, int *const len, void vim_str2nr(const char_u *const start, int *const prep, int *const len,
const int what, varnumber_T *const nptr, const int what, varnumber_T *const nptr,
uvarnumber_T *const unptr, int maxlen) uvarnumber_T *const unptr, const int maxlen)
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(1)
{ {
const char *ptr = (const char *)start; const char *ptr = (const char *)start;
if (maxlen == 0) { #define STRING_ENDED(ptr) \
maxlen = (int)strlen(ptr); (!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
}
const char *const e = ptr + maxlen;
int pre = 0; // default is decimal int pre = 0; // default is decimal
bool negative = false; bool negative = false;
@@ -1638,18 +1636,18 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
// Recognize hex, octal and bin. // Recognize hex, octal and bin.
if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
&& maxlen > 1 && !STRING_ENDED(ptr + 1)
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
pre = ptr[1]; pre = ptr[1];
if ((what & STR2NR_HEX) if ((what & STR2NR_HEX)
&& maxlen > 2 && !STRING_ENDED(ptr + 2)
&& (pre == 'X' || pre == 'x') && (pre == 'X' || pre == 'x')
&& ascii_isxdigit(ptr[2])) { && ascii_isxdigit(ptr[2])) {
// hexadecimal // hexadecimal
ptr += 2; ptr += 2;
} else if ((what & STR2NR_BIN) } else if ((what & STR2NR_BIN)
&& maxlen > 2 && !STRING_ENDED(ptr + 2)
&& (pre == 'B' || pre == 'b') && (pre == 'B' || pre == 'b')
&& ascii_isbdigit(ptr[2])) { && ascii_isbdigit(ptr[2])) {
// binary // binary
@@ -1660,7 +1658,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
if (what & STR2NR_OCT) { if (what & STR2NR_OCT) {
// Don't interpret "0", "08" or "0129" as octal. // Don't interpret "0", "08" or "0129" as octal.
for (int i = 1; i < maxlen && ascii_isdigit(ptr[i]); i++) { for (int i = 1; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
if (ptr[i] > '7') { if (ptr[i] > '7') {
// can't be octal // can't be octal
pre = 0; pre = 0;
@@ -1679,7 +1677,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
uvarnumber_T un = 0; uvarnumber_T un = 0;
if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) { if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) {
// bin // bin
while (ptr < e && '0' <= *ptr && *ptr <= '1') { while (!STRING_ENDED(ptr) && '0' <= *ptr && *ptr <= '1') {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 2) { if (un < UVARNUMBER_MAX / 2) {
un = 2 * un + (uvarnumber_T)(*ptr - '0'); un = 2 * un + (uvarnumber_T)(*ptr - '0');
@@ -1690,7 +1688,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} }
} else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) { } else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) {
// octal // octal
while (ptr < e && '0' <= *ptr && *ptr <= '7') { while (!STRING_ENDED(ptr) && '0' <= *ptr && *ptr <= '7') {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 8) { if (un < UVARNUMBER_MAX / 8) {
un = 8 * un + (uvarnumber_T)(*ptr - '0'); un = 8 * un + (uvarnumber_T)(*ptr - '0');
@@ -1701,7 +1699,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} }
} else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) { } else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) {
// hex // hex
while (ptr < e && ascii_isxdigit(*ptr)) { while (!STRING_ENDED(ptr) && ascii_isxdigit(*ptr)) {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 16) { if (un < UVARNUMBER_MAX / 16) {
un = 16 * un + (uvarnumber_T)hex2nr(*ptr); un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
@@ -1712,7 +1710,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} }
} else { } else {
// decimal // decimal
while (ptr < e && ascii_isdigit(*ptr)) { while (!STRING_ENDED(ptr) && ascii_isdigit(*ptr)) {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 10) { if (un < UVARNUMBER_MAX / 10) {
un = 10 * un + (uvarnumber_T)(*ptr - '0'); un = 10 * un + (uvarnumber_T)(*ptr - '0');
@@ -1750,6 +1748,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
if (unptr != NULL) { if (unptr != NULL) {
*unptr = un; *unptr = un;
} }
#undef STRING_ENDED
} }
/// Return the value of a single hex character. /// Return the value of a single hex character.

View File

@@ -25,13 +25,11 @@ int hex2nr(int c)
void vim_str2nr(const char_u *const start, int *const prep, int *const len, void vim_str2nr(const char_u *const start, int *const prep, int *const len,
const int what, varnumber_T *const nptr, const int what, varnumber_T *const nptr,
uvarnumber_T *const unptr, int maxlen) uvarnumber_T *const unptr, const int maxlen)
{ {
const char *ptr = (const char *)start; const char *ptr = (const char *)start;
if (maxlen == 0) { #define STRING_ENDED(ptr) \
maxlen = (int)strlen(ptr); (!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
}
const char *const e = ptr + maxlen;
int pre = 0; // default is decimal int pre = 0; // default is decimal
bool negative = false; bool negative = false;
@@ -42,18 +40,18 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
// Recognize hex, octal and bin. // Recognize hex, octal and bin.
if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
&& maxlen > 1 && !STRING_ENDED(ptr + 1)
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
pre = ptr[1]; pre = ptr[1];
if ((what & STR2NR_HEX) if ((what & STR2NR_HEX)
&& maxlen > 2 && !STRING_ENDED(ptr + 2)
&& (pre == 'X' || pre == 'x') && (pre == 'X' || pre == 'x')
&& ascii_isxdigit(ptr[2])) { && ascii_isxdigit(ptr[2])) {
// hexadecimal // hexadecimal
ptr += 2; ptr += 2;
} else if ((what & STR2NR_BIN) } else if ((what & STR2NR_BIN)
&& maxlen > 2 && !STRING_ENDED(ptr + 2)
&& (pre == 'B' || pre == 'b') && (pre == 'B' || pre == 'b')
&& ascii_isbdigit(ptr[2])) { && ascii_isbdigit(ptr[2])) {
// binary // binary
@@ -64,7 +62,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
if (what & STR2NR_OCT) { if (what & STR2NR_OCT) {
// Don't interpret "0", "08" or "0129" as octal. // Don't interpret "0", "08" or "0129" as octal.
for (int i = 1; i < maxlen && ascii_isdigit(ptr[i]); i++) { for (int i = 1; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
if (ptr[i] > '7') { if (ptr[i] > '7') {
// can't be octal // can't be octal
pre = 0; pre = 0;
@@ -83,7 +81,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
uvarnumber_T un = 0; uvarnumber_T un = 0;
if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) { if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) {
// bin // bin
while (ptr < e && '0' <= *ptr && *ptr <= '1') { while (!STRING_ENDED(ptr) && '0' <= *ptr && *ptr <= '1') {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 2) { if (un < UVARNUMBER_MAX / 2) {
un = 2 * un + (uvarnumber_T)(*ptr - '0'); un = 2 * un + (uvarnumber_T)(*ptr - '0');
@@ -94,7 +92,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} }
} else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) { } else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) {
// octal // octal
while (ptr < e && '0' <= *ptr && *ptr <= '7') { while (!STRING_ENDED(ptr) && '0' <= *ptr && *ptr <= '7') {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 8) { if (un < UVARNUMBER_MAX / 8) {
un = 8 * un + (uvarnumber_T)(*ptr - '0'); un = 8 * un + (uvarnumber_T)(*ptr - '0');
@@ -105,7 +103,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} }
} else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) { } else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) {
// hex // hex
while (ptr < e && ascii_isxdigit(*ptr)) { while (!STRING_ENDED(ptr) && ascii_isxdigit(*ptr)) {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 16) { if (un < UVARNUMBER_MAX / 16) {
un = 16 * un + (uvarnumber_T)hex2nr(*ptr); un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
@@ -116,7 +114,7 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
} }
} else { } else {
// decimal // decimal
while (ptr < e && ascii_isdigit(*ptr)) { while (!STRING_ENDED(ptr) && ascii_isdigit(*ptr)) {
// avoid ubsan error for overflow // avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 10) { if (un < UVARNUMBER_MAX / 10) {
un = 10 * un + (uvarnumber_T)(*ptr - '0'); un = 10 * un + (uvarnumber_T)(*ptr - '0');
@@ -154,4 +152,5 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
if (unptr != NULL) { if (unptr != NULL) {
*unptr = un; *unptr = un;
} }
#undef STRING_ENDED
} }