summaryrefslogtreecommitdiffstats
path: root/src/jsmn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jsmn.c')
-rw-r--r--src/jsmn.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/src/jsmn.c b/src/jsmn.c
index f190312..889b8d7 100644
--- a/src/jsmn.c
+++ b/src/jsmn.c
@@ -3,6 +3,8 @@
3 * Simple JSON parser 3 * Simple JSON parser
4 * 4 *
5 * Copyright (c) 2010 Serge A. Zaitsev 5 * Copyright (c) 2010 Serge A. Zaitsev
6 * Updated to use size_t for token offsets and harden against overflows.
7 * (Nikias Bassen, January 2026)
6 * 8 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal 10 * of this software and associated documentation files (the "Software"), to deal
@@ -24,20 +26,25 @@
24 */ 26 */
25 27
26#include <stdlib.h> 28#include <stdlib.h>
29#include <stdint.h>
30#include <limits.h>
31#include <assert.h>
27 32
28#include "jsmn.h" 33#include "jsmn.h"
29 34
35#define JSMN_POS_INVALID ((size_t)SIZE_MAX)
36
30/** 37/**
31 * Allocates a fresh unused token from the token pull. 38 * Allocates a fresh unused token from the token pull.
32 */ 39 */
33static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, 40static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
34 jsmntok_t *tokens, int num_tokens) { 41 jsmntok_t *tokens, unsigned int num_tokens) {
35 jsmntok_t *tok; 42 jsmntok_t *tok;
36 if (parser->toknext >= num_tokens) { 43 if ((unsigned int)parser->toknext >= num_tokens) {
37 return NULL; 44 return NULL;
38 } 45 }
39 tok = &tokens[parser->toknext++]; 46 tok = &tokens[parser->toknext++];
40 tok->start = tok->end = -1; 47 tok->start = tok->end = JSMN_POS_INVALID;
41 tok->size = 0; 48 tok->size = 0;
42#ifdef JSMN_PARENT_LINKS 49#ifdef JSMN_PARENT_LINKS
43 tok->parent = -1; 50 tok->parent = -1;
@@ -49,7 +56,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
49 * Fills token type and boundaries. 56 * Fills token type and boundaries.
50 */ 57 */
51static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, 58static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
52 int start, int end) { 59 size_t start, size_t end) {
53 token->type = type; 60 token->type = type;
54 token->start = start; 61 token->start = start;
55 token->end = end; 62 token->end = end;
@@ -60,9 +67,9 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
60 * Fills next available token with JSON primitive. 67 * Fills next available token with JSON primitive.
61 */ 68 */
62static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js, 69static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
63 jsmntok_t *tokens, int num_tokens) { 70 jsmntok_t *tokens, unsigned int num_tokens) {
64 jsmntok_t *token; 71 jsmntok_t *token;
65 int start; 72 size_t start;
66 73
67 start = parser->pos; 74 start = parser->pos;
68 75
@@ -107,10 +114,10 @@ found:
107 * Fills next token with JSON string. 114 * Fills next token with JSON string.
108 */ 115 */
109static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js, 116static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
110 jsmntok_t *tokens, int num_tokens) { 117 jsmntok_t *tokens, unsigned int num_tokens) {
111 jsmntok_t *token; 118 jsmntok_t *token;
112 119
113 int start = parser->pos; 120 size_t start = parser->pos;
114 121
115 parser->pos++; 122 parser->pos++;
116 123
@@ -162,7 +169,7 @@ static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
162/** 169/**
163 * Parse JSON string and fill tokens. 170 * Parse JSON string and fill tokens.
164 */ 171 */
165jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, jsmntok_t *tokens, 172jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t length, jsmntok_t *tokens,
166 unsigned int num_tokens) { 173 unsigned int num_tokens) {
167 jsmnerr_t r; 174 jsmnerr_t r;
168 int i; 175 int i;
@@ -170,6 +177,13 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j
170 177
171 parser->end = length; 178 parser->end = length;
172 179
180 if (num_tokens >= INT_MAX) {
181 return JSMN_ERROR_LIMIT;
182 }
183 if (length > SIZE_MAX / 2) {
184 return JSMN_ERROR_LIMIT;
185 }
186
173 for (; (parser->end > 0 && parser->pos < parser->end) && js[parser->pos] != '\0'; parser->pos++) { 187 for (; (parser->end > 0 && parser->pos < parser->end) && js[parser->pos] != '\0'; parser->pos++) {
174 char c; 188 char c;
175 jsmntype_t type; 189 jsmntype_t type;
@@ -198,10 +212,13 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j
198 } 212 }
199 token = &tokens[parser->toknext - 1]; 213 token = &tokens[parser->toknext - 1];
200 for (;;) { 214 for (;;) {
201 if (token->start != -1 && token->end == -1) { 215 if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) {
202 if (token->type != type) { 216 if (token->type != type) {
203 return JSMN_ERROR_INVAL; 217 return JSMN_ERROR_INVAL;
204 } 218 }
219 if (parser->pos == SIZE_MAX) {
220 return JSMN_ERROR_INVAL;
221 }
205 token->end = parser->pos + 1; 222 token->end = parser->pos + 1;
206 parser->toksuper = token->parent; 223 parser->toksuper = token->parent;
207 break; 224 break;
@@ -214,7 +231,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j
214#else 231#else
215 for (i = parser->toknext - 1; i >= 0; i--) { 232 for (i = parser->toknext - 1; i >= 0; i--) {
216 token = &tokens[i]; 233 token = &tokens[i];
217 if (token->start != -1 && token->end == -1) { 234 if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) {
218 if (token->type != type) { 235 if (token->type != type) {
219 return JSMN_ERROR_INVAL; 236 return JSMN_ERROR_INVAL;
220 } 237 }
@@ -227,7 +244,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j
227 if (i == -1) return JSMN_ERROR_INVAL; 244 if (i == -1) return JSMN_ERROR_INVAL;
228 for (; i >= 0; i--) { 245 for (; i >= 0; i--) {
229 token = &tokens[i]; 246 token = &tokens[i];
230 if (token->start != -1 && token->end == -1) { 247 if (token->start != JSMN_POS_INVALID && token->end == JSMN_POS_INVALID) {
231 parser->toksuper = i; 248 parser->toksuper = i;
232 break; 249 break;
233 } 250 }
@@ -268,7 +285,7 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, unsigned int length, j
268 285
269 for (i = parser->toknext - 1; i >= 0; i--) { 286 for (i = parser->toknext - 1; i >= 0; i--) {
270 /* Unmatched opened object or array */ 287 /* Unmatched opened object or array */
271 if (tokens[i].start != -1 && tokens[i].end == -1) { 288 if (tokens[i].start != JSMN_POS_INVALID && tokens[i].end == JSMN_POS_INVALID) {
272 return JSMN_ERROR_PART; 289 return JSMN_ERROR_PART;
273 } 290 }
274 } 291 }