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.

[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