1  /* Reduced from qemu-7.2.0's qobject/json-parser.c, which
       2     is licensed under LGPLv2.1 or later.  */
       3  
       4  /* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */
       5  
       6  #define NULL ((void *)0)
       7  typedef __builtin_va_list va_list;
       8  typedef __SIZE_TYPE__ size_t;
       9  
      10  typedef struct _GString GString;
      11  typedef struct _GQueue GQueue;
      12  typedef struct Error Error;
      13  typedef struct QDict QDict;
      14  typedef struct QList QList;
      15  typedef struct QObject QObject;
      16  typedef struct QString QString;
      17  
      18  typedef enum QType {
      19    /* [...snip...] */
      20    QTYPE_QSTRING,
      21    /* [...snip...] */
      22  } QType;
      23  
      24  struct QObjectBase_ {
      25    QType type;
      26  };
      27  
      28  struct QObject {
      29    struct QObjectBase_ base;
      30  };
      31  
      32  #define QOBJECT(obj) ((QObject *)obj)
      33  #define qobject_unref(OBJ) /* [...snip...] */
      34  
      35  void qobject_ref_impl(QObject *obj);
      36  QType qobject_type(const QObject *obj);
      37  QObject *qobject_check_type(const QObject *obj, QType type);
      38  
      39  typedef struct QTailQLink {
      40    void *tql_next;
      41    struct QTailQLink *tql_prev;
      42  } QTailQLink;
      43  
      44  typedef struct QDictEntry {
      45    char *key;
      46    QObject *value;
      47    struct {
      48      struct QDictEntry *le_next;
      49      struct QDictEntry **le_prev;
      50    } next;
      51  } QDictEntry;
      52  
      53  struct QDict {
      54    struct QObjectBase_ base;
      55    size_t size;
      56    struct {
      57      struct QDictEntry *lh_first;
      58    } table[512];
      59  };
      60  
      61  QDict *qdict_new(void);
      62  void qdict_put_obj(QDict *qdict, const char *key, QObject *value);
      63  int qdict_haskey(const QDict *qdict, const char *key);
      64  typedef struct QListEntry {
      65    QObject *value;
      66    union {
      67      struct QListEntry *tqe_next;
      68      QTailQLink tqe_circ;
      69    } next;
      70  } QListEntry;
      71  
      72  struct QList {
      73    struct QObjectBase_ base;
      74    union {
      75      struct QListEntry *tqh_first;
      76      QTailQLink tqh_circ;
      77    } head;
      78  };
      79  QList *qlist_new(void);
      80  void qlist_append_obj(QList *qlist, QObject *obj);
      81  
      82  struct QString {
      83    struct QObjectBase_ base;
      84    const char *string;
      85  };
      86  QString *qstring_from_str(const char *str);
      87  const char *qstring_get_str(const QString *qstring);
      88  
      89  typedef enum json_token_type {
      90    JSON_ERROR = 0,
      91  
      92    JSON_LCURLY = 100,
      93    JSON_MIN = JSON_LCURLY,
      94    JSON_RCURLY,
      95    JSON_LSQUARE,
      96    JSON_RSQUARE,
      97    JSON_COLON,
      98    JSON_COMMA,
      99    JSON_INTEGER,
     100    JSON_FLOAT,
     101    JSON_KEYWORD,
     102    JSON_STRING,
     103    JSON_INTERP,
     104    JSON_END_OF_INPUT,
     105    JSON_MAX = JSON_END_OF_INPUT
     106  } JSONTokenType;
     107  typedef struct JSONToken JSONToken;
     108  
     109  struct JSONToken {
     110    JSONTokenType type;
     111    int x;
     112    int y;
     113    char str[];
     114  };
     115  
     116  typedef struct JSONParserContext {
     117    Error *err;
     118    JSONToken *current;
     119    GQueue *buf;
     120    va_list *ap;
     121  } JSONParserContext;
     122  static QObject *parse_value(JSONParserContext *ctxt);
     123  
     124  void __attribute__((__format__(gnu_printf, 3, 4)))
     125  parse_error(JSONParserContext *ctxt, JSONToken *token, const char *msg, ...);
     126  
     127  JSONToken *parser_context_pop_token(JSONParserContext *ctxt);
     128  JSONToken *parser_context_peek_token(JSONParserContext *ctxt);
     129  
     130  static int parse_pair(JSONParserContext *ctxt, QDict *dict) {
     131    QObject *key_obj = NULL;
     132    QString *key;
     133    QObject *value;
     134    JSONToken *peek, *token;
     135  
     136    peek = parser_context_peek_token(ctxt);
     137    if (peek == NULL) {
     138      parse_error(ctxt, NULL, "premature EOI");
     139      goto out;
     140    }
     141  
     142    key_obj = parse_value(ctxt); /* { dg-bogus "infinite recursion" } */
     143    key = ((QString *)qobject_check_type(key_obj, QTYPE_QSTRING));
     144    if (!key) {
     145      parse_error(ctxt, peek, "key is not a string in object");
     146      goto out;
     147    }
     148  
     149    token = parser_context_pop_token(ctxt);
     150    if (token == NULL) {
     151      parse_error(ctxt, NULL, "premature EOI");
     152      goto out;
     153    }
     154  
     155    if (token->type != JSON_COLON) {
     156      parse_error(ctxt, token, "missing : in object pair");
     157      goto out;
     158    }
     159  
     160    value = parse_value(ctxt);
     161    if (value == NULL) {
     162      parse_error(ctxt, token, "Missing value in dict");
     163      goto out;
     164    }
     165  
     166    if (qdict_haskey(dict, qstring_get_str(key))) {
     167      parse_error(ctxt, token, "duplicate key");
     168      goto out;
     169    }
     170  
     171    qdict_put_obj(dict, qstring_get_str(key), value);
     172  
     173    qobject_unref(key_obj);
     174    return 0;
     175  
     176  out:
     177    qobject_unref(key_obj);
     178    return -1;
     179  }
     180  
     181  static QObject *parse_object(JSONParserContext *ctxt) {
     182    QDict *dict = NULL;
     183    JSONToken *token, *peek;
     184  
     185    token = parser_context_pop_token(ctxt);
     186  
     187    dict = qdict_new();
     188  
     189    peek = parser_context_peek_token(ctxt);
     190    if (peek == NULL) {
     191      parse_error(ctxt, NULL, "premature EOI");
     192      goto out;
     193    }
     194  
     195    if (peek->type != JSON_RCURLY) {
     196      if (parse_pair(ctxt, dict) == -1) {
     197        goto out;
     198      }
     199  
     200      token = parser_context_pop_token(ctxt);
     201      if (token == NULL) {
     202        parse_error(ctxt, NULL, "premature EOI");
     203        goto out;
     204      }
     205  
     206      while (token->type != JSON_RCURLY) {
     207        if (token->type != JSON_COMMA) {
     208          parse_error(ctxt, token, "expected separator in dict");
     209          goto out;
     210        }
     211  
     212        if (parse_pair(ctxt, dict) == -1) {
     213          goto out;
     214        }
     215  
     216        token = parser_context_pop_token(ctxt);
     217        if (token == NULL) {
     218          parse_error(ctxt, NULL, "premature EOI");
     219          goto out;
     220        }
     221      }
     222    } else {
     223      (void)parser_context_pop_token(ctxt);
     224    }
     225  
     226    return QOBJECT(dict);
     227  
     228  out:
     229    qobject_unref (dict);
     230    return NULL;
     231  }
     232  
     233  static QObject *parse_array(JSONParserContext *ctxt) {
     234    QList *list = NULL;
     235    JSONToken *token, *peek;
     236  
     237    token = parser_context_pop_token(ctxt);
     238  
     239    list = qlist_new();
     240  
     241    peek = parser_context_peek_token(ctxt);
     242    if (peek == NULL) {
     243      parse_error(ctxt, NULL, "premature EOI");
     244      goto out;
     245    }
     246  
     247    if (peek->type != JSON_RSQUARE) {
     248      QObject *obj;
     249  
     250      obj = parse_value(ctxt); /* { dg-bogus "infinite recursion" } */
     251      if (obj == NULL) {
     252        parse_error(ctxt, token, "expecting value");
     253        goto out;
     254      }
     255  
     256      qlist_append_obj(list, obj);
     257  
     258      token = parser_context_pop_token(ctxt);
     259      if (token == NULL) {
     260        parse_error(ctxt, NULL, "premature EOI");
     261        goto out;
     262      }
     263  
     264      while (token->type != JSON_RSQUARE) {
     265        if (token->type != JSON_COMMA) {
     266          parse_error(ctxt, token, "expected separator in list");
     267          goto out;
     268        }
     269  
     270        obj = parse_value(ctxt);
     271        if (obj == NULL) {
     272          parse_error(ctxt, token, "expecting value");
     273          goto out;
     274        }
     275  
     276        qlist_append_obj(list, obj);
     277  
     278        token = parser_context_pop_token(ctxt);
     279        if (token == NULL) {
     280          parse_error(ctxt, NULL, "premature EOI");
     281          goto out;
     282        }
     283      }
     284    } else {
     285      (void)parser_context_pop_token(ctxt);
     286    }
     287  
     288    return QOBJECT(list);
     289  
     290  out:
     291    qobject_unref(list);
     292    return NULL;
     293  }
     294  
     295  QObject *parse_keyword(JSONParserContext *ctxt);
     296  QObject *parse_literal(JSONParserContext *ctxt);
     297  
     298  QObject *parse_value(JSONParserContext *ctxt) {
     299    JSONToken *token;
     300  
     301    token = parser_context_peek_token(ctxt);
     302    if (token == NULL) {
     303      parse_error(ctxt, NULL, "premature EOI");
     304      return NULL;
     305    }
     306  
     307    switch (token->type) {
     308    case JSON_LCURLY:
     309      return parse_object(ctxt); /* { dg-bogus "infinite recursion" } */
     310    case JSON_LSQUARE:
     311      return parse_array(ctxt); /* { dg-bogus "infinite recursion" } */
     312    case JSON_INTEGER:
     313    case JSON_FLOAT:
     314    case JSON_STRING:
     315      return parse_literal(ctxt);
     316    case JSON_KEYWORD:
     317      return parse_keyword(ctxt);
     318    default:
     319      parse_error(ctxt, token, "expecting value");
     320      return NULL;
     321    }
     322  }