]> git.kaiwu.me - klib.git/commitdiff
Fix undefined behaviour and sign extension issues in kstrtok
authorRob Davies <rmd+git@sanger.ac.uk>
Wed, 10 Jan 2018 17:05:57 +0000 (17:05 +0000)
committerRob Davies <rmd+git@sanger.ac.uk>
Thu, 11 Jan 2018 14:30:02 +0000 (14:30 +0000)
Prevent read beyond the end of sep if it's an empty string.

Change to internally use unsigned char to avoid unwanted sign
extension on platforms where 'char' is signed.

Fix undefined behaviour where pointers were made to the element
before the start of `str`:
https://www.securecoding.cert.org/confluence/display/c/ARR30-C.+Do+not+form+or+use+out-of-bounds+pointers+or+array+subscripts

kstring.c

index 3e0b6423717a893befb21d87c8c951069dbd3405..aa6c2ee491448f7c1c1ceed064c56985ccd43f59 100644 (file)
--- a/kstring.c
+++ b/kstring.c
@@ -34,28 +34,29 @@ int ksprintf(kstring_t *s, const char *fmt, ...)
        return l;
 }
 
-char *kstrtok(const char *str, const char *sep, ks_tokaux_t *aux)
+char *kstrtok(const char *str, const char *sep_in, ks_tokaux_t *aux)
 {
-       const char *p, *start;
+       const unsigned char *p, *start, *sep = (unsigned char *) sep_in;
        if (sep) { // set up the table
                if (str == 0 && aux->finished) return 0; // no need to set up if we have finished
                aux->finished = 0;
-               if (sep[1]) {
+               if (sep[0] && sep[1]) {
                        aux->sep = -1;
                        aux->tab[0] = aux->tab[1] = aux->tab[2] = aux->tab[3] = 0;
                        for (p = sep; *p; ++p) aux->tab[*p>>6] |= 1ull<<(*p&0x3f);
                } else aux->sep = sep[0];
        }
        if (aux->finished) return 0;
-       else if (str) aux->p = str - 1, aux->finished = 0;
+       else if (str) start = (unsigned char *) str, aux->finished = 0;
+       else start = (unsigned char *) aux->p + 1;
        if (aux->sep < 0) {
-               for (p = start = aux->p + 1; *p; ++p)
+               for (p = start; *p; ++p)
                        if (aux->tab[*p>>6]>>(*p&0x3f)&1) break;
        } else {
-               for (p = start = aux->p + 1; *p; ++p)
+               for (p = start; *p; ++p)
                        if (*p == aux->sep) break;
        }
-       aux->p = p; // end of token
+       aux->p = (const char *) p; // end of token
        if (*p == 0) aux->finished = 1; // no more tokens
        return (char*)start;
 }