jit: fix string escaping

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.
This commit is contained in:
David Malcolm 2020-11-12 17:27:28 -05:00
parent 8948a5715b
commit fec5734083
3 changed files with 55 additions and 13 deletions

View 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;

View 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

View 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
}