summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnil Madhavapeddy <avsm@cvs.openbsd.org>2004-04-23 21:19:12 +0000
committerAnil Madhavapeddy <avsm@cvs.openbsd.org>2004-04-23 21:19:12 +0000
commitae834b19461bc0784018ab2c201fffe866af2094 (patch)
tree33394cc3d0d88dd77fe14bfe71f2c4b7f48db89c
parente17ad16e253a789d440f5c4c0a963591f643dd35 (diff)
Port the gcc2 bounds checking support to gcc3, activated with -Wbounded
and documented in gcc-local(1). tested by marc@ brad@ and lots of bulk ports builds
-rw-r--r--gnu/usr.bin/gcc/gcc/Makefile.in7
-rw-r--r--gnu/usr.bin/gcc/gcc/builtin-attrs.def46
-rw-r--r--gnu/usr.bin/gcc/gcc/builtins.def16
-rw-r--r--gnu/usr.bin/gcc/gcc/c-bounded.c490
-rw-r--r--gnu/usr.bin/gcc/gcc/c-common.c44
-rw-r--r--gnu/usr.bin/gcc/gcc/c-common.h6
-rw-r--r--gnu/usr.bin/gcc/gcc/c-format.c50
-rw-r--r--gnu/usr.bin/gcc/gcc/c-opts.c6
-rw-r--r--gnu/usr.bin/gcc/gcc/cp/Make-lang.in4
-rw-r--r--gnu/usr.bin/gcc/gcc/cp/call.c4
-rw-r--r--gnu/usr.bin/gcc/gcc/cp/typeck.c3
-rw-r--r--gnu/usr.bin/gcc/gcc/fold-const.c14
-rw-r--r--gnu/usr.bin/gcc/gcc/tree.h4
13 files changed, 654 insertions, 40 deletions
diff --git a/gnu/usr.bin/gcc/gcc/Makefile.in b/gnu/usr.bin/gcc/gcc/Makefile.in
index e1f277be3b3..dbb8ecbf64b 100644
--- a/gnu/usr.bin/gcc/gcc/Makefile.in
+++ b/gnu/usr.bin/gcc/gcc/Makefile.in
@@ -739,8 +739,8 @@ CXX_TARGET_OBJS=@cxx_target_objs@
# Language-specific object files for C and Objective C.
C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \
- c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \
- c-objc-common.o c-dump.o libcpp.a $(C_TARGET_OBJS)
+ c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-bounded.o \
+ c-semantics.o c-objc-common.o c-dump.o libcpp.a $(C_TARGET_OBJS)
# Language-specific object files for C.
C_OBJS = c-parse.o c-lang.o c-pretty-print.o $(C_AND_OBJC_OBJS)
@@ -1267,6 +1267,9 @@ attribs.o : attribs.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h \
c-format.o : c-format.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) langhooks.h \
$(C_COMMON_H) flags.h toplev.h intl.h diagnostic.h
+c-bounded.o : c-bounded.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) langhooks.h \
+ $(C_COMMON_H) flags.h toplev.h intl.h diagnostic.h
+
c-semantics.o : c-semantics.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) \
flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
$(EXPR_H) $(PREDICT_H)
diff --git a/gnu/usr.bin/gcc/gcc/builtin-attrs.def b/gnu/usr.bin/gcc/gcc/builtin-attrs.def
index 7bdbd628086..0fe47a4fd04 100644
--- a/gnu/usr.bin/gcc/gcc/builtin-attrs.def
+++ b/gnu/usr.bin/gcc/gcc/builtin-attrs.def
@@ -71,13 +71,18 @@ DEF_ATTR_FOR_INT (4)
CONCAT2 (ATTR_,VALUE1), CONCAT2 (ATTR_LIST_,VALUE2))
DEF_LIST_INT_INT (1,0)
DEF_LIST_INT_INT (1,2)
+DEF_LIST_INT_INT (1,3)
DEF_LIST_INT_INT (2,0)
DEF_LIST_INT_INT (2,3)
DEF_LIST_INT_INT (3,0)
+DEF_LIST_INT_INT (3,2)
DEF_LIST_INT_INT (3,4)
+DEF_LIST_INT_INT (1,3_2)
#undef DEF_LIST_INT_INT
/* Construct tress for identifiers. */
+DEF_ATTR_IDENT (ATTR_BOUNDED, "bounded")
+DEF_ATTR_IDENT (ATTR_BUFFER, "buffer")
DEF_ATTR_IDENT (ATTR_CONST, "const")
DEF_ATTR_IDENT (ATTR_FORMAT, "format")
DEF_ATTR_IDENT (ATTR_FORMAT_ARG, "format_arg")
@@ -88,7 +93,9 @@ DEF_ATTR_IDENT (ATTR_NOTHROW, "nothrow")
DEF_ATTR_IDENT (ATTR_PRINTF, "printf")
DEF_ATTR_IDENT (ATTR_PURE, "pure")
DEF_ATTR_IDENT (ATTR_SCANF, "scanf")
+DEF_ATTR_IDENT (ATTR_SIZE, "size")
DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
+DEF_ATTR_IDENT (ATTR_STRING, "string")
DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_LIST, ATTR_NOTHROW, ATTR_NULL, ATTR_NULL)
@@ -137,6 +144,45 @@ DEF_FORMAT_ARG_ATTRIBUTE(1)
DEF_FORMAT_ARG_ATTRIBUTE(2)
#undef DEF_FORMAT_ARG_ATTRIBUTE
+/* Construct a tree for a bounded attribute. */
+
+/* Generate a fragment for future use in a bounded attr, e.g. ATTR_BUFFER_2_3 */
+#define DEF_ATTR_BOUNDED_FRAG(TYPE, VALUES) \
+ DEF_ATTR_TREE_LIST (CONCAT4 (ATTR_,TYPE,_,VALUES), ATTR_NULL, \
+ CONCAT2 (ATTR_,TYPE), CONCAT2 (ATTR_LIST_,VALUES))
+/* Create bounded attribute chained to nothrow, e.g. of the
+ form ATTR_NOTHROW_BOUNDED_BUFFER_2_3 */
+#define DEF_NOTHROW_BOUNDED_ATTRIBUTE(TYPE, VALUES) \
+ DEF_ATTR_TREE_LIST (CONCAT4 (ATTR_NOTHROW_BOUNDED_,TYPE,_,VALUES), ATTR_BOUNDED, \
+ CONCAT4 (ATTR_,TYPE,_,VALUES), ATTR_NOTHROW_LIST)
+/* Chain multiple nothrow bounded buffer attributes together */
+#define DEF_MULTIPLE_NOTHROW_BOUNDED_BUFFER_ATTRIBUTE(VAL1,VAL2) \
+ DEF_ATTR_TREE_LIST (CONCAT4(ATTR_NOTHROW_BOUNDED_BUFFER_,VAL1,_,VAL2),ATTR_BOUNDED,\
+ CONCAT2(ATTR_BUFFER_,VAL1), \
+ CONCAT2(ATTR_NOTHROW_BOUNDED_BUFFER_,VAL2))
+/* Chain a bounded attribute to a format printf attribute */
+#define DEF_FORMAT_PRINTF_BOUNDED_ATTRIBUTE(TYPE, VALUES, PREPEND,PRINTVALS) \
+ DEF_ATTR_TREE_LIST (CONCAT4 (PREPEND,TYPE,_,VALUES), \
+ ATTR_BOUNDED, CONCAT4 (ATTR_,TYPE,_,VALUES), \
+ CONCAT2(ATTR_FORMAT_PRINTF_,PRINTVALS))
+DEF_ATTR_BOUNDED_FRAG(BUFFER,1_2)
+DEF_ATTR_BOUNDED_FRAG(BUFFER,1_3)
+DEF_ATTR_BOUNDED_FRAG(BUFFER,2_3)
+DEF_ATTR_BOUNDED_FRAG(SIZE,1_3_2)
+DEF_ATTR_BOUNDED_FRAG(STRING,1_2)
+DEF_NOTHROW_BOUNDED_ATTRIBUTE(BUFFER,1_2)
+DEF_NOTHROW_BOUNDED_ATTRIBUTE(BUFFER,1_3)
+DEF_NOTHROW_BOUNDED_ATTRIBUTE(BUFFER,2_3)
+DEF_NOTHROW_BOUNDED_ATTRIBUTE(SIZE,1_3_2)
+DEF_MULTIPLE_NOTHROW_BOUNDED_BUFFER_ATTRIBUTE(2_3,1_3)
+DEF_FORMAT_PRINTF_BOUNDED_ATTRIBUTE(STRING,1_2,ATTR_PRINTF_3_4_BOUNDED_,3_4)
+DEF_FORMAT_PRINTF_BOUNDED_ATTRIBUTE(STRING,1_2,ATTR_PRINTF_3_0_BOUNDED_,3_0)
+
+#undef DEF_ATTR_BOUNDED_FRAG
+#undef DEF_NOTHROW_BOUNDED_ATTRIBUTE
+#undef DEF_MULTIPLE_NOTHROW_BOUNDED_ATTRIBUTE
+#undef DEF_FORMAT_PRINTF_BOUNDED_ATTRIBUTE
+
/* Define an attribute for a function, along with the IDENTIFIER_NODE. */
#define DEF_FN_ATTR_IDENT(NAME, ATTRS, PREDICATE) \
DEF_ATTR_IDENT (CONCAT2(ATTR_,NAME), STRINGX(NAME)) \
diff --git a/gnu/usr.bin/gcc/gcc/builtins.def b/gnu/usr.bin/gcc/gcc/builtins.def
index c208b751629..3b76ce401ac 100644
--- a/gnu/usr.bin/gcc/gcc/builtins.def
+++ b/gnu/usr.bin/gcc/gcc/builtins.def
@@ -230,7 +230,7 @@ DEF_BUILTIN (BUILT_IN_BZERO,
BT_FN_VOID_PTR_SIZE,
BT_FN_VOID_VAR,
true, true, true,
- ATTR_NOTHROW_LIST)
+ ATTR_NOTHROW_BOUNDED_BUFFER_1_2)
DEF_BUILTIN (BUILT_IN_BCMP,
"__builtin_bcmp",
BUILT_IN_NORMAL,
@@ -255,7 +255,7 @@ DEF_EXT_LIB_BUILTIN(BUILT_IN_RINDEX,
DEF_LIB_BUILTIN(BUILT_IN_MEMCPY,
"__builtin_memcpy",
BT_FN_PTR_PTR_CONST_PTR_SIZE,
- ATTR_NOTHROW_LIST)
+ ATTR_NOTHROW_BOUNDED_BUFFER_2_3_1_3)
DEF_LIB_BUILTIN(BUILT_IN_MEMCMP,
"__builtin_memcmp",
BT_FN_INT_CONST_PTR_CONST_PTR_SIZE,
@@ -263,7 +263,7 @@ DEF_LIB_BUILTIN(BUILT_IN_MEMCMP,
DEF_LIB_BUILTIN(BUILT_IN_MEMSET,
"__builtin_memset",
BT_FN_PTR_PTR_INT_SIZE,
- ATTR_NOTHROW_LIST)
+ ATTR_NOTHROW_BOUNDED_BUFFER_1_3)
DEF_LIB_BUILTIN(BUILT_IN_STRCAT,
"__builtin_strcat",
@@ -272,7 +272,7 @@ DEF_LIB_BUILTIN(BUILT_IN_STRCAT,
DEF_LIB_BUILTIN(BUILT_IN_STRNCAT,
"__builtin_strncat",
BT_FN_STRING_STRING_CONST_STRING_SIZE,
- ATTR_NOTHROW_LIST)
+ ATTR_NOTHROW_BOUNDED_BUFFER_1_3)
DEF_LIB_BUILTIN(BUILT_IN_STRCPY,
"__builtin_strcpy",
BT_FN_STRING_STRING_CONST_STRING,
@@ -280,7 +280,7 @@ DEF_LIB_BUILTIN(BUILT_IN_STRCPY,
DEF_LIB_BUILTIN(BUILT_IN_STRNCPY,
"__builtin_strncpy",
BT_FN_STRING_STRING_CONST_STRING_SIZE,
- ATTR_NOTHROW_LIST)
+ ATTR_NOTHROW_BOUNDED_BUFFER_1_3)
DEF_LIB_BUILTIN(BUILT_IN_STRCMP,
"__builtin_strcmp",
BT_FN_INT_CONST_STRING_CONST_STRING,
@@ -542,7 +542,7 @@ DEF_LIB_BUILTIN(BUILT_IN_PUTS,
DEF_C99_BUILTIN(BUILT_IN_SNPRINTF,
"__builtin_snprintf",
BT_FN_INT_STRING_SIZE_CONST_STRING_VAR,
- ATTR_FORMAT_PRINTF_3_4)
+ ATTR_PRINTF_3_4_BOUNDED_STRING_1_2)
DEF_LIB_BUILTIN(BUILT_IN_SPRINTF,
"__builtin_sprintf",
BT_FN_INT_STRING_CONST_STRING_VAR,
@@ -570,7 +570,7 @@ DEF_C99_BUILTIN(BUILT_IN_VSSCANF,
DEF_C99_BUILTIN(BUILT_IN_VSNPRINTF,
"__builtin_vsnprintf",
BT_FN_INT_STRING_SIZE_CONST_STRING_VALIST_ARG,
- ATTR_FORMAT_PRINTF_3_0)
+ ATTR_PRINTF_3_0_BOUNDED_STRING_1_2)
DEF_LIB_BUILTIN(BUILT_IN_VSPRINTF,
"__builtin_vsprintf",
BT_FN_INT_STRING_CONST_STRING_VALIST_ARG,
@@ -597,7 +597,7 @@ DEF_BUILTIN (BUILT_IN_FPUTS,
DEF_FALLBACK_BUILTIN(BUILT_IN_FWRITE,
"__builtin_fwrite",
BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR,
- ATTR_NOTHROW_LIST)
+ ATTR_NOTHROW_BOUNDED_SIZE_1_3_2)
DEF_FRONT_END_LIB_BUILTIN(BUILT_IN_FPRINTF,
"__builtin_fprintf",
BT_FN_INT_PTR_CONST_STRING_VAR,
diff --git a/gnu/usr.bin/gcc/gcc/c-bounded.c b/gnu/usr.bin/gcc/gcc/c-bounded.c
new file mode 100644
index 00000000000..81d12e54ff3
--- /dev/null
+++ b/gnu/usr.bin/gcc/gcc/c-bounded.c
@@ -0,0 +1,490 @@
+/* Bounds checker for library functions with buffers and sizes.
+ *
+ * Copyright (c) 2004 Anil Madhavapeddy <anil@recoil.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "c-tree.h"
+#include "flags.h"
+#include "toplev.h"
+#include "c-common.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+
+/* Handle attributes associated with bounds checking. */
+
+/* Bounded attribute types */
+enum bounded_type { buffer_bound_type, string_bound_type,
+ minbytes_bound_type, size_bound_type,
+ bounded_type_error };
+
+typedef struct bound_check_info
+{
+ enum bounded_type bounded_type; /* type of bound (string, minsize, etc) */
+ unsigned HOST_WIDE_INT bounded_buf; /* number of buffer pointer arg */
+ unsigned HOST_WIDE_INT bounded_num; /* number of buffer length arg || min size */
+ unsigned HOST_WIDE_INT bounded_size; /* number of buffer element size arg */
+} function_bounded_info;
+
+tree handle_bounded_attribute(tree *, tree, tree, int, bool *);
+void check_function_bounded (int *, tree, tree);
+
+static bool decode_bounded_attr PARAMS ((tree, function_bounded_info *, int));
+static enum bounded_type decode_bounded_type PARAMS ((const char *));
+
+/* Handle a "bounded" attribute; arguments as in
+ struct attribute_spec.handler. */
+tree
+handle_bounded_attribute (node, name, args, flags, no_add_attrs)
+ tree *node;
+ tree name ATTRIBUTE_UNUSED;
+ tree args;
+ int flags ATTRIBUTE_UNUSED;
+ bool *no_add_attrs;
+{
+ tree type = *node;
+ function_bounded_info info;
+ tree argument, arg_iterate;
+ unsigned HOST_WIDE_INT arg_num;
+
+ if (!decode_bounded_attr (args, &info, 0))
+ {
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ /* `min_size' directly specifies the minimum buffer length */
+ if (info.bounded_type == minbytes_bound_type
+ && info.bounded_num <= 0)
+ {
+ error ("`minbytes' bound size must be a positive integer value");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ argument = TYPE_ARG_TYPES (type);
+ if (argument)
+ {
+ arg_iterate = argument;
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (arg_iterate == 0 || arg_num == info.bounded_buf)
+ break;
+ arg_iterate = TREE_CHAIN (arg_iterate);
+ }
+ if (! arg_iterate
+ || (TREE_CODE (TREE_VALUE (arg_iterate)) != POINTER_TYPE
+ && TREE_CODE (TREE_VALUE (arg_iterate)) != ARRAY_TYPE))
+ {
+ error ("bound buffer argument not an array or pointer type");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+
+ if (info.bounded_type == size_bound_type
+ || info.bounded_type == string_bound_type
+ || info.bounded_type == buffer_bound_type)
+ {
+ arg_iterate = argument;
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (arg_iterate == 0 || arg_num == info.bounded_num)
+ break;
+ arg_iterate = TREE_CHAIN (arg_iterate);
+ }
+ if (! arg_iterate
+ || TREE_CODE (TREE_VALUE (arg_iterate)) != INTEGER_TYPE)
+ {
+ error ("bound length argument not an integer type");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+ if (info.bounded_type == size_bound_type)
+ {
+ arg_iterate = argument;
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (arg_iterate == 0 || arg_num == info.bounded_size)
+ break;
+ arg_iterate = TREE_CHAIN (arg_iterate);
+ }
+ if (! arg_iterate
+ || TREE_CODE (TREE_VALUE (arg_iterate)) != INTEGER_TYPE)
+ {
+ error ("bound element size argument not an integer type");
+ *no_add_attrs = true;
+ return NULL_TREE;
+ }
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Decode the arguments to a "bounded" attribute into a function_bounded_info
+ structure. It is already known that the list is of the right length.
+ If VALIDATED_P is true, then these attributes have already been validated
+ and this function will abort if they are erroneous; if false, it
+ will give an error message. Returns true if the attributes are
+ successfully decoded, false otherwise. */
+
+static bool
+decode_bounded_attr (args, info, validated_p)
+ tree args;
+ function_bounded_info *info;
+ int validated_p;
+{
+ int bounded_num;
+ tree bounded_type_id = TREE_VALUE (args);
+ tree bounded_buf_expr = TREE_VALUE (TREE_CHAIN (args));
+ tree bounded_num_expr = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+ tree bounded_size_expr = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (args)));
+
+ if (TREE_CODE (bounded_type_id) != IDENTIFIER_NODE)
+ {
+ if (validated_p)
+ abort ();
+ error ("unrecognized bounded type specifier");
+ return false;
+ }
+ else
+ {
+ const char *p = IDENTIFIER_POINTER (bounded_type_id);
+
+ info->bounded_type = decode_bounded_type (p);
+
+ if (info->bounded_type == bounded_type_error)
+ {
+ if (validated_p)
+ abort ();
+ warning ("`%s' is an unrecognized bounded function type", p);
+ return false;
+ }
+ }
+
+ /* Extract the third argument if its appropriate */
+ switch (info->bounded_type)
+ {
+ case bounded_type_error:
+ /* should never happen */
+ internal_error ("unexpected bounded_type_error in decode_bounded_attr");
+ break;
+ case string_bound_type:
+ if (bounded_size_expr)
+ warning ("`string' bound type only takes 2 parameters");
+ bounded_size_expr = size_int (0);
+ break;
+ case buffer_bound_type:
+ if (bounded_size_expr)
+ warning ("`buffer' bound type only takes 2 parameters");
+ bounded_size_expr = size_int (0);
+ break;
+ case minbytes_bound_type:
+ if (bounded_size_expr)
+ warning("`minbytes' bound type only takes 2 parameters");
+ bounded_size_expr = size_int (0);
+ break;
+ case size_bound_type:
+ if (bounded_size_expr)
+ bounded_size_expr = TREE_VALUE (bounded_size_expr);
+ else
+ {
+ error ("parameter 3 not specified for `size' bounded function");
+ return false;
+ }
+ break;
+ }
+
+ /* Strip any conversions from the buffer parameters and verify they
+ are constants */
+ while (TREE_CODE (bounded_num_expr) == NOP_EXPR
+ || TREE_CODE (bounded_num_expr) == CONVERT_EXPR
+ || TREE_CODE (bounded_num_expr) == NON_LVALUE_EXPR)
+ bounded_num_expr = TREE_OPERAND (bounded_num_expr, 0);
+
+ while (TREE_CODE (bounded_buf_expr) == NOP_EXPR
+ || TREE_CODE (bounded_buf_expr) == CONVERT_EXPR
+ || TREE_CODE (bounded_buf_expr) == NON_LVALUE_EXPR)
+ bounded_buf_expr = TREE_OPERAND (bounded_buf_expr, 0);
+
+ while (TREE_CODE (bounded_size_expr) == NOP_EXPR
+ || TREE_CODE (bounded_size_expr) == CONVERT_EXPR
+ || TREE_CODE (bounded_size_expr) == NON_LVALUE_EXPR)
+ bounded_size_expr = TREE_OPERAND (bounded_size_expr, 0);
+
+ if (TREE_CODE (bounded_num_expr) != INTEGER_CST)
+ {
+ if (validated_p)
+ abort ();
+ error ("bound length operand number is not an integer constant");
+ return false;
+ }
+
+ if (TREE_CODE (bounded_buf_expr) != INTEGER_CST)
+ {
+ if (validated_p)
+ abort ();
+ error ("bound buffer operand number is not an integer constant");
+ return false;
+ }
+
+ if (TREE_CODE (bounded_size_expr) != INTEGER_CST)
+ {
+ if (validated_p)
+ abort ();
+ error ("bound element size operand number is not an integer constant");
+ return false;
+ }
+
+ info->bounded_buf = TREE_INT_CST_LOW (bounded_buf_expr);
+ info->bounded_size = TREE_INT_CST_LOW (bounded_size_expr);
+ bounded_num = TREE_INT_CST_LOW (bounded_num_expr);
+
+ /* `minbytes' directly specifies the minimum buffer length */
+ if (info->bounded_type == minbytes_bound_type
+ && bounded_num <= 0)
+ {
+ if (validated_p)
+ abort ();
+ error ("`minbytes' bound size must be a positive integer value");
+ return false;
+ }
+
+ info->bounded_num = (unsigned HOST_WIDE_INT) bounded_num;
+ return true;
+}
+
+static void check_bounded_info PARAMS ((int *, function_bounded_info *, tree));
+
+/* Decode a bounded type from a string, returning the type, or
+ bounded_type_error if not valid, in which case the caller should print an
+ error message. */
+static enum bounded_type
+decode_bounded_type (s)
+ const char *s;
+{
+ if (!strcmp (s, "string") || !strcmp (s, "__string__"))
+ return string_bound_type;
+ else if (!strcmp (s, "buffer") || !strcmp (s, "__buffer__"))
+ return buffer_bound_type;
+ else if (!strcmp (s, "minbytes") || !strcmp (s, "__minbytes__"))
+ return minbytes_bound_type;
+ else if (!strcmp (s, "size") || !strcmp (s, "__size__"))
+ return size_bound_type;
+ else
+ return bounded_type_error;
+}
+
+/* Check the argument list of a call to memcpy, bzero, etc.
+ ATTRS are the attributes on the function type.
+ PARAMS is the list of argument values. */
+
+void
+check_function_bounded (status, attrs, params)
+ int *status;
+ tree attrs;
+ tree params;
+{
+ tree a;
+ /* See if this function has any bounded attributes. */
+ for (a = attrs; a; a = TREE_CHAIN (a))
+ {
+ if (is_attribute_p ("bounded", TREE_PURPOSE (a)))
+ {
+ /* Yup; check it. */
+ function_bounded_info info;
+ decode_bounded_attr (TREE_VALUE (a), &info, 1);
+ check_bounded_info (status, &info, params);
+ }
+ }
+}
+
+/* This function replaces `warning' inside the bounds checking
+ functions. If the `status' parameter is non-NULL, then it is
+ dereferenced and set to 1 whenever a warning is caught. Otherwise
+ it warns as usual by replicating the innards of the warning
+ function from diagnostic.c. */
+static void
+status_warning VPARAMS ((int *status, const char *msgid, ...))
+{
+ diagnostic_info diagnostic ;
+
+ VA_OPEN (ap, msgid);
+ VA_FIXEDARG (ap, int *, status);
+ VA_FIXEDARG (ap, const char *, msgid);
+
+ if (status)
+ *status = 1;
+ else
+ {
+ /* This duplicates the warning function behavior. */
+ diagnostic_set_info (&diagnostic, _(msgid), &ap, input_filename, lineno,
+ DK_WARNING);
+ report_diagnostic (&diagnostic);
+ }
+
+ VA_CLOSE (ap);
+}
+
+/* Check the argument list of a call to memcpy, bzero, etc.
+ INFO points to the function_bounded_info structure.
+ PARAMS is the list of argument values. */
+
+static void
+check_bounded_info (status, info, params)
+ int *status;
+ function_bounded_info *info;
+ tree params;
+{
+ tree buf_expr, length_expr, size_expr;
+ unsigned HOST_WIDE_INT arg_num;
+
+ /* Extract the buffer expression from the arguments */
+ buf_expr = params;
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (buf_expr == 0)
+ return;
+ if (arg_num == info->bounded_buf)
+ break;
+ buf_expr = TREE_CHAIN (buf_expr);
+ }
+ buf_expr = TREE_VALUE (buf_expr);
+
+ /* Get the buffer length, either directly from the function attribute
+ info, or from the parameter pointed to */
+ if (info->bounded_type == minbytes_bound_type)
+ length_expr = size_int (info->bounded_num);
+ else
+ {
+ /* Extract the buffer length expression from the arguments */
+ length_expr = params;
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (length_expr == 0)
+ return;
+ if (arg_num == info->bounded_num)
+ break;
+ length_expr = TREE_CHAIN (length_expr);
+ }
+ length_expr = TREE_VALUE (length_expr);
+ }
+
+ /* If the bound type is `size', resolve the third parameter */
+ if (info->bounded_type == size_bound_type)
+ {
+ size_expr = params;
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (size_expr == 0)
+ return;
+ if (arg_num == info->bounded_size)
+ break;
+ size_expr = TREE_CHAIN (size_expr);
+ }
+ size_expr = TREE_VALUE (size_expr);
+ }
+ else
+ size_expr = size_int (0);
+
+ STRIP_NOPS (buf_expr);
+
+ /* Check for a possible sizeof(pointer) error in string functions */
+ if (info->bounded_type == string_bound_type
+ && SIZEOF_PTR_DERIVED (length_expr))
+ status_warning(status, "sizeof(pointer) possibly incorrect in argument %d",
+ info->bounded_num);
+
+ /* We only need to check if the buffer expression is a static
+ * array (which is inside an ADDR_EXPR) */
+ if (TREE_CODE (buf_expr) != ADDR_EXPR)
+ return;
+ buf_expr = TREE_OPERAND (buf_expr, 0);
+
+ if (TREE_CODE (TREE_TYPE (buf_expr)) == ARRAY_TYPE
+ && TYPE_DOMAIN (TREE_TYPE (buf_expr)))
+ {
+ int array_size, length, elem_size, type_size;
+ tree array_size_expr = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (buf_expr)));
+ tree array_type = TREE_TYPE (TREE_TYPE (buf_expr));
+ tree array_type_size_expr = TYPE_SIZE (array_type);
+
+ /* Can't deal with variable-sized arrays yet */
+ if (TREE_CODE (array_type_size_expr) != INTEGER_CST)
+ return;
+
+ /* Get the size of the type of the array and sanity check it */
+ type_size = TREE_INT_CST_LOW (array_type_size_expr);
+ if ((type_size % 8) != 0)
+ {
+ error ("found non-byte aligned type while checking bounds");
+ return;
+ }
+ type_size /= 8;
+
+ /* Both the size of the static buffer and the length should be
+ * integer constants by now */
+ if (TREE_CODE (array_size_expr) != INTEGER_CST
+ || TREE_CODE (length_expr) != INTEGER_CST
+ || TREE_CODE (size_expr) != INTEGER_CST)
+ return;
+
+ /* array_size_expr contains maximum array index, so add one for size */
+ array_size = (TREE_INT_CST_LOW (array_size_expr) + 1) * type_size;
+ length = TREE_INT_CST_LOW (length_expr);
+
+ /* XXX - warn about a too-small buffer? */
+ if (array_size < 1)
+ return;
+
+ switch (info->bounded_type)
+ {
+ case bounded_type_error:
+ /* should never happen */
+ internal_error ("unexpected bounded_type_error");
+ break;
+ case string_bound_type:
+ case buffer_bound_type:
+ /* warn about illegal bounds value */
+ if (length < 0)
+ status_warning (status, "non-positive bounds length (%d) detected", length);
+ /* check if the static buffer is smaller than bound length */
+ if (array_size < length)
+ status_warning(status, "array size (%d) smaller than bound length (%d)",
+ array_size, length);
+ break;
+ case minbytes_bound_type:
+ /* check if array is smaller than the minimum allowed */
+ if (array_size < length)
+ status_warning (status, "array size (%d) is smaller than minimum required (%d)",
+ array_size, length);
+ break;
+ case size_bound_type:
+ elem_size = TREE_INT_CST_LOW (size_expr);
+ /* warn about illegal bounds value */
+ if (length < 1)
+ status_warning (status, "non-positive bounds length (%d) detected", length);
+ /* check if the static buffer is smaller than bound length */
+ if (array_size < (length * elem_size))
+ status_warning(status, "array size (%d) smaller than required length (%d * %d)",
+ array_size, length, elem_size);
+ break;
+ }
+ }
+}
diff --git a/gnu/usr.bin/gcc/gcc/c-common.c b/gnu/usr.bin/gcc/gcc/c-common.c
index 7edd965cb97..941b52c2bae 100644
--- a/gnu/usr.bin/gcc/gcc/c-common.c
+++ b/gnu/usr.bin/gcc/gcc/c-common.c
@@ -39,7 +39,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "langhooks.h"
#include "except.h" /* For USING_SJLJ_EXCEPTIONS. */
#include "tree-inline.h"
-#include "c-tree.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -333,6 +332,9 @@ int warn_format_nonliteral;
int warn_format_security;
+/* Warn about buffer size mismatches. */
+
+int warn_bounded;
/* C/ObjC language option variables. */
@@ -765,8 +767,6 @@ static tree handle_deprecated_attribute PARAMS ((tree *, tree, tree, int,
bool *));
static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
bool *));
-static tree handle_bounded_attribute PARAMS ((tree *, tree, tree, int,
- bool *));
static tree handle_nonnull_attribute PARAMS ((tree *, tree, tree, int,
bool *));
static tree handle_sentinel_attribute PARAMS ((tree *, tree, tree, int,
@@ -3060,6 +3060,7 @@ c_sizeof_or_alignof_type (type, op, complain)
const char *op_name;
tree value = NULL;
enum tree_code type_code = TREE_CODE (type);
+ bool sizeof_ptr_flag = false;
my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
op_name = op == SIZEOF_EXPR ? "sizeof" : "__alignof__";
@@ -3091,10 +3092,15 @@ c_sizeof_or_alignof_type (type, op, complain)
else
{
if (op == SIZEOF_EXPR)
- /* Convert in case a char is more than one unit. */
- value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
- size_int (TYPE_PRECISION (char_type_node)
- / BITS_PER_UNIT));
+ {
+ /* Convert in case a char is more than one unit. */
+ value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
+ size_int (TYPE_PRECISION (char_type_node)
+ / BITS_PER_UNIT));
+
+ if (type_code == POINTER_TYPE)
+ sizeof_ptr_flag = true;
+ }
else
value = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
}
@@ -3105,7 +3111,10 @@ c_sizeof_or_alignof_type (type, op, complain)
`size_t', which is just a typedef for an ordinary integer type. */
value = fold (build1 (NOP_EXPR, size_type_node, value));
my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)), 20001021);
-
+
+ if (sizeof_ptr_flag)
+ SIZEOF_PTR_DERIVED (value) = 1;
+
return value;
}
@@ -6389,22 +6398,6 @@ vector_size_helper (type, bottom)
return outer;
}
-/* Handle a "bounded" attribute; arguments as in
- struct attribute_spec.handler.
- Just a stub for now. */
-
-static tree
-handle_bounded_attribute (node, name, args, flags, no_add_attrs)
- tree *node ATTRIBUTE_UNUSED;
- tree name ATTRIBUTE_UNUSED;
- tree args ATTRIBUTE_UNUSED;
- int flags ATTRIBUTE_UNUSED;
- bool *no_add_attrs;
-{
- *no_add_attrs = true;
- return NULL_TREE;
-}
-
/* Handle a "sentinel" attribute.
Just a stub for now. */
@@ -6633,6 +6626,9 @@ check_function_arguments (attrs, params)
if (warn_format)
check_function_format (NULL, attrs, params);
+
+ if (warn_bounded)
+ check_function_bounded (NULL, attrs, params);
}
/* Generic argument checking recursion routine. PARAM is the argument to
diff --git a/gnu/usr.bin/gcc/gcc/c-common.h b/gnu/usr.bin/gcc/gcc/c-common.h
index 1f59ebd7d82..515d99a2cca 100644
--- a/gnu/usr.bin/gcc/gcc/c-common.h
+++ b/gnu/usr.bin/gcc/gcc/c-common.h
@@ -501,6 +501,9 @@ extern int warn_format_nonliteral;
extern int warn_format_security;
+/* Warn about buffer size mismatches. */
+
+extern int warn_bounded;
/* C/ObjC language option variables. */
@@ -866,7 +869,10 @@ extern void check_function_arguments_recurse PARAMS ((void (*) (void *,
void *, tree,
unsigned HOST_WIDE_INT));
extern void check_function_format PARAMS ((int *, tree, tree));
+extern void check_function_bounded PARAMS ((int *, tree, tree));
extern void set_Wformat PARAMS ((int));
+extern tree handle_bounded_attribute PARAMS ((tree *, tree, tree,
+ int, bool *));
extern tree handle_format_attribute PARAMS ((tree *, tree, tree,
int, bool *));
extern tree handle_format_arg_attribute PARAMS ((tree *, tree, tree,
diff --git a/gnu/usr.bin/gcc/gcc/c-format.c b/gnu/usr.bin/gcc/gcc/c-format.c
index ad254ea61f9..d778849835a 100644
--- a/gnu/usr.bin/gcc/gcc/c-format.c
+++ b/gnu/usr.bin/gcc/gcc/c-format.c
@@ -540,6 +540,10 @@ typedef struct format_wanted_type
/* Whether the argument, dereferenced once, is written into and so the
argument must not be a pointer to a const-qualified type. */
int writing_in_flag;
+ /* If the argument is to be written into and is an array, should the
+ width specifier be equal to the size of the array, or one less
+ (to accommodate a NULL being placed at the end) */
+ int size_equals_width;
/* Whether the argument, dereferenced once, is read from and so
must not be a NULL pointer. */
int reading_from_flag;
@@ -552,6 +556,8 @@ typedef struct format_wanted_type
const char *name;
/* The actual parameter to check against the wanted type. */
tree param;
+ /* Field width of type */
+ int field_width;
/* The argument number of that parameter. */
int arg_num;
/* The next type to check for this format conversion, or NULL if none. */
@@ -1634,6 +1640,7 @@ check_format_info_main (status, res, info, format_chars, format_length,
const format_length_info *fli = NULL;
const format_char_info *fci = NULL;
char flag_chars[256];
+ int field_width = 0;
int aflag = 0;
if (*format_chars == 0)
{
@@ -1775,20 +1782,29 @@ check_format_info_main (status, res, info, format_chars, format_length,
/* Possibly read a numeric width. If the width is zero,
we complain if appropriate. */
int non_zero_width_char = FALSE;
- int found_width = FALSE;
+ unsigned int found_width = 0;
+ char format_num_str[32];
+
+ format_num_str[0] = '\0';
while (ISDIGIT (*format_chars))
{
- found_width = TRUE;
+ if (found_width < (sizeof(format_num_str)-2))
+ {
+ format_num_str[found_width++] = *format_chars;
+ format_num_str[found_width] = '\0';
+ }
if (*format_chars != '0')
non_zero_width_char = TRUE;
++format_chars;
}
- if (found_width && !non_zero_width_char &&
+
+ if (found_width > 0 && !non_zero_width_char &&
(fki->flags & (int) FMT_FLAG_ZERO_WIDTH_BAD))
status_warning (status, "zero width in %s format",
fki->name);
- if (found_width)
+ if (found_width > 0)
{
+ field_width = atoi(format_num_str);
i = strlen (flag_chars);
flag_chars[i++] = fki->width_char;
flag_chars[i] = 0;
@@ -2186,10 +2202,15 @@ check_format_info_main (status, res, info, format_chars, format_length,
main_wanted_type.wanted_type_name = wanted_type_name;
main_wanted_type.pointer_count = fci->pointer_count + aflag;
main_wanted_type.char_lenient_flag = 0;
+ main_wanted_type.field_width = field_width;
if (strchr (fci->flags2, 'c') != 0)
main_wanted_type.char_lenient_flag = 1;
main_wanted_type.writing_in_flag = 0;
main_wanted_type.reading_from_flag = 0;
+ if (strchr (fci->format_chars, 'c') != 0)
+ main_wanted_type.size_equals_width = 1;
+ else
+ main_wanted_type.size_equals_width = 0;
if (aflag)
main_wanted_type.writing_in_flag = 1;
else
@@ -2285,6 +2306,27 @@ check_format_types (status, types)
else
cur_param = 0;
+ /* Test static string bounds for sscan if -Wbounded is on as well */
+ if (warn_bounded
+ && types->writing_in_flag
+ && i == 0
+ && cur_param != 0
+ && COMPLETE_TYPE_P (TREE_TYPE (cur_param))
+ && TREE_CODE (TREE_TYPE (cur_param)) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (cur_param))) == INTEGER_TYPE)
+ {
+ tree array_domain = TYPE_DOMAIN (TREE_TYPE (cur_param));
+ tree array_size_expr = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (cur_param)));
+ int f = types->size_equals_width ? 0 : 1;
+ if (array_size_expr != 0 && types->field_width > 0)
+ {
+ int array_size = TREE_INT_CST_LOW (array_size_expr) + 1;
+ if (array_size < (types->field_width + f))
+ warning ("Array size (%d) smaller than format string size (%d)",
+ array_size, types->field_width + f);
+ }
+ }
+
/* See if this is an attempt to write into a const type with
scanf or with printf "%n". Note: the writing in happens
at the first indirection only, if for example
diff --git a/gnu/usr.bin/gcc/gcc/c-opts.c b/gnu/usr.bin/gcc/gcc/c-opts.c
index 77a468ab184..193b6f16f1b 100644
--- a/gnu/usr.bin/gcc/gcc/c-opts.c
+++ b/gnu/usr.bin/gcc/gcc/c-opts.c
@@ -127,6 +127,7 @@ static void sanitize_cpp_opts PARAMS ((void));
OPT("Wabi", CL_CXX, OPT_Wabi) \
OPT("Wall", CL_ALL, OPT_Wall) \
OPT("Wbad-function-cast", CL_C, OPT_Wbad_function_cast) \
+ OPT("Wbounded", CL_ALL, OPT_Wbounded) \
OPT("Wcast-qual", CL_ALL, OPT_Wcast_qual) \
OPT("Wchar-subscripts", CL_ALL, OPT_Wchar_subscripts) \
OPT("Wcomment", CL_ALL, OPT_Wcomment) \
@@ -694,6 +695,7 @@ c_common_decode_option (argc, argv)
set_Wunused (on);
set_Wformat (on);
set_Wimplicit (on);
+ warn_bounded = on;
warn_char_subscripts = on;
warn_missing_braces = on;
warn_parentheses = on;
@@ -789,6 +791,10 @@ c_common_decode_option (argc, argv)
warn_float_equal = on;
break;
+ case OPT_Wbounded:
+ warn_bounded = on;
+ break;
+
case OPT_Wformat:
set_Wformat (on);
break;
diff --git a/gnu/usr.bin/gcc/gcc/cp/Make-lang.in b/gnu/usr.bin/gcc/gcc/cp/Make-lang.in
index d683d45d9b6..59d6ea39b9a 100644
--- a/gnu/usr.bin/gcc/gcc/cp/Make-lang.in
+++ b/gnu/usr.bin/gcc/gcc/cp/Make-lang.in
@@ -78,8 +78,8 @@ g++-cross$(exeext): g++$(exeext)
# The compiler itself.
# Shared with C front end:
-CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \
- c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o
+CXX_C_OBJS = attribs.o c-common.o c-format.o c-bounded.o c-pragma.o c-semantics.o \
+ c-lex.o c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o
# Language-specific object files.
CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
diff --git a/gnu/usr.bin/gcc/gcc/cp/call.c b/gnu/usr.bin/gcc/gcc/cp/call.c
index 1a1a493774b..60e79dfc050 100644
--- a/gnu/usr.bin/gcc/gcc/cp/call.c
+++ b/gnu/usr.bin/gcc/gcc/cp/call.c
@@ -4592,6 +4592,10 @@ build_over_call (cand, args, flags)
check_function_format (NULL, TYPE_ATTRIBUTES (TREE_TYPE (fn)),
converted_args);
+ if (warn_bounded)
+ check_function_bounded (NULL, TYPE_ATTRIBUTES (TREE_TYPE (fn)),
+ converted_args);
+
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
diff --git a/gnu/usr.bin/gcc/gcc/cp/typeck.c b/gnu/usr.bin/gcc/gcc/cp/typeck.c
index 4b36cc2ceaa..96f914c7541 100644
--- a/gnu/usr.bin/gcc/gcc/cp/typeck.c
+++ b/gnu/usr.bin/gcc/gcc/cp/typeck.c
@@ -2739,6 +2739,9 @@ build_function_call_real (function, params, flags)
if (warn_format)
check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
+ if (warn_bounded)
+ check_function_bounded (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
+
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
to do something useful. */
diff --git a/gnu/usr.bin/gcc/gcc/fold-const.c b/gnu/usr.bin/gcc/gcc/fold-const.c
index 94682d477ee..22db9633043 100644
--- a/gnu/usr.bin/gcc/gcc/fold-const.c
+++ b/gnu/usr.bin/gcc/gcc/fold-const.c
@@ -1036,6 +1036,10 @@ int_const_binop (code, arg1, arg2, notrunc)
= (TREE_CODE (type) == INTEGER_TYPE && TYPE_IS_SIZETYPE (type));
int overflow = 0;
int no_overflow = 0;
+ int sizeof_flag = 0;
+
+ if (SIZEOF_PTR_DERIVED (arg1) == 1 || SIZEOF_PTR_DERIVED (arg2) == 1)
+ sizeof_flag = 1;
int1l = TREE_INT_CST_LOW (arg1);
int1h = TREE_INT_CST_HIGH (arg1);
@@ -1203,6 +1207,10 @@ int_const_binop (code, arg1, arg2, notrunc)
TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
| TREE_CONSTANT_OVERFLOW (arg1)
| TREE_CONSTANT_OVERFLOW (arg2));
+
+ if (sizeof_flag == 1)
+ SIZEOF_PTR_DERIVED (t) = 1;
+
return t;
}
@@ -5039,6 +5047,9 @@ fold (expr)
| force_fit_type (t, overflow && !TREE_UNSIGNED (type)));
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
+ /* If arg0 was calculated from sizeof(ptr), record this */
+ if (SIZEOF_PTR_DERIVED (arg0))
+ SIZEOF_PTR_DERIVED (t) = 1;
}
else if (TREE_CODE (arg0) == REAL_CST)
t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
@@ -5082,6 +5093,9 @@ fold (expr)
| force_fit_type (t, overflow));
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
+ /* If arg0 was calculated from sizeof(ptr), record this */
+ if (SIZEOF_PTR_DERIVED (arg0))
+ SIZEOF_PTR_DERIVED (t) = 1;
}
}
else if (TREE_CODE (arg0) == REAL_CST)
diff --git a/gnu/usr.bin/gcc/gcc/tree.h b/gnu/usr.bin/gcc/gcc/tree.h
index facaa9d0277..aa422537a56 100644
--- a/gnu/usr.bin/gcc/gcc/tree.h
+++ b/gnu/usr.bin/gcc/gcc/tree.h
@@ -698,6 +698,10 @@ extern void tree_vec_elt_check_failed PARAMS ((int, int, const char *,
#define TREE_LANG_FLAG_4(NODE) ((NODE)->common.lang_flag_4)
#define TREE_LANG_FLAG_5(NODE) ((NODE)->common.lang_flag_5)
#define TREE_LANG_FLAG_6(NODE) ((NODE)->common.lang_flag_6)
+
+/* Used to track constants derived from sizeof(pointer) operations */
+#define SIZEOF_PTR_DERIVED(NODE) (TREE_LANG_FLAG_6((NODE)))
+
/* Define additional fields and accessors for nodes representing constants. */