source: lib/json.c @ b201c68

Last change on this file since b201c68 was eab8e52, checked in by Miklos Vajna <vmiklos@…>, at 2013-01-01T15:31:22Z

json: fix uninitialized variables

json.c: In function ‘json_parse_ex’:
json.c:260:30: warning: ‘string_length’ may be used uninitialized in this function [-Wmaybe-uninitialized]
json.c:358:16: warning: ‘string’ may be used uninitialized in this function [-Wmaybe-uninitialized]

  • Property mode set to 100644
File size: 19.3 KB
RevLine 
[696dc9e]1
2/* vim: set et ts=3 sw=3 ft=c:
3 *
4 * Copyright (C) 2012 James McLaughlin et al.  All rights reserved.
5 * https://github.com/udp/json-parser
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *   notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *   notice, this list of conditions and the following disclaimer in the
16 *   documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include "json.h"
32
33#ifdef _MSC_VER
34   #ifndef _CRT_SECURE_NO_WARNINGS
35      #define _CRT_SECURE_NO_WARNINGS
36   #endif
37#endif
38
39#ifdef __cplusplus
40   const struct _json_value json_value_none; /* zero-d by ctor */
41#else
42   const struct _json_value json_value_none = { 0 };
43#endif
44
[e8161ec]45#include <glib.h>
[696dc9e]46#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <ctype.h>
50
51typedef unsigned short json_uchar;
52
53static unsigned char hex_value (json_char c)
54{
55   if (c >= 'A' && c <= 'F')
56      return (c - 'A') + 10;
57
58   if (c >= 'a' && c <= 'f')
59      return (c - 'a') + 10;
60
61   if (c >= '0' && c <= '9')
62      return c - '0';
63
64   return 0xFF;
65}
66
67typedef struct
68{
69   json_settings settings;
70   int first_pass;
71
72   unsigned long used_memory;
73
74   unsigned int uint_max;
75   unsigned long ulong_max;
76
77} json_state;
78
79static void * json_alloc (json_state * state, unsigned long size, int zero)
80{
81   void * mem;
82
83   if ((state->ulong_max - state->used_memory) < size)
84      return 0;
85
86   if (state->settings.max_memory
87         && (state->used_memory += size) > state->settings.max_memory)
88   {
89      return 0;
90   }
91
92   if (! (mem = zero ? calloc (size, 1) : malloc (size)))
93      return 0;
94
95   return mem;
96}
97
98static int new_value
99   (json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type)
100{
101   json_value * value;
102   int values_size;
103
104   if (!state->first_pass)
105   {
106      value = *top = *alloc;
107      *alloc = (*alloc)->_reserved.next_alloc;
108
109      if (!*root)
110         *root = value;
111
112      switch (value->type)
113      {
114         case json_array:
115
116            if (! (value->u.array.values = (json_value **) json_alloc
117               (state, value->u.array.length * sizeof (json_value *), 0)) )
118            {
119               return 0;
120            }
121
122            break;
123
124         case json_object:
125
126            values_size = sizeof (*value->u.object.values) * value->u.object.length;
127
128            if (! ((*(void **) &value->u.object.values) = json_alloc
129                  (state, values_size + ((unsigned long) value->u.object.values), 0)) )
130            {
131               return 0;
132            }
133
134            value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size;
135
136            break;
137
138         case json_string:
139
140            if (! (value->u.string.ptr = (json_char *) json_alloc
141               (state, (value->u.string.length + 1) * sizeof (json_char), 0)) )
142            {
143               return 0;
144            }
145
146            break;
147
148         default:
149            break;
150      };
151
152      value->u.array.length = 0;
153
154      return 1;
155   }
156
157   value = (json_value *) json_alloc (state, sizeof (json_value), 1);
158
159   if (!value)
160      return 0;
161
162   if (!*root)
163      *root = value;
164
165   value->type = type;
166   value->parent = *top;
167
168   if (*alloc)
169      (*alloc)->_reserved.next_alloc = value;
170
171   *alloc = *top = value;
172
173   return 1;
174}
175
176#define e_off \
177   ((int) (i - cur_line_begin))
178
179#define whitespace \
180   case '\n': ++ cur_line;  cur_line_begin = i; \
181   case ' ': case '\t': case '\r'
182
183#define string_add(b)  \
184   do { if (!state.first_pass) string [string_length] = b;  ++ string_length; } while (0);
185
186const static int
187   flag_next = 1, flag_reproc = 2, flag_need_comma = 4, flag_seek_value = 8, flag_exponent = 16,
188   flag_got_exponent_sign = 32, flag_escaped = 64, flag_string = 128, flag_need_colon = 256,
189   flag_done = 512;
190
191json_value * json_parse_ex (json_settings * settings, const json_char * json, char * error_buf)
192{
193   json_char error [128];
194   unsigned int cur_line;
195   const json_char * cur_line_begin, * i;
196   json_value * top, * root, * alloc = 0;
197   json_state state;
198   int flags;
199
200   error[0] = '\0';
201
202   memset (&state, 0, sizeof (json_state));
203   memcpy (&state.settings, settings, sizeof (json_settings));
204
205   memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
206   memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
207
208   state.uint_max -= 8; /* limit of how much can be added before next check */
209   state.ulong_max -= 8;
210
211   for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
212   {
213      json_uchar uchar;
214      unsigned char uc_b1, uc_b2, uc_b3, uc_b4;
[eab8e52]215      json_char * string = 0;
216      unsigned int string_length = 0;
[696dc9e]217
218      top = root = 0;
219      flags = flag_seek_value;
220
221      cur_line = 1;
222      cur_line_begin = json;
223
224      for (i = json ;; ++ i)
225      {
226         json_char b = *i;
227
228         if (flags & flag_done)
229         {
230            if (!b)
231               break;
232
233            switch (b)
234            {
235               whitespace:
236                  continue;
237
238               default:
239                  sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b);
240                  goto e_failed;
241            };
242         }
243
244         if (flags & flag_string)
245         {
246            if (!b)
247            {  sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off);
248               goto e_failed;
249            }
250
251            if (string_length > state.uint_max)
252               goto e_overflow;
253
254            if (flags & flag_escaped)
255            {
256               flags &= ~ flag_escaped;
257
258               switch (b)
259               {
260                  case 'b':  string_add ('\b');  break;
261                  case 'f':  string_add ('\f');  break;
262                  case 'n':  string_add ('\n');  break;
263                  case 'r':  string_add ('\r');  break;
264                  case 't':  string_add ('\t');  break;
265                  case 'u':
266
267                    if ((uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF
268                          || (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF)
269                    {
270                        sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off);
271                        goto e_failed;
272                    }
273
274                    uc_b1 = uc_b1 * 16 + uc_b2;
275                    uc_b2 = uc_b3 * 16 + uc_b4;
276
277                    uchar = ((json_char) uc_b1) * 256 + uc_b2;
278
279                    if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F))
280                    {
281                       string_add ((json_char) uchar);
282                       break;
283                    }
284
285                    if (uchar <= 0x7FF)
286                    {
287                        if (state.first_pass)
288                           string_length += 2;
289                        else
[e8161ec]290                        {  string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2);
[696dc9e]291                           string [string_length ++] = 0x80 | (uc_b2 & 0x3F);
292                        }
293
294                        break;
295                    }
296
297                    if (state.first_pass)
298                       string_length += 3;
299                    else
300                    {  string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4);
301                       string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6);
302                       string [string_length ++] = 0x80 | (uc_b2 & 0x3F);
303                    }
304
305                    break;
306
307                  default:
308                     string_add (b);
309               };
310
311               continue;
312            }
313
314            if (b == '\\')
315            {
316               flags |= flag_escaped;
317               continue;
318            }
319
320            if (b == '"')
321            {
322               if (!state.first_pass)
323                  string [string_length] = 0;
324
325               flags &= ~ flag_string;
326               string = 0;
327
328               switch (top->type)
329               {
330                  case json_string:
331
332                     top->u.string.length = string_length;
333                     flags |= flag_next;
334
335                     break;
336
337                  case json_object:
338
339                     if (state.first_pass)
340                        (*(json_char **) &top->u.object.values) += string_length + 1;
341                     else
342                     { 
343                        top->u.object.values [top->u.object.length].name
344                           = (json_char *) top->_reserved.object_mem;
345
346                        (*(json_char **) &top->_reserved.object_mem) += string_length + 1;
347                     }
348
349                     flags |= flag_seek_value | flag_need_colon;
350                     continue;
351
352                  default:
353                     break;
354               };
355            }
356            else
357            {
358               string_add (b);
359               continue;
360            }
361         }
362
363         if (flags & flag_seek_value)
364         {
365            switch (b)
366            {
367               whitespace:
368                  continue;
369
370               case ']':
371
372                  if (top->type == json_array)
373                     flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
374                  else if (!state.settings.settings & json_relaxed_commas)
375                  {  sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off);
376                     goto e_failed;
377                  }
378
379                  break;
380
381               default:
382
383                  if (flags & flag_need_comma)
384                  {
385                     if (b == ',')
386                     {  flags &= ~ flag_need_comma;
387                        continue;
388                     }
389                     else
390                     {  sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b);
391                        goto e_failed;
392                     }
393                  }
394
395                  if (flags & flag_need_colon)
396                  {
397                     if (b == ':')
398                     {  flags &= ~ flag_need_colon;
399                        continue;
400                     }
401                     else
402                     {  sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b);
403                        goto e_failed;
404                     }
405                  }
406
407                  flags &= ~ flag_seek_value;
408
409                  switch (b)
410                  {
411                     case '{':
412
413                        if (!new_value (&state, &top, &root, &alloc, json_object))
414                           goto e_alloc_failure;
415
416                        continue;
417
418                     case '[':
419
420                        if (!new_value (&state, &top, &root, &alloc, json_array))
421                           goto e_alloc_failure;
422
423                        flags |= flag_seek_value;
424                        continue;
425
426                     case '"':
427
428                        if (!new_value (&state, &top, &root, &alloc, json_string))
429                           goto e_alloc_failure;
430
431                        flags |= flag_string;
432
433                        string = top->u.string.ptr;
434                        string_length = 0;
435
436                        continue;
437
438                     case 't':
439
440                        if (*(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e')
441                           goto e_unknown_value;
442
443                        if (!new_value (&state, &top, &root, &alloc, json_boolean))
444                           goto e_alloc_failure;
445
446                        top->u.boolean = 1;
447
448                        flags |= flag_next;
449                        break;
450
451                     case 'f':
452
453                        if (*(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e')
454                           goto e_unknown_value;
455
456                        if (!new_value (&state, &top, &root, &alloc, json_boolean))
457                           goto e_alloc_failure;
458
459                        flags |= flag_next;
460                        break;
461
462                     case 'n':
463
464                        if (*(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l')
465                           goto e_unknown_value;
466
467                        if (!new_value (&state, &top, &root, &alloc, json_null))
468                           goto e_alloc_failure;
469
470                        flags |= flag_next;
471                        break;
472
473                     default:
474
475                        if (isdigit (b) || b == '-')
476                        {
477                           if (!new_value (&state, &top, &root, &alloc, json_integer))
478                              goto e_alloc_failure;
479
480                           flags &= ~ (flag_exponent | flag_got_exponent_sign);
481
482                           if (state.first_pass)
483                              continue;
484
485                           if (top->type == json_double)
[e8161ec]486                              top->u.dbl = g_ascii_strtod (i, (json_char **) &i);
[696dc9e]487                           else
[e8161ec]488                              top->u.integer = g_ascii_strtoll (i, (json_char **) &i, 10);
[696dc9e]489
490                           flags |= flag_next | flag_reproc;
491                        }
492                        else
493                        {  sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b);
494                           goto e_failed;
495                        }
496                  };
497            };
498         }
499         else
500         {
501            switch (top->type)
502            {
503            case json_object:
504               
505               switch (b)
506               {
507                  whitespace:
508                     continue;
509
510                  case '"':
511
512                     if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas))
513                     {
514                        sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off);
515                        goto e_failed;
516                     }
517
518                     flags |= flag_string;
519
520                     string = (json_char *) top->_reserved.object_mem;
521                     string_length = 0;
522
523                     break;
524                 
525                  case '}':
526
527                     flags = (flags & ~ flag_need_comma) | flag_next;
528                     break;
529
530                  case ',':
531
532                     if (flags & flag_need_comma)
533                     {
534                        flags &= ~ flag_need_comma;
535                        break;
536                     }
537
538                  default:
539
540                     sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b);
541                     goto e_failed;
542               };
543
544               break;
545
546            case json_integer:
547            case json_double:
548
549               if (isdigit (b))
550                  continue;
551
552               if (b == 'e' || b == 'E')
553               {
554                  if (!(flags & flag_exponent))
555                  {
556                     flags |= flag_exponent;
557                     top->type = json_double;
558
559                     continue;
560                  }
561               }
562               else if (b == '+' || b == '-')
563               {
564                  if (flags & flag_exponent && !(flags & flag_got_exponent_sign))
565                  {
566                     flags |= flag_got_exponent_sign;
567                     continue;
568                  }
569               }
570               else if (b == '.' && top->type == json_integer)
571               {
572                  top->type = json_double;
573                  continue;
574               }
575
576               flags |= flag_next | flag_reproc;
577               break;
578
579            default:
580               break;
581            };
582         }
583
584         if (flags & flag_reproc)
585         {
586            flags &= ~ flag_reproc;
587            -- i;
588         }
589
590         if (flags & flag_next)
591         {
592            flags = (flags & ~ flag_next) | flag_need_comma;
593
594            if (!top->parent)
595            {
596               /* root value done */
597
598               flags |= flag_done;
599               continue;
600            }
601
602            if (top->parent->type == json_array)
603               flags |= flag_seek_value;
604               
605            if (!state.first_pass)
606            {
607               json_value * parent = top->parent;
608
609               switch (parent->type)
610               {
611                  case json_object:
612
613                     parent->u.object.values
614                        [parent->u.object.length].value = top;
615
616                     break;
617
618                  case json_array:
619
620                     parent->u.array.values
621                           [parent->u.array.length] = top;
622
623                     break;
624
625                  default:
626                     break;
627               };
628            }
629
630            if ( (++ top->parent->u.array.length) > state.uint_max)
631               goto e_overflow;
632
633            top = top->parent;
634
635            continue;
636         }
637      }
638
639      alloc = root;
640   }
641
642   return root;
643
644e_unknown_value:
645
646   sprintf (error, "%d:%d: Unknown value", cur_line, e_off);
647   goto e_failed;
648
649e_alloc_failure:
650
651   strcpy (error, "Memory allocation failure");
652   goto e_failed;
653
654e_overflow:
655
656   sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off);
657   goto e_failed;
658
659e_failed:
660
661   if (error_buf)
662   {
663      if (*error)
664         strcpy (error_buf, error);
665      else
666         strcpy (error_buf, "Unknown error");
667   }
668
669   if (state.first_pass)
670      alloc = root;
671
672   while (alloc)
673   {
674      top = alloc->_reserved.next_alloc;
675      free (alloc);
676      alloc = top;
677   }
678
679   if (!state.first_pass)
680      json_value_free (root);
681
682   return 0;
683}
684
685json_value * json_parse (const json_char * json)
686{
687   json_settings settings;
688   memset (&settings, 0, sizeof (json_settings));
689
690   return json_parse_ex (&settings, json, 0);
691}
692
693void json_value_free (json_value * value)
694{
695   json_value * cur_value;
696
697   if (!value)
698      return;
699
700   value->parent = 0;
701
702   while (value)
703   {
704      switch (value->type)
705      {
706         case json_array:
707
708            if (!value->u.array.length)
709            {
710               free (value->u.array.values);
711               break;
712            }
713
714            value = value->u.array.values [-- value->u.array.length];
715            continue;
716
717         case json_object:
718
719            if (!value->u.object.length)
720            {
721               free (value->u.object.values);
722               break;
723            }
724
725            value = value->u.object.values [-- value->u.object.length].value;
726            continue;
727
728         case json_string:
729
730            free (value->u.string.ptr);
731            break;
732
733         default:
734            break;
735      };
736
737      cur_value = value;
738      value = value->parent;
739      free (cur_value);
740   }
741}
742
743
Note: See TracBrowser for help on using the repository browser.