jit: fix string escaping
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 12 Nov 2020 22:27:28 +0000 (17:27 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 12 Nov 2020 22:27:28 +0000 (17:27 -0500)
This patch fixes a bug in recording::string::make_debug_string in which
'\t' and '\n' were "escaped" by simply prepending a '\', thus emitting
'\' then '\n', rather than '\' then 'n'.  It also removes a hack that
determined if a string is to be escaped by checking for a leading '"',
by instead adding a flag.

gcc/jit/ChangeLog:
* jit-recording.c (recording::context::new_string): Add "escaped"
param and use it when creating the new recording::string instance.
(recording::string::string): Add "escaped" param and use it to
initialize m_escaped.
(recording::string::make_debug_string): Replace check that first
char is double-quote with use of m_escaped.  Fix escaping of
'\t' and '\n'.  Set "escaped" on the result.
* jit-recording.h (recording::context::new_string): Add "escaped"
param.
(recording::string::string): Add "escaped" param.
(recording::string::m_escaped): New field.

gcc/testsuite/ChangeLog:
* jit.dg/test-debug-strings.c (create_code): Add tests of
string literal escaping.

gcc/jit/jit-recording.c
gcc/jit/jit-recording.h
gcc/testsuite/jit.dg/test-debug-strings.c

index 3cbeba0f3714b97d2c50559c508b526bfcfeca12..3a84c1fc5c0c3433b022a10be46e098a36d80d03 100644 (file)
@@ -724,12 +724,12 @@ recording::context::disassociate_from_playback ()
    This creates a fresh copy of the given 0-terminated buffer.  */
 
 recording::string *
-recording::context::new_string (const char *text)
+recording::context::new_string (const char *text, bool escaped)
 {
   if (!text)
     return NULL;
 
-  recording::string *result = new string (this, text);
+  recording::string *result = new string (this, text, escaped);
   record (result);
   return result;
 }
@@ -1954,8 +1954,9 @@ recording::memento::write_to_dump (dump &d)
 /* Constructor for gcc::jit::recording::string::string, allocating a
    copy of the given text using new char[].  */
 
-recording::string::string (context *ctxt, const char *text)
-  : memento (ctxt)
+recording::string::string (context *ctxt, const char *text, bool escaped)
+: memento (ctxt),
+  m_escaped (escaped)
 {
   m_len = strlen (text);
   m_buffer = new char[m_len + 1];
@@ -2005,9 +2006,9 @@ recording::string::from_printf (context *ctxt, const char *fmt, ...)
 recording::string *
 recording::string::make_debug_string ()
 {
-  /* Hack to avoid infinite recursion into strings when logging all
-     mementos: don't re-escape strings:  */
-  if (m_buffer[0] == '"')
+  /* Avoid infinite recursion into strings when logging all mementos:
+     don't re-escape strings:  */
+  if (m_escaped)
     return this;
 
   /* Wrap in quotes and do escaping etc */
@@ -2024,15 +2025,31 @@ recording::string::make_debug_string ()
   for (size_t i = 0; i < m_len ; i++)
     {
       char ch = m_buffer[i];
-      if (ch == '\t' || ch == '\n' || ch == '\\' || ch == '"')
-       APPEND('\\');
-      APPEND(ch);
+      switch (ch)
+       {
+       default:
+         APPEND(ch);
+         break;
+       case '\t':
+         APPEND('\\');
+         APPEND('t');
+         break;
+       case '\n':
+         APPEND('\\');
+         APPEND('n');
+         break;
+       case '\\':
+       case '"':
+         APPEND('\\');
+         APPEND(ch);
+         break;
+       }
     }
   APPEND('"'); /* closing quote */
 #undef APPEND
   tmp[len] = '\0'; /* nil termintator */
 
-  string *result = m_ctxt->new_string (tmp);
+  string *result = m_ctxt->new_string (tmp, true);
 
   delete[] tmp;
   return result;
index 30e37aff387d2c1a3f8cf0333a367d4f51a3ab49..9a43a7bf33a744f53e3d2f74de6f5e81aa36b2b2 100644 (file)
@@ -74,7 +74,7 @@ public:
   void disassociate_from_playback ();
 
   string *
-  new_string (const char *text);
+  new_string (const char *text, bool escaped = false);
 
   location *
   new_location (const char *filename,
@@ -414,7 +414,7 @@ private:
 class string : public memento
 {
 public:
-  string (context *ctxt, const char *text);
+  string (context *ctxt, const char *text, bool escaped);
   ~string ();
 
   const char *c_str () { return m_buffer; }
@@ -431,6 +431,11 @@ private:
 private:
   size_t m_len;
   char *m_buffer;
+
+  /* Flag to track if this string is the result of string::make_debug_string,
+     to avoid infinite recursion when logging all mementos: don't re-escape
+     such strings.  */
+  bool m_escaped;
 };
 
 class location : public memento
index e515a176257351f493c327f6b3c67becadba6926..03ef3370d94c85c871e981744422c96bb008a4b4 100644 (file)
@@ -178,6 +178,26 @@ create_code (gcc_jit_context *ctxt, void *user_data)
                               "((struct node *)ptr->next)->next");
   }
 
+  /* Check string literal escaping.  */
+  {
+    CHECK_RVALUE_DEBUG_STRING
+      (gcc_jit_context_new_string_literal (ctxt, ""),
+       "\"\"");
+    CHECK_RVALUE_DEBUG_STRING
+      (gcc_jit_context_new_string_literal (ctxt, "foo"),
+       "\"foo\"");
+    CHECK_RVALUE_DEBUG_STRING
+      (gcc_jit_context_new_string_literal (ctxt, "\""),
+       "\"\\\"\"");
+    CHECK_RVALUE_DEBUG_STRING
+      (gcc_jit_context_new_string_literal (ctxt, "line 1\nline 2\n"),
+       "\"line 1\\nline 2\\n\"");
+    CHECK_RVALUE_DEBUG_STRING
+      (gcc_jit_context_new_string_literal (ctxt, "foo\tbar"),
+       "\"foo\\tbar\"");
+  }
+
+#undef CHECK_RVALUE_DEBUG_STRING
 #undef CHECK_LVALUE_DEBUG_STRING
 }