Ensure that control characters in user supplied error and warning messages are escaped.
PR 84195 * tree.c (escaped_string): New class. Converts an unescaped string into its escaped equivalent. (warn_deprecated_use): Use the new class to convert the deprecation message, if present. (test_escaped_strings): New self test. (test_c_tests): Add test_escaped_strings. From-SVN: r261697
This commit is contained in:
parent
a7fc274f87
commit
eede1a6bf3
2 changed files with 158 additions and 7 deletions
|
@ -1,3 +1,21 @@
|
|||
2018-06-18 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR 84195
|
||||
* tree.c (escaped_string): New class. Converts an unescaped
|
||||
string into its escaped equivalent.
|
||||
(warn_deprecated_use): Use the new class to convert the
|
||||
deprecation message, if present.
|
||||
(test_escaped_strings): New self test.
|
||||
(test_c_tests): Add test_escaped_strings.
|
||||
* doc/extend.texi (deprecated): Add a note that the
|
||||
deprecation message is affected by the -fmessage-length
|
||||
option, and that control characters will be escaped.
|
||||
(#pragma GCC error): Document this pragma.
|
||||
(#pragma GCC warning): Likewise.
|
||||
* doc/invoke.texi (-fmessage-length): Document this option's
|
||||
effect on the #warning and #error preprocessor directives and
|
||||
the deprecated attribute.
|
||||
|
||||
2018-06-18 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* tree.c (decl_value_expr_lookup): Revert latest change.
|
||||
|
|
147
gcc/tree.c
147
gcc/tree.c
|
@ -12423,13 +12423,103 @@ typedef_variant_p (const_tree type)
|
|||
return is_typedef_decl (TYPE_NAME (type));
|
||||
}
|
||||
|
||||
/* A class to handle converting a string that might contain
|
||||
control characters, (eg newline, form-feed, etc), into one
|
||||
in which contains escape sequences instead. */
|
||||
|
||||
class escaped_string
|
||||
{
|
||||
public:
|
||||
escaped_string () { m_owned = false; m_str = NULL; };
|
||||
~escaped_string () { if (m_owned) free (m_str); }
|
||||
operator const char *() const { return (const char *) m_str; }
|
||||
void escape (const char *);
|
||||
private:
|
||||
char *m_str;
|
||||
bool m_owned;
|
||||
};
|
||||
|
||||
/* PR 84195: Replace control characters in "unescaped" with their
|
||||
escaped equivalents. Allow newlines if -fmessage-length has
|
||||
been set to a non-zero value. This is done here, rather than
|
||||
where the attribute is recorded as the message length can
|
||||
change between these two locations. */
|
||||
|
||||
void
|
||||
escaped_string::escape (const char *unescaped)
|
||||
{
|
||||
char *escaped;
|
||||
size_t i, new_i, len;
|
||||
|
||||
if (m_owned)
|
||||
free (m_str);
|
||||
|
||||
m_str = (char *) unescaped;
|
||||
m_owned = false;
|
||||
|
||||
if (unescaped == NULL || *unescaped == 0)
|
||||
return;
|
||||
|
||||
len = strlen (unescaped);
|
||||
escaped = NULL;
|
||||
new_i = 0;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
char c = unescaped[i];
|
||||
|
||||
if (!ISCNTRL (c))
|
||||
{
|
||||
if (escaped)
|
||||
escaped[new_i++] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c != '\n' || !pp_is_wrapping_line (global_dc->printer))
|
||||
{
|
||||
if (escaped == NULL)
|
||||
{
|
||||
/* We only allocate space for a new string if we
|
||||
actually encounter a control character that
|
||||
needs replacing. */
|
||||
escaped = (char *) xmalloc (len * 2 + 1);
|
||||
strncpy (escaped, unescaped, i);
|
||||
new_i = i;
|
||||
}
|
||||
|
||||
escaped[new_i++] = '\\';
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\a': escaped[new_i++] = 'a'; break;
|
||||
case '\b': escaped[new_i++] = 'b'; break;
|
||||
case '\f': escaped[new_i++] = 'f'; break;
|
||||
case '\n': escaped[new_i++] = 'n'; break;
|
||||
case '\r': escaped[new_i++] = 'r'; break;
|
||||
case '\t': escaped[new_i++] = 't'; break;
|
||||
case '\v': escaped[new_i++] = 'v'; break;
|
||||
default: escaped[new_i++] = '?'; break;
|
||||
}
|
||||
}
|
||||
else if (escaped)
|
||||
escaped[new_i++] = c;
|
||||
}
|
||||
|
||||
if (escaped)
|
||||
{
|
||||
escaped[new_i] = 0;
|
||||
m_str = escaped;
|
||||
m_owned = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Warn about a use of an identifier which was marked deprecated. Returns
|
||||
whether a warning was given. */
|
||||
|
||||
bool
|
||||
warn_deprecated_use (tree node, tree attr)
|
||||
{
|
||||
const char *msg;
|
||||
escaped_string msg;
|
||||
|
||||
if (node == 0 || !warn_deprecated_decl)
|
||||
return false;
|
||||
|
@ -12451,16 +12541,14 @@ warn_deprecated_use (tree node, tree attr)
|
|||
attr = lookup_attribute ("deprecated", attr);
|
||||
|
||||
if (attr)
|
||||
msg = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)));
|
||||
else
|
||||
msg = NULL;
|
||||
msg.escape (TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
|
||||
|
||||
bool w = false;
|
||||
if (DECL_P (node))
|
||||
{
|
||||
if (msg)
|
||||
w = warning (OPT_Wdeprecated_declarations,
|
||||
"%qD is deprecated: %s", node, msg);
|
||||
"%qD is deprecated: %s", node, (const char *) msg);
|
||||
else
|
||||
w = warning (OPT_Wdeprecated_declarations,
|
||||
"%qD is deprecated", node);
|
||||
|
@ -12485,7 +12573,7 @@ warn_deprecated_use (tree node, tree attr)
|
|||
{
|
||||
if (msg)
|
||||
w = warning (OPT_Wdeprecated_declarations,
|
||||
"%qE is deprecated: %s", what, msg);
|
||||
"%qE is deprecated: %s", what, (const char *) msg);
|
||||
else
|
||||
w = warning (OPT_Wdeprecated_declarations,
|
||||
"%qE is deprecated", what);
|
||||
|
@ -12494,11 +12582,12 @@ warn_deprecated_use (tree node, tree attr)
|
|||
{
|
||||
if (msg)
|
||||
w = warning (OPT_Wdeprecated_declarations,
|
||||
"type is deprecated: %s", msg);
|
||||
"type is deprecated: %s", (const char *) msg);
|
||||
else
|
||||
w = warning (OPT_Wdeprecated_declarations,
|
||||
"type is deprecated");
|
||||
}
|
||||
|
||||
if (w && decl)
|
||||
inform (DECL_SOURCE_LOCATION (decl), "declared here");
|
||||
}
|
||||
|
@ -14537,6 +14626,49 @@ test_location_wrappers ()
|
|||
check_strip_nops (wrapped_int_var, int_var);
|
||||
}
|
||||
|
||||
/* Check that string escaping works correctly. */
|
||||
|
||||
static void
|
||||
test_escaped_strings (void)
|
||||
{
|
||||
int saved_cutoff;
|
||||
escaped_string msg;
|
||||
|
||||
msg.escape (NULL);
|
||||
/* ASSERT_STREQ does not accept NULL as a valid test
|
||||
result, so we have to use ASSERT_EQ instead. */
|
||||
ASSERT_EQ (NULL, (const char *) msg);
|
||||
|
||||
msg.escape ("");
|
||||
ASSERT_STREQ ("", (const char *) msg);
|
||||
|
||||
msg.escape ("foobar");
|
||||
ASSERT_STREQ ("foobar", (const char *) msg);
|
||||
|
||||
/* Ensure that we have -fmessage-length set to 0. */
|
||||
saved_cutoff = pp_line_cutoff (global_dc->printer);
|
||||
pp_line_cutoff (global_dc->printer) = 0;
|
||||
|
||||
msg.escape ("foo\nbar");
|
||||
ASSERT_STREQ ("foo\\nbar", (const char *) msg);
|
||||
|
||||
msg.escape ("\a\b\f\n\r\t\v");
|
||||
ASSERT_STREQ ("\\a\\b\\f\\n\\r\\t\\v", (const char *) msg);
|
||||
|
||||
/* Now repeat the tests with -fmessage-length set to 5. */
|
||||
pp_line_cutoff (global_dc->printer) = 5;
|
||||
|
||||
/* Note that the newline is not translated into an escape. */
|
||||
msg.escape ("foo\nbar");
|
||||
ASSERT_STREQ ("foo\nbar", (const char *) msg);
|
||||
|
||||
msg.escape ("\a\b\f\n\r\t\v");
|
||||
ASSERT_STREQ ("\\a\\b\\f\n\\r\\t\\v", (const char *) msg);
|
||||
|
||||
/* Restore the original message length setting. */
|
||||
pp_line_cutoff (global_dc->printer) = saved_cutoff;
|
||||
}
|
||||
|
||||
/* Run all of the selftests within this file. */
|
||||
|
||||
void
|
||||
|
@ -14547,6 +14679,7 @@ tree_c_tests ()
|
|||
test_labels ();
|
||||
test_vector_cst_patterns ();
|
||||
test_location_wrappers ();
|
||||
test_escaped_strings ();
|
||||
}
|
||||
|
||||
} // namespace selftest
|
||||
|
|
Loading…
Add table
Reference in a new issue