From eaefc9149313076a994c821b186ce8ddc418ac0c Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 31 May 2017 10:22:20 -0400
Subject: [PATCH 32/38] FIXME: json.c fixes

---
 gcc/json.c | 99 +++++++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 63 insertions(+), 36 deletions(-)

diff --git a/gcc/json.c b/gcc/json.c
index 56c6b96..c2dc565 100644
--- a/gcc/json.c
+++ b/gcc/json.c
@@ -321,12 +321,23 @@ object::get_if_nonnull (const char *key) const
 }
 
 /* Set the json::value * for KEY, taking ownership of VALUE
-   (and taking a copy of KEY).  */
+   (and taking a copy of KEY if necessary).  */
 
 void
 object::set (const char *key, value *v)
 {
-  m_map.put (xstrdup (key), v);
+  value **ptr = m_map.get (key);
+  if (ptr)
+    {
+      /* If the key is already present, delete the existing value
+	 and overwrite it.  */
+      delete *ptr;
+      *ptr = v;
+    }
+  else
+    /* If the key wasn't already present, take a copy of the key,
+       and store the value.  */
+    m_map.put (xstrdup (key), v);
 }
 
 /* class json::array, a subclass of json::value, representing
@@ -379,17 +390,9 @@ array::clone () const
 void
 number::print (pretty_printer *pp) const
 {
-  pp_printf (pp, "%i", (int)m_value);
-  double remaining = fabs (m_value - (int)m_value);
-  // FIXME: ensure termination
-  if (remaining)
-    pp_character (pp, '.');
-  while (remaining > 0.0001) // FIXME
-    {
-      remaining *= 10;
-      pp_printf (pp, "%i", (int)remaining);
-      remaining = remaining - (int)remaining;
-    }
+  char tmp[1024];
+  snprintf (tmp, sizeof (tmp), "%g", m_value);
+  pp_string (pp, tmp);
 }
 
 /* Implementation of json::value::clone for json::number.  */
@@ -559,6 +562,7 @@ class lexer
 {
  public:
   lexer ();
+  ~lexer ();
   bool add_utf8 (size_t length, const char *utf8_buf, char **err_out);
 
   const token *peek ();
@@ -589,9 +593,9 @@ class parser
  public:
   parser (char **err_out);
   bool add_utf8 (size_t length, const char *utf8_buf, char **err_out);
-  value *parse_value ();
-  object *parse_object ();
-  array *parse_array ();
+  value *parse_value (int depth);
+  object *parse_object (int depth);
+  array *parse_array (int depth);
 
   bool seen_error_p () const { return *m_err_out; }
   void require_eof ();
@@ -616,6 +620,14 @@ lexer::lexer ()
 {
 }
 
+/* lexer's dtor.  */
+
+lexer::~lexer ()
+{
+  while (m_num_next_tokens > 0)
+    consume ();
+}
+
 /* Peek the next token.  */
 
 const token *
@@ -949,7 +961,7 @@ lexer::lex_string (token *out)
       if (!get_char (uc))
 	{
 	  out->id = TOK_ERROR;
-	  out->u.string = xasprintf ("EOF within string");
+	  out->u.string = xstrdup ("EOF within string");
 	  return;
 	}
       switch (uc)
@@ -963,7 +975,7 @@ lexer::lex_string (token *out)
 	    if (!get_char (next_char))
 	      {
 		out->id = TOK_ERROR;
-		out->u.string = xasprintf ("EOF within string");;
+		out->u.string = xstrdup ("EOF within string");;
 		return;
 	      }
 	    switch (next_char)
@@ -1003,7 +1015,7 @@ lexer::lex_string (token *out)
 		      if (!get_char (hexdigit))
 			{
 			  out->id = TOK_ERROR;
-			  out->u.string = xasprintf ("EOF within string");
+			  out->u.string = xstrdup ("EOF within string");
 			  return;
 			}
 		      result <<= 4;
@@ -1016,7 +1028,7 @@ lexer::lex_string (token *out)
 		      else
 			{
 			  out->id = TOK_ERROR;
-			  out->u.string = xasprintf ("bogus hex char");
+			  out->u.string = xstrdup ("bogus hex char");
 			  return;
 			}
 		    }
@@ -1028,7 +1040,7 @@ lexer::lex_string (token *out)
 
 	      default:
 		out->id = TOK_ERROR;
-		out->u.string = xasprintf ("unrecognized escape char");
+		out->u.string = xstrdup ("unrecognized escape char");
 		return;
 	      }
 	  }
@@ -1040,7 +1052,7 @@ lexer::lex_string (token *out)
 	  if (uc <= 0x1f)
 	    {
 		out->id = TOK_ERROR;
-		out->u.string = xasprintf ("unescaped control char");
+		out->u.string = xstrdup ("unescaped control char");
 		return;
 	    }
 
@@ -1105,7 +1117,7 @@ lexer::lex_number (token *out, unichar first_char)
       if (!get_char (first_char))
 	{
 	  out->id = TOK_ERROR;
-	  out->u.string = xasprintf ("expected digit");
+	  out->u.string = xstrdup ("expected digit");
 	  return;
 	}
     }
@@ -1115,7 +1127,7 @@ lexer::lex_number (token *out, unichar first_char)
   else if (!ISDIGIT (first_char))
     {
       out->id = TOK_ERROR;
-      out->u.string = xasprintf ("expected digit");
+      out->u.string = xstrdup ("expected digit");
       return;
     }
   else
@@ -1165,7 +1177,7 @@ lexer::lex_number (token *out, unichar first_char)
 	  if (!had_digit)
 	    {
 	      out->id = TOK_ERROR;
-	      out->u.string = xasprintf ("expected digit");
+	      out->u.string = xstrdup ("expected digit");
 	      return;
 	    }
 	}
@@ -1187,7 +1199,7 @@ lexer::lex_number (token *out, unichar first_char)
 	  if (!get_char (sign_char))
 	    {
 	      out->id = TOK_ERROR;
-	      out->u.string = xasprintf ("EOF within exponent");
+	      out->u.string = xstrdup ("EOF within exponent");
 	      return;
 	    }
 	  if (sign_char == '-')
@@ -1203,7 +1215,7 @@ lexer::lex_number (token *out, unichar first_char)
 	    {
 	      out->id = TOK_ERROR;
 	      out->u.string
-		= xasprintf ("expected '-','+' or digit within exponent");
+		= xstrdup ("expected '-','+' or digit within exponent");
 	      return;
 	    }
 
@@ -1230,7 +1242,7 @@ lexer::lex_number (token *out, unichar first_char)
 	  if (!had_exponent_digit)
 	    {
 	      out->id = TOK_ERROR;
-	      out->u.string = xasprintf ("expected digit within exponent");
+	      out->u.string = xstrdup ("expected digit within exponent");
 	      return;
 	    }
 	  if (negate_exponent)
@@ -1299,13 +1311,28 @@ parser::add_utf8 (size_t length, const char *utf8_buf, char **err_out)
    (ECMA-404 section 5; RFC 7159 section 3).  */
 
 value *
-parser::parse_value ()
+parser::parse_value (int depth)
 {
   const token *tok = m_lexer.peek ();
+
+  /* Avoid stack overflow with deeply-nested inputs; RFC 7159 section 9
+     states: "An implementation may set limits on the maximum depth
+     of nesting.".
+
+     Ideally we'd avoid this limit (e.g. by rewriting parse_value,
+     parse_object, and parse_array into a single function with a vec of
+     state).  */
+  const int MAX_DEPTH = 100;
+  if (depth >= MAX_DEPTH)
+    {
+      error_at (tok->index, "maximum nesting depth exceeded: %i", MAX_DEPTH);
+      return NULL;
+    }
+
   switch (tok->id)
     {
     case TOK_OPEN_CURLY:
-      return parse_object ();
+      return parse_object (depth);
 
     case TOK_STRING:
       {
@@ -1315,7 +1342,7 @@ parser::parse_value ()
       }
 
     case TOK_OPEN_SQUARE:
-      return parse_array ();
+      return parse_array (depth);
 
     case TOK_NUMBER:
       {
@@ -1355,7 +1382,7 @@ parser::parse_value ()
    (ECMA-404 section 6; RFC 7159 section 4).  */
 
 object *
-parser::parse_object ()
+parser::parse_object (int depth)
 {
   require (TOK_OPEN_CURLY);
 
@@ -1385,7 +1412,7 @@ parser::parse_object ()
 
       require (TOK_COLON);
 
-      value *v = parse_value ();
+      value *v = parse_value (depth + 1);
       if (!v)
 	{
 	  free (key);
@@ -1414,7 +1441,7 @@ parser::parse_object ()
    (ECMA-404 section 7; RFC 7159 section 5).  */
 
 array *
-parser::parse_array ()
+parser::parse_array (int depth)
 {
   require (TOK_OPEN_SQUARE);
 
@@ -1429,7 +1456,7 @@ parser::parse_array ()
 
   while (!seen_error_p ())
     {
-      value *v = parse_value ();
+      value *v = parse_value (depth + 1);
       if (!v)
 	return result;
 
@@ -1520,7 +1547,7 @@ json::parse_utf8_string (size_t length, const char *utf8_buf,
   parser p (err_out);
   if (!p.add_utf8 (length, utf8_buf, err_out))
     return NULL;
-  value *result = p.parse_value ();
+  value *result = p.parse_value (0);
   if (!p.seen_error_p ())
     p.require_eof ();
   if (p.seen_error_p ())
-- 
1.8.5.3

