From 8c523f59907d2c57cddea80e5f49d036ce4e052e Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 17 May 2017 15:54:24 -0400
Subject: [PATCH 02/31] FIXME: fix memory leaks

---
 gcc/json.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 108 insertions(+), 11 deletions(-)

diff --git a/gcc/json.c b/gcc/json.c
index 16e51c4..a920972 100644
--- a/gcc/json.c
+++ b/gcc/json.c
@@ -20,14 +20,36 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "obstack.h"
 #include "selftest.h"
 
 namespace json
 {
 
+class value;
+  class string;
+  class number;
+  class object;
+  class array;
+  class literal;
+
+/* FIXME: do we want a context to own everything, or do we want
+   explicit deallocation?
+   TODO: how do we run the dtors for the vec/hash_map within object/array ?  */
 #if 0
 class context
 {
+ public:
+  context ();
+  ~context ();
+
+  string *new_string (const char *buf);
+  number *new_number (double value);
+  object *new_object ();
+  array *new_array ();
+
+ private:
+  struct obstack m_obstack;
 };
 #endif
 
@@ -47,6 +69,7 @@ enum kind
 class value
 {
  public:
+  virtual ~value () {}
   virtual enum kind get_kind () const = 0;
 };
 
@@ -55,14 +78,17 @@ class value
 class object : public value
 {
  public:
+  ~object ();
+
   enum kind get_kind () const FINAL OVERRIDE { return JSON_OBJECT; }
 
   value *get (const char *key) const;
-  void set (const char *key, value *v);
+  void set (char *key, value *v);
 
  private:
-  hash_map <const char *, value *,
-    simple_hashmap_traits<nofree_string_hash, value *> > m_map;
+  typedef hash_map <char *, value *,
+    simple_hashmap_traits<nofree_string_hash, value *> > map_t;
+  map_t m_map;
 };
 
 /* Subclass of value for arrays.  */
@@ -70,6 +96,8 @@ class object : public value
 class array : public value
 {
  public:
+  ~array ();
+
   enum kind get_kind () const FINAL OVERRIDE { return JSON_ARRAY; }
 
   unsigned get_length () const { return m_elements.length (); }
@@ -100,14 +128,15 @@ class number : public value
 class string : public value
 {
  public:
-  string (const char *utf8) : m_utf8 (utf8) {}
+  string (const char *utf8) : m_utf8 (xstrdup (utf8)) {}
+  ~string () { free (m_utf8); }
 
   enum kind get_kind () const FINAL OVERRIDE { return JSON_STRING; }
 
   const char *get_string () const { return m_utf8; }
 
  private:
-  const char *m_utf8;
+  char *m_utf8;
 };
 
 /* Subclass of value for the literals "true", "false", and "null".  */
@@ -125,6 +154,53 @@ class literal : public value
 
 /* Implemenation.  */
 
+#if 0
+/* class context.  */
+
+context::context ()
+{
+  gcc_obstack_init (&m_obstack);
+}
+
+context::~context ()
+{
+  obstack_free (&m_obstack, NULL);
+}
+
+string *
+context::new_string (const char *buf)
+{
+  return new (XOBNEW (&m_obstack, json::string)) json::string (buf);
+}
+
+number *
+context::new_number (double value)
+{
+  return new (XOBNEW (&m_obstack, json::number)) json::number (value);
+}
+
+object *
+context::new_object ()
+{
+  return new (XOBNEW (&m_obstack, json::object)) json::object ();
+}
+
+array *
+context::new_array ()
+{
+  return new (XOBNEW (&m_obstack, json::array)) json::array ();
+}
+#endif
+
+object::~object ()
+{
+  for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
+    {
+      free (const_cast <char *>((*it).first));
+      delete ((*it).second);
+    }
+}
+
 value *
 object::get (const char *key) const
 {
@@ -134,12 +210,23 @@ object::get (const char *key) const
   return NULL;
 }
 
+/* Takes ownership of KEY and VALUE.  */
+
 void
-object::set (const char *key, value *v)
+object::set (char *key, value *v)
 {
   m_map.put (key, v);
 }
 
+array::~array ()
+{
+  unsigned i;
+  value *v;
+  FOR_EACH_VEC_ELT (m_elements, i, v)
+    delete v;
+}
+
+
 /* Parsing decls.  */
 
 extern value *parse_utf8_string (const char *utf8);
@@ -262,9 +349,12 @@ lexer::consume ()
   dump_token (stderr, &m_next_tokens[0]);
   fprintf (stderr, "\n");
 
+  if (m_next_tokens[0].id == TOK_STRING)
+    free (m_next_tokens[0].u.string);
+
+  m_num_next_tokens--;
   memmove (&m_next_tokens[0], &m_next_tokens[1],
 	   sizeof (token) * m_num_next_tokens);
-  m_num_next_tokens--;
 }
 
 void
@@ -536,7 +626,7 @@ parser::parse_value ()
     return parse_object ();
   else if (tok->id == TOK_STRING)
     {
-      string *result = new json::string (tok->u.string);
+      string *result = new string (tok->u.string);
       m_lexer.consume ();
       return result;
     }
@@ -544,7 +634,7 @@ parser::parse_value ()
     return parse_array ();
   else if (tok->id == TOK_NUMBER)
     {
-      number *result = new json::number (tok->u.number);
+      number *result = new number (tok->u.number);
       m_lexer.consume ();
       return result;
     }
@@ -577,7 +667,7 @@ parser::parse_object ()
       tok = m_lexer.peek ();
       if (tok->id != TOK_STRING)
 	error ("expected string for object key");
-      const char *key = tok->u.string;
+      char *key = xstrdup (tok->u.string);
       m_lexer.consume ();
 
       require (TOK_COLON);
@@ -673,6 +763,7 @@ test_parse_string ()
   json::value *jv = parse_utf8_string ("\"foo\"");
   ASSERT_EQ (JSON_STRING, jv->get_kind ());
   ASSERT_STREQ ("foo", ((json::string *)jv)->get_string ());
+  delete jv;
 }
 
 static void
@@ -681,6 +772,7 @@ test_parse_number ()
   json::value *jv = parse_utf8_string ("42");
   ASSERT_EQ (JSON_NUMBER, jv->get_kind ());
   ASSERT_EQ (42.0, ((json::number *)jv)->get ());
+  delete jv;
 }
 
 static void
@@ -696,12 +788,14 @@ test_parse_array ()
       ASSERT_EQ (JSON_NUMBER, element->get_kind ());
       ASSERT_EQ (i, ((json::number *)element)->get ());
     }
+  delete jv;
 }
 
 static void
 test_parse_object ()
 {
-  json::value *jv = parse_utf8_string ("{\"foo\": \"bar\", \"baz\": [42, 43]}");
+  json::value *jv
+    = parse_utf8_string ("{\"foo\": \"bar\", \"baz\": [42, 43]}");
   ASSERT_TRUE (jv != NULL);
   ASSERT_EQ (JSON_OBJECT, jv->get_kind ());
   json::object *jo = static_cast <json::object *> (jv);
@@ -723,6 +817,8 @@ test_parse_object ()
 
   // TODO: error-handling
   // TODO: partial document
+
+  delete jv;
 }
 
 static void
@@ -731,6 +827,7 @@ test_parse_empty_object ()
   json::value *jv = parse_utf8_string ("{}");
   ASSERT_TRUE (jv != NULL);
   ASSERT_EQ (JSON_OBJECT, jv->get_kind ());
+  delete jv;
 }
 
 /* Run all of the selftests within this file.  */
-- 
1.8.5.3

