From c8fb255fde88c6d2b08dd01f623d95e85ef96d1d Mon Sep 17 00:00:00 2001 From: Colomban Wendling Date: Thu, 25 May 2023 23:26:06 +0200 Subject: [PATCH] Fix calls to ctype functions All ctype functions like `isdigit()` and alike expect a character as an `unsigned char` or EOF, anything else has undefined behavior. This commit should fix all calls to the various ctype functions either: * adding `unsigned char` cast where appropriate; * removing useless `int` casts that are more confusing than useful. Some instances required slightly more involved changes though, but the fix itself is the same. To find the calls to check, I used an equivalent to the following: ``` git grep -P 'is(alnum|alpha|cntrl|x?digit|graph|lower|print|punct|'\ 'space|upper|ascii|blank)|to(low|up)er' ``` ...and then proceeded to manually check them to see if the call, or call chain, was using appropriate values and types. --- readtags.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/readtags.c b/readtags.c index 25c05d31..45488c36 100644 --- a/readtags.c +++ b/readtags.c @@ -135,7 +135,7 @@ static int readtags_fseek(FILE *fp, rt_off_t pos, int whence) } /* Converts a hexadecimal digit to its value */ -static int xdigitValue (char digit) +static int xdigitValue (unsigned char digit) { if (digit >= '0' && digit <= '9') return digit - '0'; @@ -151,32 +151,33 @@ static int xdigitValue (char digit) * Reads the first character from the string, possibly un-escaping it, and * advances *s to the start of the next character. */ -static int readTagCharacter (const char **s) +static int readTagCharacter (const char **const s) { - int c = **(const unsigned char **)s; + const unsigned char *p = (const unsigned char *) *s; + int c = *p; - (*s)++; + p++; if (c == '\\') { - switch (**s) + switch (*p) { - case 't': c = '\t'; (*s)++; break; - case 'r': c = '\r'; (*s)++; break; - case 'n': c = '\n'; (*s)++; break; - case '\\': c = '\\'; (*s)++; break; + case 't': c = '\t'; p++; break; + case 'r': c = '\r'; p++; break; + case 'n': c = '\n'; p++; break; + case '\\': c = '\\'; p++; break; /* Universal-CTags extensions */ - case 'a': c = '\a'; (*s)++; break; - case 'b': c = '\b'; (*s)++; break; - case 'v': c = '\v'; (*s)++; break; - case 'f': c = '\f'; (*s)++; break; + case 'a': c = '\a'; p++; break; + case 'b': c = '\b'; p++; break; + case 'v': c = '\v'; p++; break; + case 'f': c = '\f'; p++; break; case 'x': - if (isxdigit ((*s)[1]) && isxdigit ((*s)[2])) + if (isxdigit (p[1]) && isxdigit (p[2])) { - int val = (xdigitValue ((*s)[1]) << 4) | xdigitValue ((*s)[2]); + int val = (xdigitValue (p[1]) << 4) | xdigitValue (p[2]); if (val < 0x80) { - (*s) += 3; + p += 3; c = val; } } @@ -184,6 +185,8 @@ static int readTagCharacter (const char **s) } } + *s = (const char *) p; + return c; } @@ -610,12 +613,12 @@ static tagResult parseTagLine (tagFile *file, tagEntry *const entry, int *err) else ++p; } - else if (isdigit ((int) *(unsigned char*) p)) + else if (isdigit (*(unsigned char*) p)) { /* parse line number */ entry->address.pattern = p; entry->address.lineNumber = atol (p); - while (isdigit ((int) *(unsigned char*) p)) + while (isdigit (*(unsigned char*) p)) ++p; if (p) {