On Sun, Jul 12, 2020 at 09:57:02AM +0430, Ali Farzanrad wrote: > Hi @tech, > > I was comparing jsmn.c in acme-client with jsmn.c in FreeBSD [1]. > I found a switch without a default case which is an undefined behavior: > > @@ -69,6 +69,8 @@ > case '\t' : case '\r' : case '\n' : case ' ' : > case ',' : case ']' : case '}' : > goto found; > + default: > + break; > } > if (js[parser->pos] < 32 || js[parser->pos] >= 127) { > parser->pos = start; > > I have patched that undefined behavior + some style fix.
It is bad practise to intermix style changes with bug fixes. Please post the fix seperately. -Otto > > [1] https://svnweb.freebsd.org/base/head/lib/libpmc/pmu-events/jsmn.c > > Index: jsmn.c > =================================================================== > RCS file: /cvs/src/usr.sbin/acme-client/jsmn.c,v > retrieving revision 1.1 > diff -u -p -r1.1 jsmn.c > --- jsmn.c 31 Aug 2016 22:01:42 -0000 1.1 > +++ jsmn.c 12 Jul 2020 05:10:34 -0000 > @@ -1,31 +1,33 @@ > /* > - Copyright (c) 2010 Serge A. Zaitsev > - > - Permission is hereby granted, free of charge, to any person obtaining a copy > - of this software and associated documentation files (the "Software"), to > deal > - in the Software without restriction, including without limitation the rights > - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > - copies of the Software, and to permit persons to whom the Software is > - furnished to do so, subject to the following conditions: > - > - The above copyright notice and this permission notice shall be included in > - all copies or substantial portions of the Software. > - > - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE > - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > FROM, > - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > - THE SOFTWARE.* > + * Copyright (c) 2010 Serge A. Zaitsev > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > copy > + * of this software and associated documentation files (the "Software"), to > deal > + * in the Software without restriction, including without limitation the > rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > THE > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > */ > + > #include "jsmn.h" > > -/** > - * Allocates a fresh unused token from the token pull. > +/* > + * Allocates a fresh unused token from the token pool. > */ > -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, > - jsmntok_t *tokens, size_t num_tokens) { > +static jsmntok_t * > +jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens) > +{ > jsmntok_t *tok; > if (parser->toknext >= num_tokens) { > return NULL; > @@ -39,22 +41,25 @@ static jsmntok_t *jsmn_alloc_token(jsmn_ > return tok; > } > > -/** > +/* > * Fills token type and boundaries. > */ > -static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, > - int start, int end) { > +static void > +jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) > +{ > token->type = type; > token->start = start; > token->end = end; > token->size = 0; > } > > -/** > +/* > * Fills next available token with JSON primitive. > */ > -static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, > - size_t len, jsmntok_t *tokens, size_t num_tokens) { > +static int > +jsmn_parse_primitive(jsmn_parser *parser, const char *js, > + size_t len, jsmntok_t *tokens, size_t num_tokens) > +{ > jsmntok_t *token; > int start; > > @@ -63,12 +68,19 @@ static int jsmn_parse_primitive(jsmn_par > for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { > switch (js[parser->pos]) { > #ifndef JSMN_STRICT > - /* In strict mode primitive must be followed by "," or > "}" or "]" */ > - case ':': > + /* In strict mode primitive must be followed by "," or "}" or > "]" */ > + case ':': > #endif > - case '\t' : case '\r' : case '\n' : case ' ' : > - case ',' : case ']' : case '}' : > - goto found; > + case '\t': > + case '\r': > + case '\n': > + case ' ': > + case ',': > + case ']': > + case '}': > + goto found; > + default: > + break; > } > if (js[parser->pos] < 32 || js[parser->pos] >= 127) { > parser->pos = start; > @@ -99,13 +111,14 @@ found: > return 0; > } > > -/** > +/* > * Fills next token with JSON string. > */ > -static int jsmn_parse_string(jsmn_parser *parser, const char *js, > - size_t len, jsmntok_t *tokens, size_t num_tokens) { > +static int > +jsmn_parse_string(jsmn_parser *parser, const char *js, > + size_t len, jsmntok_t *tokens, size_t num_tokens) > +{ > jsmntok_t *token; > - > int start = parser->pos; > > parser->pos++; > @@ -137,28 +150,34 @@ static int jsmn_parse_string(jsmn_parser > parser->pos++; > switch (js[parser->pos]) { > /* Allowed escaped symbols */ > - case '\"': case '/' : case '\\' : case 'b' : > - case 'f' : case 'r' : case 'n' : case 't' : > - break; > + case '\"': > + case '/': > + case '\\': > + case 'b': > + case 'f': > + case 'r': > + case 'n': > + case 't': > + break; > /* Allows escaped symbol \uXXXX */ > - case 'u': > - parser->pos++; > - for(i = 0; i < 4 && parser->pos < len > && js[parser->pos] != '\0'; i++) { > - /* If it isn't a hex character > we have an error */ > - if(!((js[parser->pos] >= 48 && > js[parser->pos] <= 57) || /* 0-9 */ > - > (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ > - > (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ > - parser->pos = start; > - return JSMN_ERROR_INVAL; > - } > - parser->pos++; > + case 'u': > + parser->pos++; > + for(i = 0; i < 4 && parser->pos < len && > js[parser->pos] != '\0'; i++) { > + /* If it isn't a hex character we have > an error */ > + if(!((js[parser->pos] >= 48 && > js[parser->pos] <= 57) || /* 0-9 */ > + > (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ > + > (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ > + parser->pos = start; > + return JSMN_ERROR_INVAL; > } > - parser->pos--; > - break; > + parser->pos++; > + } > + parser->pos--; > + break; > /* Unexpected symbol */ > - default: > - parser->pos = start; > - return JSMN_ERROR_INVAL; > + default: > + parser->pos = start; > + return JSMN_ERROR_INVAL; > } > } > } > @@ -166,11 +185,13 @@ static int jsmn_parse_string(jsmn_parser > return JSMN_ERROR_PART; > } > > -/** > +/* > * Parse JSON string and fill tokens. > */ > -int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, > - jsmntok_t *tokens, unsigned int num_tokens) { > +int > +jsmn_parse(jsmn_parser *parser, const char *js, size_t len, > + jsmntok_t *tokens, unsigned int num_tokens) > +{ > int r; > int i; > jsmntok_t *token; > @@ -182,128 +203,147 @@ int jsmn_parse(jsmn_parser *parser, cons > > c = js[parser->pos]; > switch (c) { > - case '{': case '[': > - count++; > - if (tokens == NULL) { > - break; > - } > - token = jsmn_alloc_token(parser, tokens, > num_tokens); > - if (token == NULL) > - return JSMN_ERROR_NOMEM; > - if (parser->toksuper != -1) { > - tokens[parser->toksuper].size++; > + case '{': > + case '[': > + count++; > + if (tokens == NULL) { > + break; > + } > + token = jsmn_alloc_token(parser, tokens, num_tokens); > + if (token == NULL) > + return JSMN_ERROR_NOMEM; > + if (parser->toksuper != -1) { > + tokens[parser->toksuper].size++; > #ifdef JSMN_PARENT_LINKS > - token->parent = parser->toksuper; > + token->parent = parser->toksuper; > #endif > - } > - token->type = (c == '{' ? JSMN_OBJECT : > JSMN_ARRAY); > - token->start = parser->pos; > - parser->toksuper = parser->toknext - 1; > + } > + token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); > + token->start = parser->pos; > + parser->toksuper = parser->toknext - 1; > + break; > + case '}': > + case ']': > + if (tokens == NULL) > break; > - case '}': case ']': > - if (tokens == NULL) > - break; > - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); > + type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); > #ifdef JSMN_PARENT_LINKS > - if (parser->toknext < 1) { > - return JSMN_ERROR_INVAL; > - } > - token = &tokens[parser->toknext - 1]; > - for (;;) { > - if (token->start != -1 && token->end == > -1) { > - if (token->type != type) { > - return JSMN_ERROR_INVAL; > - } > - token->end = parser->pos + 1; > - parser->toksuper = > token->parent; > - break; > - } > - if (token->parent == -1) { > - break; > + if (parser->toknext < 1) { > + return JSMN_ERROR_INVAL; > + } > + token = &tokens[parser->toknext - 1]; > + for (;;) { > + if (token->start != -1 && token->end == -1) { > + if (token->type != type) { > + return JSMN_ERROR_INVAL; > } > - token = &tokens[token->parent]; > + token->end = parser->pos + 1; > + parser->toksuper = token->parent; > + break; > + } > + if (token->parent == -1) { > + break; > } > + token = &tokens[token->parent]; > + } > #else > - for (i = parser->toknext - 1; i >= 0; i--) { > - token = &tokens[i]; > - if (token->start != -1 && token->end == > -1) { > - if (token->type != type) { > - return JSMN_ERROR_INVAL; > - } > - parser->toksuper = -1; > - token->end = parser->pos + 1; > - break; > + for (i = parser->toknext - 1; i >= 0; i--) { > + token = &tokens[i]; > + if (token->start != -1 && token->end == -1) { > + if (token->type != type) { > + return JSMN_ERROR_INVAL; > } > + parser->toksuper = -1; > + token->end = parser->pos + 1; > + break; > } > - /* Error if unmatched closing bracket */ > - if (i == -1) return JSMN_ERROR_INVAL; > - for (; i >= 0; i--) { > - token = &tokens[i]; > - if (token->start != -1 && token->end == > -1) { > - parser->toksuper = i; > - break; > - } > + } > + /* Error if unmatched closing bracket */ > + if (i == -1) > + return JSMN_ERROR_INVAL; > + for (; i >= 0; i--) { > + token = &tokens[i]; > + if (token->start != -1 && token->end == -1) { > + parser->toksuper = i; > + break; > } > + } > #endif > - break; > - case '\"': > - r = jsmn_parse_string(parser, js, len, tokens, > num_tokens); > - if (r < 0) return r; > - count++; > - if (parser->toksuper != -1 && tokens != NULL) > - tokens[parser->toksuper].size++; > - break; > - case '\t' : case '\r' : case '\n' : case ' ': > - break; > - case ':': > - parser->toksuper = parser->toknext - 1; > - break; > - case ',': > - if (tokens != NULL && parser->toksuper != -1 && > - tokens[parser->toksuper].type > != JSMN_ARRAY && > - tokens[parser->toksuper].type > != JSMN_OBJECT) { > + break; > + case '\"': > + r = jsmn_parse_string(parser, js, len, tokens, > num_tokens); > + if (r < 0) > + return r; > + count++; > + if (parser->toksuper != -1 && tokens != NULL) > + tokens[parser->toksuper].size++; > + break; > + case '\t': > + case '\r': > + case '\n': > + case ' ': > + break; > + case ':': > + parser->toksuper = parser->toknext - 1; > + break; > + case ',': > + if (tokens != NULL && parser->toksuper != -1 && > + tokens[parser->toksuper].type != > JSMN_ARRAY && > + tokens[parser->toksuper].type != > JSMN_OBJECT) { > #ifdef JSMN_PARENT_LINKS > - parser->toksuper = > tokens[parser->toksuper].parent; > + parser->toksuper = > tokens[parser->toksuper].parent; > #else > - for (i = parser->toknext - 1; i >= 0; > i--) { > - if (tokens[i].type == > JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { > - if (tokens[i].start != > -1 && tokens[i].end == -1) { > - > parser->toksuper = i; > - break; > - } > + for (i = parser->toknext - 1; i >= 0; i--) { > + if (tokens[i].type == JSMN_ARRAY || > tokens[i].type == JSMN_OBJECT) { > + if (tokens[i].start != -1 && > tokens[i].end == -1) { > + parser->toksuper = i; > + break; > } > } > -#endif > } > - break; > +#endif > + } > + break; > #ifdef JSMN_STRICT > /* In strict mode primitives are: numbers and booleans > */ > - case '-': case '0': case '1' : case '2': case '3' : > case '4': > - case '5': case '6': case '7' : case '8': case '9': > - case 't': case 'f': case 'n' : > - /* And they must not be keys of the object */ > - if (tokens != NULL && parser->toksuper != -1) { > - jsmntok_t *t = > &tokens[parser->toksuper]; > - if (t->type == JSMN_OBJECT || > - (t->type == JSMN_STRING > && t->size != 0)) { > - return JSMN_ERROR_INVAL; > - } > + case '-': > + case '0': > + case '1': > + case '2': > + case '3': > + case '4': > + case '5': > + case '6': > + case '7': > + case '8': > + case '9': > + case 't': > + case 'f': > + case 'n': > + /* And they must not be keys of the object */ > + if (tokens != NULL && parser->toksuper != -1) { > + jsmntok_t *t = &tokens[parser->toksuper]; > + if (t->type == JSMN_OBJECT || > + (t->type == JSMN_STRING && > t->size != 0)) { > + return JSMN_ERROR_INVAL; > } > + } > #else > /* In non-strict mode every unquoted value is a > primitive */ > - default: > + default: > #endif > - r = jsmn_parse_primitive(parser, js, len, > tokens, num_tokens); > - if (r < 0) return r; > - count++; > - if (parser->toksuper != -1 && tokens != NULL) > - tokens[parser->toksuper].size++; > - break; > + r = jsmn_parse_primitive(parser, js, len, tokens, > num_tokens); > + if (r < 0) > + return r; > + count++; > + if (parser->toksuper != -1 && tokens != NULL) > + tokens[parser->toksuper].size++; > + break; > > #ifdef JSMN_STRICT > /* Unexpected char in strict mode */ > - default: > - return JSMN_ERROR_INVAL; > + default: > + return JSMN_ERROR_INVAL; > #endif > } > } > @@ -320,11 +360,13 @@ int jsmn_parse(jsmn_parser *parser, cons > return count; > } > > -/** > +/* > * Creates a new parser based over a given buffer with an array of tokens > * available. > */ > -void jsmn_init(jsmn_parser *parser) { > +void > +jsmn_init(jsmn_parser *parser) > +{ > parser->pos = 0; > parser->toknext = 0; > parser->toksuper = -1; >