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;
> 

Reply via email to