Changeset View
Changeset View
Standalone View
Standalone View
lib/libc/string/strtok.c
Show All 40 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <stddef.h> | #include <stddef.h> | ||||
#ifdef DEBUG_STRTOK | #ifdef DEBUG_STRTOK | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#endif | #endif | ||||
#include <string.h> | #include <string.h> | ||||
char *__strtok_r(char *, const char *, char **); | char *__strtok_r(char * __restrict, const char * __restrict, char ** __restrict); | ||||
__weak_reference(__strtok_r, strtok_r); | __weak_reference(__strtok_r, strtok_r); | ||||
char * | char * | ||||
__strtok_r(char *s, const char *delim, char **last) | __strtok_r(char * __restrict s, const char * __restrict delim, char ** __restrict last) | ||||
{ | { | ||||
char *spanp, *tok; | char *spanp, *tok; | ||||
int c, sc; | int c, sc; | ||||
if (s == NULL && (s = *last) == NULL) | if (s == NULL) | ||||
return (NULL); | s = *last; | ||||
jrtc27: You've lost the return NULL for if s is still NULL | |||||
Done Inline ActionsI mean it is undefined to have s and last be null according to the c standard gfunni234_gmail.com: I mean it is undefined to have s and last be null according to the c standard | |||||
Done Inline ActionsNot true; *last is entirely unspecified and up to the implementation. In particular, when our strtok_r returns the final token, it sets *last to NULL, but the application needs to call strtok_r one more time to see the NULL *return* value. This means the final call to strtok_r for an application iterating over the tokens is going to dereference a null pointer. See https://godbolt.org/z/9qEqb34z4 for an example proving the old code works but your new code renders the standard use broken. Also, strtok_r is POSIX not C. jrtc27: Not true; `*last` is entirely unspecified and up to the implementation. In particular, when our… | |||||
/* | /* | ||||
* Skip (span) leading delimiters (s += strspn(s, delim), sort of). | * Skip (span) leading delimiters (s += strspn(s, delim), sort of). | ||||
*/ | */ | ||||
cont: | cont: | ||||
c = *s++; | c = *s++; | ||||
for (spanp = (char *)delim; (sc = *spanp++) != 0;) { | for (spanp = (char *)delim; (sc = *spanp++) != 0;) { | ||||
if (c == sc) | if (c == sc) | ||||
Show All 23 Lines | do { | ||||
return (tok); | return (tok); | ||||
} | } | ||||
} while (sc != 0); | } while (sc != 0); | ||||
} | } | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
} | } | ||||
char * | char * | ||||
strtok(char *s, const char *delim) | strtok(char * __restrict s, const char * __restrict delim) | ||||
{ | { | ||||
static char *last; | static char *last; | ||||
return (__strtok_r(s, delim, &last)); | return (__strtok_r(s, delim, &last)); | ||||
} | } | ||||
#ifdef DEBUG_STRTOK | #ifdef DEBUG_STRTOK | ||||
/* | /* | ||||
Show All 30 Lines |
You've lost the return NULL for if s is still NULL