From df90f070378583f295dd972db4400f324752a240 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 20 Nov 2020 13:44:57 -0700 Subject: [PATCH] PR middle-end/97879 - ICE on invalid mode in attribute access gcc/c-family/ChangeLog: PR middle-end/97879 * c-attribs.c (handle_access_attribute): Handle ATTR_FLAG_INTERNAL. Error out on invalid modes. gcc/c/ChangeLog: PR middle-end/97879 * c-decl.c (start_function): Set ATTR_FLAG_INTERNAL in flags. gcc/ChangeLog: PR middle-end/97879 * tree-core.h (enum attribute_flags): Add ATTR_FLAG_INTERNAL. gcc/testsuite/ChangeLog: PR middle-end/97879 * gcc.dg/attr-access-3.c: New test. --- gcc/c-family/c-attribs.c | 35 +++++++++++++++++++--------- gcc/c/c-decl.c | 3 ++- gcc/testsuite/gcc.dg/attr-access-3.c | 21 +++++++++++++++++ gcc/tree-core.h | 5 +++- 4 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/attr-access-3.c diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index b979fbcc0c6..1d2ab7c81ed 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -2810,9 +2810,11 @@ handle_copy_attribute (tree *node, tree name, tree args, tree attrs = TYPE_ATTRIBUTES (reftype); /* Copy type attributes from REF to DECL. Pass in REF if it's a DECL - or a type but not if it's an expression. */ + or a type but not if it's an expression. Set ATTR_FLAG_INTERNAL + since the attributes' arguments may be in their internal form. */ for (tree at = attrs; at; at = TREE_CHAIN (at)) - decl_attributes (node, at, flags, EXPR_P (ref) ? NULL_TREE : ref); + decl_attributes (node, at, flags | ATTR_FLAG_INTERNAL, + EXPR_P (ref) ? NULL_TREE : ref); return NULL_TREE; } @@ -4289,8 +4291,8 @@ append_access_attr (tree node[3], tree attrs, const char *attrstr, the attribute and its arguments into a string. */ static tree -handle_access_attribute (tree node[3], tree name, tree args, - int ARG_UNUSED (flags), bool *no_add_attrs) +handle_access_attribute (tree node[3], tree name, tree args, int flags, + bool *no_add_attrs) { tree attrs = TYPE_ATTRIBUTES (*node); tree type = *node; @@ -4336,15 +4338,19 @@ handle_access_attribute (tree node[3], tree name, tree args, /* Recursively call self to "replace" the documented/external form of the attribute with the condensend internal form. */ - decl_attributes (node, axsat, flags); + decl_attributes (node, axsat, flags | ATTR_FLAG_INTERNAL); return NULL_TREE; } - /* This is a recursive call to handle the condensed internal form - of the attribute (see below). Since all validation has been - done simply return here, accepting the attribute as is. */ - *no_add_attrs = false; - return NULL_TREE; + if (flags & ATTR_FLAG_INTERNAL) + { + /* This is a recursive call to handle the condensed internal + form of the attribute (see below). Since all validation + has been done simply return here, accepting the attribute + as is. */ + *no_add_attrs = false; + return NULL_TREE; + } } /* Set to true when the access mode has the form of a function call @@ -4363,6 +4369,13 @@ handle_access_attribute (tree node[3], tree name, tree args, access_mode = DECL_NAME (access_mode); funcall = true; } + else if (TREE_CODE (access_mode) != IDENTIFIER_NODE) + { + error ("attribute %qE mode %qE is not an identifier; expected one of " + "%qs, %qs, %qs, or %qs", name, access_mode, + "read_only", "read_write", "write_only", "none"); + return NULL_TREE; + } const char* const access_str = IDENTIFIER_POINTER (access_mode); const char *ps = access_str; @@ -4573,7 +4586,7 @@ handle_access_attribute (tree node[3], tree name, tree args, /* Recursively call self to "replace" the documented/external form of the attribute with the condensed internal form. */ - decl_attributes (node, new_attrs, flags); + decl_attributes (node, new_attrs, flags | ATTR_FLAG_INTERNAL); return NULL_TREE; } diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 1b02240114b..27f77224ea4 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -9598,7 +9598,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, current_function_decl = pushdecl (decl1); if (tree access = build_attr_access_from_parms (parms, false)) - decl_attributes (¤t_function_decl, access, 0, old_decl); + decl_attributes (¤t_function_decl, access, ATTR_FLAG_INTERNAL, + old_decl); push_scope (); declare_parm_level (); diff --git a/gcc/testsuite/gcc.dg/attr-access-3.c b/gcc/testsuite/gcc.dg/attr-access-3.c new file mode 100644 index 00000000000..45dd1aaad11 --- /dev/null +++ b/gcc/testsuite/gcc.dg/attr-access-3.c @@ -0,0 +1,21 @@ +/* PR middle-end/97879 - ICE on invalid mode in attribute access + { dg-do compile } + { dg-options "-Wall" } */ + +#define A(...) __attribute__ ((access (__VA_ARGS__))) + +A (" ", 1) void f1 (int *); // { dg-error "attribute 'access' mode '\" \"' is not an identifier; expected one of 'read_only', 'read_write', 'write_only', or 'none'" } + void f1 (int *); + + +A ("none", 1) void f2 (char *); // { dg-error "not an identifier" } + void f2 (char *); + +A (1) void f3 (); // { dg-error "not an identifier" } + +A (1, 2) void f4 (); // { dg-error "not an identifier" } +A (2., 3.) void f5 (); // { dg-error "not an identifier" } + +// Verify that copying a valid access attribute doesn't cause errors. +A (read_only, 1, 2) void f6 (void*, int); +__attribute__ ((copy (f6))) void f7 (void*, int); diff --git a/gcc/tree-core.h b/gcc/tree-core.h index c9280a8d3b1..313a6af2253 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -859,7 +859,10 @@ enum attribute_flags { are not in fact compatible with the function type. */ ATTR_FLAG_BUILT_IN = 16, /* A given attribute has been parsed as a C++-11 attribute. */ - ATTR_FLAG_CXX11 = 32 + ATTR_FLAG_CXX11 = 32, + /* The attribute handler is being invoked with an internal argument + that may not otherwise be valid when specified in source code. */ + ATTR_FLAG_INTERNAL = 64 }; /* Types used to represent sizes. */ -- 2.30.2