mirror of
https://gcc.gnu.org/git/gcc.git
synced 2026-02-22 20:01:22 -05:00
Implement a solution for PR middle-end/10138 and PR middle-end/95136.
PR middle-end/10138 - warn for uninitialized arrays passed as const arguments PR middle-end/95136 - missing -Wuninitialized on an array access with a variable offset gcc/c-family/ChangeLog: PR middle-end/10138 PR middle-end/95136 * c-attribs.c (append_access_attrs): Handle attr_access::none. (handle_access_attribute): Same. gcc/ChangeLog: PR middle-end/10138 PR middle-end/95136 * attribs.c (init_attr_rdwr_indices): Move function here. * attribs.h (rdwr_access_hash, rdwr_map): Define. (attr_access): Add 'none'. (init_attr_rdwr_indices): Declared function. * builtins.c (warn_for_access)): New function. (check_access): Call it. * builtins.h (checK-access): Add an optional argument. * calls.c (rdwr_access_hash, rdwr_map): Move to attribs.h. (init_attr_rdwr_indices): Declare extern. (append_attrname): Handle attr_access::none. (maybe_warn_rdwr_sizes): Same. (initialize_argument_information): Update comments. * doc/extend.texi (attribute access): Document 'none'. * tree-ssa-uninit.c (struct wlimits): New. (maybe_warn_operand): New function. (maybe_warn_pass_by_reference): Same. (warn_uninitialized_vars): Refactor code into maybe_warn_operand. Also call for function calls. (pass_late_warn_uninitialized::execute): Adjust comments. (execute_early_warn_uninitialized): Same. gcc/testsuite/ChangeLog: PR middle-end/10138 PR middle-end/95136 * c-c++-common/Wsizeof-pointer-memaccess1.c: Prune out valid Wuninitialized. * c-c++-common/uninit-pr51010.c: Adjust expected warning format. * c-c++-common/goacc/uninit-dim-clause.c: Same. * c-c++-common/goacc/uninit-firstprivate-clause.c: Same. * c-c++-common/goacc/uninit-if-clause.c: Same. * c-c++-common/gomp/pr70550-1.c: Same. * c-c++-common/gomp/pr70550-2.c: Adjust. * g++.dg/20090107-1.C: Same. * g++.dg/20090121-1.C: Same. * g++.dg/ext/attr-access.C: Avoid -Wuninitialized. * gcc.dg/tree-ssa/forwprop-6.c: Prune out -Wuninitialized. * gcc.dg/Warray-bounds-52.c: Prune out valid -Wuninitialized. * gcc.dg/Warray-bounds-53.c: Same. * gcc.dg/Warray-bounds-54.c: Same. * gcc.dg/Wstringop-overflow-33.c: New test. * gcc.dg/attr-access-none.c: New test. * gcc.dg/attr-access-read-only.c: Adjust. * gcc.dg/attr-access-read-write.c: Same. * gcc.dg/attr-access-write-only.c: Same. * gcc.dg/pr71581.c: Adjust text of expected warning. * gcc.dg/uninit-15.c: Same. * gcc.dg/uninit-32.c: New test. * gcc.dg/uninit-33.c: New test. * gcc.dg/uninit-34.c: New test. * gcc.dg/uninit-36.c: New test. * gcc.dg/uninit-B-O0.c: Adjust text of expected warning. * gcc.dg/uninit-I-O0.c: Same. * gcc.dg/uninit-pr19430-O0.c: Same. * gcc.dg/uninit-pr19430.c: Same. * gcc.dg/uninit-pr95136.c: New test. * gfortran.dg/assignment_4.f90: Expect -Wuninitialized. * gfortran.dg/goacc/uninit-dim-clause.f95: Adjust text of expected warning. * gfortran.dg/goacc/uninit-firstprivate-clause.f95 * gfortran.dg/goacc/uninit-if-clause.f95 * gfortran.dg/pr66545_2.f90
This commit is contained in:
@@ -2017,6 +2017,65 @@ maybe_diag_alias_attributes (tree alias, tree target)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize a mapping for a call to function FNDECL declared with
|
||||
attribute access. Each attribute positional operand inserts one
|
||||
entry into the mapping with the operand number as the key. */
|
||||
|
||||
void
|
||||
init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
|
||||
{
|
||||
if (!fntype)
|
||||
return;
|
||||
|
||||
for (tree access = TYPE_ATTRIBUTES (fntype);
|
||||
(access = lookup_attribute ("access", access));
|
||||
access = TREE_CHAIN (access))
|
||||
{
|
||||
/* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE
|
||||
is the attribute argument's value. */
|
||||
tree mode = TREE_VALUE (access);
|
||||
gcc_assert (TREE_CODE (mode) == TREE_LIST);
|
||||
mode = TREE_VALUE (mode);
|
||||
gcc_assert (TREE_CODE (mode) == STRING_CST);
|
||||
|
||||
const char *modestr = TREE_STRING_POINTER (mode);
|
||||
for (const char *m = modestr; *m; )
|
||||
{
|
||||
attr_access acc = { };
|
||||
|
||||
switch (*m)
|
||||
{
|
||||
case 'r': acc.mode = acc.read_only; break;
|
||||
case 'w': acc.mode = acc.write_only; break;
|
||||
case 'x': acc.mode = acc.read_write; break;
|
||||
case '-': acc.mode = acc.none; break;
|
||||
default: gcc_unreachable ();
|
||||
}
|
||||
|
||||
char *end;
|
||||
acc.ptrarg = strtoul (++m, &end, 10);
|
||||
m = end;
|
||||
if (*m == ',')
|
||||
{
|
||||
acc.sizarg = strtoul (++m, &end, 10);
|
||||
m = end;
|
||||
}
|
||||
else
|
||||
acc.sizarg = UINT_MAX;
|
||||
|
||||
acc.ptr = NULL_TREE;
|
||||
acc.size = NULL_TREE;
|
||||
|
||||
/* Unconditionally add an entry for the required pointer
|
||||
operand of the attribute, and one for the optional size
|
||||
operand when it's specified. */
|
||||
rwm->put (acc.ptrarg, acc);
|
||||
if (acc.sizarg != UINT_MAX)
|
||||
rwm->put (acc.sizarg, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if CHECKING_P
|
||||
|
||||
|
||||
@@ -234,8 +234,18 @@ struct attr_access
|
||||
unsigned sizarg;
|
||||
|
||||
/* The access mode. */
|
||||
enum access_mode { read_only, write_only, read_write };
|
||||
enum access_mode { none, read_only, write_only, read_write };
|
||||
access_mode mode;
|
||||
};
|
||||
|
||||
/* Used to define rdwr_map below. */
|
||||
struct rdwr_access_hash: int_hash<int, -1> { };
|
||||
|
||||
/* A mapping between argument number corresponding to attribute access
|
||||
mode (read_only, write_only, or read_write) and operands. */
|
||||
struct attr_access;
|
||||
typedef hash_map<rdwr_access_hash, attr_access> rdwr_map;
|
||||
|
||||
extern void init_attr_rdwr_indices (rdwr_map *, tree);
|
||||
|
||||
#endif // GCC_ATTRIBS_H
|
||||
|
||||
126
gcc/builtins.c
126
gcc/builtins.c
@@ -3310,6 +3310,90 @@ determine_block_size (tree len, rtx len_rtx,
|
||||
GET_MODE_MASK (GET_MODE (len_rtx)));
|
||||
}
|
||||
|
||||
/* For an expression EXP issue an access warning controlled by option OPT
|
||||
with access to a region SLEN bytes in size in the RANGE of sizes. */
|
||||
|
||||
static bool
|
||||
warn_for_access (location_t loc, tree func, tree exp, int opt, tree range[2],
|
||||
tree slen, bool access)
|
||||
{
|
||||
bool warned = false;
|
||||
|
||||
if (access)
|
||||
{
|
||||
if (tree_int_cst_equal (range[0], range[1]))
|
||||
warned = (func
|
||||
? warning_n (loc, opt, tree_to_uhwi (range[0]),
|
||||
"%K%qD reading %E byte from a region of size %E",
|
||||
"%K%qD reading %E bytes from a region of size %E",
|
||||
exp, func, range[0], slen)
|
||||
: warning_n (loc, opt, tree_to_uhwi (range[0]),
|
||||
"%Kreading %E byte from a region of size %E",
|
||||
"%Kreading %E bytes from a region of size %E",
|
||||
exp, range[0], slen));
|
||||
else if (tree_int_cst_sign_bit (range[1]))
|
||||
{
|
||||
/* Avoid printing the upper bound if it's invalid. */
|
||||
warned = (func
|
||||
? warning_at (loc, opt,
|
||||
"%K%qD reading %E or more bytes from a region "
|
||||
"of size %E",
|
||||
exp, func, range[0], slen)
|
||||
: warning_at (loc, opt,
|
||||
"%Kreading %E or more bytes from a region "
|
||||
"of size %E",
|
||||
exp, range[0], slen));
|
||||
}
|
||||
else
|
||||
warned = (func
|
||||
? warning_at (loc, opt,
|
||||
"%K%qD reading between %E and %E bytes from "
|
||||
"a region of size %E",
|
||||
exp, func, range[0], range[1], slen)
|
||||
: warning_at (loc, opt,
|
||||
"%Kreading between %E and %E bytes from "
|
||||
"a region of size %E",
|
||||
exp, range[0], range[1], slen));
|
||||
|
||||
return warned;
|
||||
}
|
||||
|
||||
if (tree_int_cst_equal (range[0], range[1]))
|
||||
warned = (func
|
||||
? warning_n (loc, opt, tree_to_uhwi (range[0]),
|
||||
"%K%qD epecting %E byte in a region of size %E",
|
||||
"%K%qD expecting %E bytes in a region of size %E",
|
||||
exp, func, range[0], slen)
|
||||
: warning_n (loc, opt, tree_to_uhwi (range[0]),
|
||||
"%Kexpecting %E byte in a region of size %E",
|
||||
"%Kexpecting %E bytes in a region of size %E",
|
||||
exp, range[0], slen));
|
||||
else if (tree_int_cst_sign_bit (range[1]))
|
||||
{
|
||||
/* Avoid printing the upper bound if it's invalid. */
|
||||
warned = (func
|
||||
? warning_at (loc, opt,
|
||||
"%K%qD expecting %E or more bytes in a region "
|
||||
"of size %E",
|
||||
exp, func, range[0], slen)
|
||||
: warning_at (loc, opt,
|
||||
"%Kexpecting %E or more bytes in a region "
|
||||
"of size %E",
|
||||
exp, range[0], slen));
|
||||
}
|
||||
else
|
||||
warned = (func
|
||||
? warning_at (loc, opt,
|
||||
"%K%qD expecting between %E and %E bytes in "
|
||||
"a region of size %E",
|
||||
exp, func, range[0], range[1], slen)
|
||||
: warning_at (loc, opt,
|
||||
"%Kexpectting between %E and %E bytes in "
|
||||
"a region of size %E",
|
||||
exp, range[0], range[1], slen));
|
||||
return warned;
|
||||
}
|
||||
|
||||
/* Try to verify that the sizes and lengths of the arguments to a string
|
||||
manipulation function given by EXP are within valid bounds and that
|
||||
the operation does not lead to buffer overflow or read past the end.
|
||||
@@ -3336,12 +3420,16 @@ determine_block_size (tree len, rtx len_rtx,
|
||||
When DSTWRITE is null LEN is checked to verify that it doesn't exceed
|
||||
SIZE_MAX.
|
||||
|
||||
ACCESS is true for accesses, false for simple size checks in calls
|
||||
to functions that neither read from nor write to the region.
|
||||
|
||||
If the call is successfully verified as safe return true, otherwise
|
||||
return false. */
|
||||
|
||||
bool
|
||||
check_access (tree exp, tree, tree, tree dstwrite,
|
||||
tree maxread, tree srcstr, tree dstsize)
|
||||
tree maxread, tree srcstr, tree dstsize,
|
||||
bool access /* = true */)
|
||||
{
|
||||
int opt = OPT_Wstringop_overflow_;
|
||||
|
||||
@@ -3649,44 +3737,10 @@ check_access (tree exp, tree, tree, tree dstwrite,
|
||||
if (TREE_NO_WARNING (exp))
|
||||
return false;
|
||||
|
||||
bool warned = false;
|
||||
location_t loc = tree_nonartificial_location (exp);
|
||||
loc = expansion_point_location_if_in_system_header (loc);
|
||||
|
||||
if (tree_int_cst_equal (range[0], range[1]))
|
||||
warned = (func
|
||||
? warning_n (loc, opt, tree_to_uhwi (range[0]),
|
||||
"%K%qD reading %E byte from a region of size %E",
|
||||
"%K%qD reading %E bytes from a region of size %E",
|
||||
exp, func, range[0], slen)
|
||||
: warning_n (loc, opt, tree_to_uhwi (range[0]),
|
||||
"%Kreading %E byte from a region of size %E",
|
||||
"%Kreading %E bytes from a region of size %E",
|
||||
exp, range[0], slen));
|
||||
else if (tree_int_cst_sign_bit (range[1]))
|
||||
{
|
||||
/* Avoid printing the upper bound if it's invalid. */
|
||||
warned = (func
|
||||
? warning_at (loc, opt,
|
||||
"%K%qD reading %E or more bytes from a region "
|
||||
"of size %E",
|
||||
exp, func, range[0], slen)
|
||||
: warning_at (loc, opt,
|
||||
"%Kreading %E or more bytes from a region "
|
||||
"of size %E",
|
||||
exp, range[0], slen));
|
||||
}
|
||||
else
|
||||
warned = (func
|
||||
? warning_at (loc, opt,
|
||||
"%K%qD reading between %E and %E bytes from "
|
||||
"a region of size %E",
|
||||
exp, func, range[0], range[1], slen)
|
||||
: warning_at (loc, opt,
|
||||
"%Kreading between %E and %E bytes from "
|
||||
"a region of size %E",
|
||||
exp, range[0], range[1], slen));
|
||||
if (warned)
|
||||
if (warn_for_access (loc, func, exp, opt, range, slen, access))
|
||||
TREE_NO_WARNING (exp) = true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -156,7 +156,8 @@ bool check_nul_terminated_array (tree, tree, tree = NULL_TREE);
|
||||
extern void warn_string_no_nul (location_t, const char *, tree, tree);
|
||||
extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
|
||||
extern bool builtin_with_linkage_p (tree);
|
||||
extern bool check_access (tree, tree, tree, tree, tree, tree, tree);
|
||||
extern bool check_access (tree, tree, tree, tree, tree, tree, tree,
|
||||
bool = true);
|
||||
|
||||
|
||||
#endif /* GCC_BUILTINS_H */
|
||||
|
||||
@@ -3875,14 +3875,17 @@ append_access_attrs (tree t, tree attrs, const char *attrstr,
|
||||
/* Found a matching positional argument. */
|
||||
if (*attrspec != pos[-1])
|
||||
{
|
||||
const char* const modestr
|
||||
= (pos[-1] == 'r'
|
||||
? "read_only"
|
||||
: (pos[-1] == 'w'
|
||||
? "write_only"
|
||||
: (pos[-1] == 'x' ? "read_write" : "none")));
|
||||
/* Mismatch in access mode. */
|
||||
auto_diagnostic_group d;
|
||||
if (warning (OPT_Wattributes,
|
||||
"attribute %qs mismatch with mode %qs",
|
||||
attrstr,
|
||||
(pos[-1] == 'r'
|
||||
? "read_only"
|
||||
: (pos[-1] == 'w' ? "write_only" : "read_write")))
|
||||
attrstr, modestr)
|
||||
&& DECL_P (t))
|
||||
inform (DECL_SOURCE_LOCATION (t),
|
||||
"previous declaration here");
|
||||
@@ -4014,13 +4017,14 @@ handle_access_attribute (tree *node, tree name, tree args,
|
||||
ps += 2;
|
||||
}
|
||||
|
||||
const bool read_only = strncmp (ps, "read_only", 9) == 0;
|
||||
const bool write_only = strncmp (ps, "write_only", 10) == 0;
|
||||
if (!read_only && !write_only && strncmp (ps, "read_write", 10))
|
||||
const bool read_only = !strncmp (ps, "read_only", 9);
|
||||
const bool write_only = !strncmp (ps, "write_only", 10);
|
||||
const bool read_write = !strncmp (ps, "read_write", 10);
|
||||
if (!read_only && !write_only && !read_write && strncmp (ps, "none", 4))
|
||||
{
|
||||
error ("attribute %qE invalid mode %qs; expected one of "
|
||||
"%qs, %qs, or %qs", name, access_str,
|
||||
"read_only", "read_write", "write_only");
|
||||
"%qs, %qs, %qs, or %qs", name, access_str,
|
||||
"read_only", "read_write", "write_only", "none");
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
@@ -4145,9 +4149,9 @@ handle_access_attribute (tree *node, tree name, tree args,
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_only)
|
||||
if (read_write || write_only)
|
||||
{
|
||||
/* A read_write and write_only modes must reference non-const
|
||||
/* Read_write and write_only modes must reference non-const
|
||||
arguments. */
|
||||
if (TYPE_READONLY (TREE_TYPE (argtypes[0])))
|
||||
{
|
||||
@@ -4178,7 +4182,8 @@ handle_access_attribute (tree *node, tree name, tree args,
|
||||
/* Verify that the new attribute doesn't conflict with any existing
|
||||
attributes specified on previous declarations of the same type
|
||||
and if not, concatenate the two. */
|
||||
const char code = read_only ? 'r' : write_only ? 'w' : 'x';
|
||||
const char code
|
||||
= read_only ? 'r' : write_only ? 'w' : read_write ? 'x' : '-';
|
||||
tree new_attrs = append_access_attrs (node[0], attrs, attrstr, code, idxs);
|
||||
if (!new_attrs)
|
||||
return NULL_TREE;
|
||||
|
||||
83
gcc/calls.c
83
gcc/calls.c
@@ -1865,70 +1865,6 @@ maybe_complain_about_tail_call (tree call_expr, const char *reason)
|
||||
error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason);
|
||||
}
|
||||
|
||||
/* Used to define rdwr_map below. */
|
||||
struct rdwr_access_hash: int_hash<int, -1> { };
|
||||
|
||||
/* A mapping between argument number corresponding to attribute access
|
||||
mode (read_only, write_only, or read_write) and operands. */
|
||||
typedef hash_map<rdwr_access_hash, attr_access> rdwr_map;
|
||||
|
||||
/* Initialize a mapping for a call to function FNDECL declared with
|
||||
attribute access. Each attribute positional operand inserts one
|
||||
entry into the mapping with the operand number as the key. */
|
||||
|
||||
static void
|
||||
init_attr_rdwr_indices (rdwr_map *rwm, tree fntype)
|
||||
{
|
||||
if (!fntype)
|
||||
return;
|
||||
|
||||
for (tree access = TYPE_ATTRIBUTES (fntype);
|
||||
(access = lookup_attribute ("access", access));
|
||||
access = TREE_CHAIN (access))
|
||||
{
|
||||
/* The TREE_VALUE of an attribute is a TREE_LIST whose TREE_VALUE
|
||||
is the attribute argument's value. */
|
||||
tree mode = TREE_VALUE (access);
|
||||
gcc_assert (TREE_CODE (mode) == TREE_LIST);
|
||||
mode = TREE_VALUE (mode);
|
||||
gcc_assert (TREE_CODE (mode) == STRING_CST);
|
||||
|
||||
const char *modestr = TREE_STRING_POINTER (mode);
|
||||
for (const char *m = modestr; *m; )
|
||||
{
|
||||
attr_access acc = { };
|
||||
|
||||
switch (*m)
|
||||
{
|
||||
case 'r': acc.mode = acc.read_only; break;
|
||||
case 'w': acc.mode = acc.write_only; break;
|
||||
default: acc.mode = acc.read_write; break;
|
||||
}
|
||||
|
||||
char *end;
|
||||
acc.ptrarg = strtoul (++m, &end, 10);
|
||||
m = end;
|
||||
if (*m == ',')
|
||||
{
|
||||
acc.sizarg = strtoul (++m, &end, 10);
|
||||
m = end;
|
||||
}
|
||||
else
|
||||
acc.sizarg = UINT_MAX;
|
||||
|
||||
acc.ptr = NULL_TREE;
|
||||
acc.size = NULL_TREE;
|
||||
|
||||
/* Unconditionally add an entry for the required pointer
|
||||
operand of the attribute, and one for the optional size
|
||||
operand when it's specified. */
|
||||
rwm->put (acc.ptrarg, acc);
|
||||
if (acc.sizarg != UINT_MAX)
|
||||
rwm->put (acc.sizarg, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the type of the argument ARGNO to function with type FNTYPE
|
||||
or null when the typoe cannot be determined or no such argument exists. */
|
||||
|
||||
@@ -1959,11 +1895,13 @@ append_attrname (const std::pair<int, attr_access> &access,
|
||||
appends the attribute pointer operand even when none was specified. */
|
||||
size_t len = strlen (attrstr);
|
||||
|
||||
const char *atname
|
||||
const char* const atname
|
||||
= (access.second.mode == attr_access::read_only
|
||||
? "read_only"
|
||||
: (access.second.mode == attr_access::write_only
|
||||
? "write_only" : "read_write"));
|
||||
? "write_only"
|
||||
: (access.second.mode == attr_access::read_write
|
||||
? "read_write" : "none")));
|
||||
|
||||
const char *sep = len ? ", " : "";
|
||||
|
||||
@@ -2131,11 +2069,13 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp)
|
||||
/* For read-only and read-write attributes also set the source
|
||||
size. */
|
||||
srcsize = objsize;
|
||||
if (access.second.mode == attr_access::read_only)
|
||||
if (access.second.mode == attr_access::read_only
|
||||
|| access.second.mode == attr_access::none)
|
||||
{
|
||||
/* For a read-only attribute there is no destination so
|
||||
clear OBJSIZE. This emits "reading N bytes" kind of
|
||||
diagnostics instead of the "writing N bytes" kind. */
|
||||
diagnostics instead of the "writing N bytes" kind,
|
||||
unless MODE is none. */
|
||||
objsize = NULL_TREE;
|
||||
}
|
||||
}
|
||||
@@ -2145,7 +2085,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree exp)
|
||||
diagnosed. */
|
||||
TREE_NO_WARNING (exp) = false;
|
||||
check_access (exp, NULL_TREE, NULL_TREE, size, /*maxread=*/ NULL_TREE,
|
||||
srcsize, objsize);
|
||||
srcsize, objsize, access.second.mode != attr_access::none);
|
||||
|
||||
if (TREE_NO_WARNING (exp))
|
||||
/* If check_access issued a warning above, append the relevant
|
||||
@@ -2285,8 +2225,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
|
||||
/* Array for up to the two attribute alloc_size arguments. */
|
||||
tree alloc_args[] = { NULL_TREE, NULL_TREE };
|
||||
|
||||
/* Map of attribute read_only, write_only, or read_write specifications
|
||||
for function arguments. */
|
||||
/* Map of attribute accewss specifications for function arguments. */
|
||||
rdwr_map rdwr_idx;
|
||||
init_attr_rdwr_indices (&rdwr_idx, fntype);
|
||||
|
||||
@@ -2559,7 +2498,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
|
||||
nul-terminated strings. */
|
||||
maybe_warn_nonstring_arg (fndecl, exp);
|
||||
|
||||
/* Check read_only, write_only, and read_write arguments. */
|
||||
/* Check attribute access arguments. */
|
||||
maybe_warn_rdwr_sizes (&rdwr_idx, exp);
|
||||
}
|
||||
|
||||
|
||||
@@ -2497,8 +2497,8 @@ may be diagnosed by warnings such as @option{-Wstringop-overflow},
|
||||
The @code{access} attribute specifies that a function to whose by-reference
|
||||
arguments the attribute applies accesses the referenced object according to
|
||||
@var{access-mode}. The @var{access-mode} argument is required and must be
|
||||
one of three names: @code{read_only}, @code{read_write}, or @code{write_only}.
|
||||
The remaining two are positional arguments.
|
||||
one of four names: @code{read_only}, @code{read_write}, @code{write_only},
|
||||
or @code{none}. The remaining two are positional arguments.
|
||||
|
||||
The required @var{ref-index} positional argument denotes a function
|
||||
argument of pointer (or in C++, reference) type that is subject to
|
||||
@@ -2555,6 +2555,14 @@ __attribute__ ((access (write_only, 1), access (read_only, 2))) char* strcpy (ch
|
||||
__attribute__ ((access (write_only, 1, 2), access (read_write, 3))) int fgets (char*, int, FILE*);
|
||||
@end smallexample
|
||||
|
||||
The access mode @code{none} specifies that the pointer to which it applies
|
||||
is not used to access the referenced object at all. Unless the pointer is
|
||||
null the pointed-to object must exist and have at least the size as denoted
|
||||
by the @var{size-index} argument. The object need not be initialized.
|
||||
The mode is intended to be used as a means to help validate the expected
|
||||
object size, for example in functions that call @code{__builtin_object_size}.
|
||||
@xref{Object Size Checking}.
|
||||
|
||||
@item alias ("@var{target}")
|
||||
@cindex @code{alias} function attribute
|
||||
The @code{alias} attribute causes the declaration to be emitted as an alias
|
||||
|
||||
@@ -161,3 +161,5 @@ f4 (char x[64], char *y, __builtin_va_list ap)
|
||||
snprintf (p, sizeof (buf), "%s", y);
|
||||
vsnprintf (p, sizeof (buf), "%s", ap);
|
||||
}
|
||||
|
||||
/* { dg-prune-output "-Wuninitialized" } */
|
||||
|
||||
@@ -4,13 +4,13 @@ void acc_parallel()
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
#pragma acc parallel num_gangs(i) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc parallel num_gangs(i) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc parallel num_workers(j) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc parallel num_workers(j) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc parallel vector_length(k) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc parallel vector_length(k) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ void acc_kernels()
|
||||
{
|
||||
int i, j, k;
|
||||
|
||||
#pragma acc kernels num_gangs(i) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc kernels num_gangs(i) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc kernels num_workers(j) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc kernels num_workers(j) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc kernels vector_length(k) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc kernels vector_length(k) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ foo2 (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#pragma acc parallel firstprivate (i) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc parallel firstprivate (i) /* { dg-warning "is used uninitialized" } */
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
|
||||
@@ -11,28 +11,28 @@ main (void)
|
||||
bool b, b2, b3, b4;
|
||||
int i, i2;
|
||||
|
||||
#pragma acc parallel if(l) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc parallel if(l) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc parallel if(b) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
|
||||
#pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
|
||||
;
|
||||
|
||||
#pragma acc kernels if(l2) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc kernels if(l2) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc kernels if(b2) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
|
||||
#pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
|
||||
;
|
||||
|
||||
#pragma acc data if(l3) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc data if(l3) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc data if(b3) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
|
||||
#pragma acc data if(b3) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
|
||||
;
|
||||
|
||||
#pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized" } */
|
||||
;
|
||||
|
||||
#pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized in this function" "" { xfail c++ } } */
|
||||
#pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ foo (void)
|
||||
{
|
||||
{
|
||||
int i;
|
||||
#pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
i = 26;
|
||||
bar (i);
|
||||
@@ -24,7 +24,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
T j;
|
||||
#pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp target defaultmap(tofrom:scalar) /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
j = 37;
|
||||
bar (j);
|
||||
@@ -32,7 +32,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
int i;
|
||||
#pragma omp target /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp target /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
i = 26;
|
||||
bar (i);
|
||||
@@ -40,7 +40,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
T j;
|
||||
#pragma omp target /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp target /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
j = 37;
|
||||
bar (j);
|
||||
@@ -48,7 +48,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
int i;
|
||||
#pragma omp target firstprivate (i) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma omp target firstprivate (i) /* { dg-warning "is used uninitialized" } */
|
||||
{
|
||||
i = 26;
|
||||
bar (i);
|
||||
@@ -56,7 +56,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
T j;
|
||||
#pragma omp target firstprivate (j) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma omp target firstprivate (j) /* { dg-warning "is used uninitialized" } */
|
||||
{
|
||||
j = 37;
|
||||
bar (j);
|
||||
@@ -64,7 +64,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
int i;
|
||||
#pragma omp target private (i) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp target private (i) /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
i = 26;
|
||||
bar (i);
|
||||
@@ -72,7 +72,7 @@ foo (void)
|
||||
}
|
||||
{
|
||||
T j;
|
||||
#pragma omp target private (j) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp target private (j) /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
j = 37;
|
||||
bar (j);
|
||||
|
||||
@@ -8,45 +8,45 @@ void
|
||||
foo (void)
|
||||
{
|
||||
int i, j, k, l, m, n, o, p, q;
|
||||
#pragma omp task /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp task /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
i = 2;
|
||||
bar (i);
|
||||
}
|
||||
#pragma omp taskloop /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp taskloop /* { dg-bogus "is used uninitialized" } */
|
||||
for (j = 0; j < 10; j++)
|
||||
{
|
||||
k = 7;
|
||||
bar (k);
|
||||
}
|
||||
#pragma omp task firstprivate (l) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma omp task firstprivate (l) /* { dg-warning "is used uninitialized" } */
|
||||
{
|
||||
l = 2;
|
||||
bar (l);
|
||||
}
|
||||
#pragma omp taskloop firstprivate (m) /* { dg-warning "is used uninitialized in this function" } */
|
||||
#pragma omp taskloop firstprivate (m) /* { dg-warning "is used uninitialized" } */
|
||||
for (j = 0; j < 10; j++)
|
||||
{
|
||||
m = 7;
|
||||
bar (m);
|
||||
}
|
||||
#pragma omp task shared (n) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp task shared (n) /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
n = 2;
|
||||
bar (n);
|
||||
}
|
||||
#pragma omp taskloop shared (o) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp taskloop shared (o) /* { dg-bogus "is used uninitialized" } */
|
||||
for (j = 0; j < 10; j++)
|
||||
{
|
||||
o = 7;
|
||||
bar (o);
|
||||
}
|
||||
#pragma omp task private (p) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp task private (p) /* { dg-bogus "is used uninitialized" } */
|
||||
{
|
||||
p = 2;
|
||||
bar (p);
|
||||
}
|
||||
#pragma omp taskloop shared (q) /* { dg-bogus "is used uninitialized in this function" } */
|
||||
#pragma omp taskloop shared (q) /* { dg-bogus "is used uninitialized" } */
|
||||
for (j = 0; j < 10; j++)
|
||||
{
|
||||
q = 7;
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
int f (int j)
|
||||
{
|
||||
int a [10];
|
||||
return a [j]; /* { dg-warning "a\\\[j\\\]. is used uninitialized" } */
|
||||
return a [j]; /* { dg-warning "a|a\\\[j\\\]. is used uninitialized" } */
|
||||
}
|
||||
int g (int j)
|
||||
{
|
||||
int a [10];
|
||||
return a [j+1]; /* { dg-warning "a\\\[<unknown>\\\]. is used uninitialized" } */
|
||||
return a [j+1]; /* { dg-warning "a|a\\\[<unknown>\\\]. is used uninitialized" } */
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ template <typename T> struct Q1 { typedef int x; };
|
||||
template <typename T> struct Q2 {
|
||||
typename Q1<T>::x f() {
|
||||
int k;
|
||||
return k; /* { dg-warning "'k' is used uninitialized in this function" } */
|
||||
return k; /* { dg-warning "'k' is used uninitialized" } */
|
||||
}
|
||||
};
|
||||
int foo() { return Q2<int>().f(); }
|
||||
|
||||
@@ -7,7 +7,7 @@ private:
|
||||
int y;
|
||||
|
||||
public:
|
||||
A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized in this function" } */
|
||||
A () { int x; y = x + 1; } /* { dg-warning "'x' is used uninitialized" } */
|
||||
int get_y () { return y; }
|
||||
};
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ void call_rop1_ror2_O0 (void)
|
||||
|
||||
void call_rdwrp1_rdwrr2_O0 (void)
|
||||
{
|
||||
int32_t x[1];
|
||||
int32_t x[1] = { };
|
||||
|
||||
rdwrp1_rdwrr2 (x, x[0]);
|
||||
rdwrp1_rdwrr2 (x, x[1]); // { dg-warning "writing 4 bytes into a region of size 0" }
|
||||
@@ -78,7 +78,7 @@ void call_rop1_ror2_O1 (void)
|
||||
|
||||
void call_rdwrp1_rdwrr2_O1 (void)
|
||||
{
|
||||
int32_t x[1];
|
||||
int32_t x[1] = { };
|
||||
int32_t *p0 = x, &r0 = x[0];
|
||||
int32_t *p1 = (int32_t*)((char*)p0 + 1);
|
||||
int32_t &r2 = *(int32_t*)((char*)p1 + 1);
|
||||
|
||||
@@ -95,3 +95,6 @@ void ptr_idx_range (void)
|
||||
i = SR (3, 4);
|
||||
T (i, (int[]){ 2, 3, 4 }); // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" }
|
||||
}
|
||||
|
||||
/* Some of the invalid accesses above also trigger -Wuninitialized.
|
||||
{ dg-prune-output "\\\[-Wuninitialized" } */
|
||||
|
||||
@@ -95,3 +95,6 @@ void ptr_idx_range (void)
|
||||
i = SR (3, 4);
|
||||
T (i, (int[]){ 2, 3, 4 }); // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" }
|
||||
}
|
||||
|
||||
/* Some of the invalid accesses above also trigger -Wuninitialized.
|
||||
{ dg-prune-output "\\\[-Wuninitialized" } */
|
||||
|
||||
@@ -10,9 +10,9 @@ int f0 (void)
|
||||
return p[2]; // { dg-warning "-Warray-bounds" }
|
||||
}
|
||||
|
||||
int f1 (void)
|
||||
int f1 (int j)
|
||||
{
|
||||
int i;
|
||||
int i = j;
|
||||
int *p = &i;
|
||||
return p[2]; // { dg-warning "-Warray-bounds" }
|
||||
}
|
||||
@@ -22,3 +22,5 @@ int f2 (int i)
|
||||
int *p = &i;
|
||||
return p[2]; // { dg-warning "-Warray-bounds" }
|
||||
}
|
||||
|
||||
/* { dg-prune-output "-Wuninitialized" } */
|
||||
|
||||
40
gcc/testsuite/gcc.dg/Wstringop-overflow-33.c
Normal file
40
gcc/testsuite/gcc.dg/Wstringop-overflow-33.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/* PR middle-end/82456 - missing -Wstringop-overflow on strcpy reading past
|
||||
the end of an array
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
void fcst (char *d)
|
||||
{
|
||||
char a[2] = "0";
|
||||
|
||||
__builtin_strcpy (d, a + 3); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
|
||||
}
|
||||
|
||||
void frng (char *d, int i)
|
||||
{
|
||||
char a[2] = "0";
|
||||
|
||||
if (i < 3)
|
||||
i = 3;
|
||||
|
||||
__builtin_strcpy (d, a + i); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
|
||||
}
|
||||
|
||||
void gcst (char *d)
|
||||
{
|
||||
char a[2] = "0";
|
||||
|
||||
__builtin_strcpy (d, a + 2); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
|
||||
}
|
||||
|
||||
void grng (char *d, int i)
|
||||
{
|
||||
char a[2] = "0";
|
||||
|
||||
if (i < 2)
|
||||
i = 2;
|
||||
|
||||
__builtin_strcpy (d, a + i); // { dg-warning "\\\[-W(array-bounds|stringop-overflow)" }
|
||||
}
|
||||
|
||||
/* { dg-prune-output "-Wuninitialized" } */
|
||||
38
gcc/testsuite/gcc.dg/attr-access-none.c
Normal file
38
gcc/testsuite/gcc.dg/attr-access-none.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Test to verify the handling of attribute access (none).
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O -Wall -ftrack-macro-expansion=0" } */
|
||||
|
||||
int __attribute__ ((access (none, 1)))
|
||||
fnone_pv1 (void*);
|
||||
|
||||
void nowarn_fnone_pv1 (void)
|
||||
{
|
||||
int x;
|
||||
fnone_pv1 (&x);
|
||||
}
|
||||
|
||||
|
||||
int __attribute__ ((access (none, 1)))
|
||||
fnone_pcv1 (const void*);
|
||||
|
||||
void nowarn_fnone_pcv1 (void)
|
||||
{
|
||||
char a[2];
|
||||
fnone_pcv1 (a);
|
||||
}
|
||||
|
||||
|
||||
int __attribute__ ((access (none, 1, 2)))
|
||||
fnone_pcv1_2 (const void*, int); // { dg-message "in a call to function 'fnone_pcv1_2' declared with attribute 'none \\\(1, 2\\\)'" }
|
||||
|
||||
void nowarn_fnone_pcv1_2 (void)
|
||||
{
|
||||
char a[2];
|
||||
fnone_pcv1_2 (a, 2);
|
||||
}
|
||||
|
||||
void warn_fnone_pcv1_2 (void)
|
||||
{
|
||||
char a[3];
|
||||
fnone_pcv1_2 (a, 4); // { dg-warning "expecting 4 bytes in a region of size 3" }
|
||||
}
|
||||
@@ -11,7 +11,7 @@ int __attribute__ ((access ()))
|
||||
access___v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" }
|
||||
|
||||
int __attribute__ ((access (rdonly)))
|
||||
rdonly_spelling (void); // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', or 'write_only'" }
|
||||
rdonly_spelling (void); // { dg-error "attribute .access. invalid mode 'rdonly'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" }
|
||||
|
||||
int __attribute__ ((access (read_only)))
|
||||
rdonly_v_all (void); // { dg-error "attribute .access\\(read_only\\). missing an argument" }
|
||||
|
||||
@@ -10,7 +10,7 @@ int __attribute__ ((access ()))
|
||||
access___v (void); /* { dg-error "wrong number of arguments specified for 'access' attribute" } */
|
||||
|
||||
int __attribute__ ((access (rdwr)))
|
||||
rdwr_spelling (void); /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', or 'write_only'" } */
|
||||
rdwr_spelling (void); /* { dg-error "attribute .access. invalid mode 'rdwr'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" } */
|
||||
|
||||
int __attribute__ ((access (read_write)))
|
||||
rdwr_v_all (void); /* { dg-error "attribute .access\\(read_write\\). missing an argument" } */
|
||||
|
||||
@@ -11,7 +11,7 @@ int __attribute__ ((access ()))
|
||||
access___v (void); // { dg-error "wrong number of arguments specified for 'access' attribute" }
|
||||
|
||||
int __attribute__ ((access (wronly)))
|
||||
wronly_spelling (void); // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', or 'write_only'" }
|
||||
wronly_spelling (void); // { dg-error "attribute .access. invalid mode 'wronly'; expected one of 'read_only', 'read_write', 'write_only', or 'none'" }
|
||||
|
||||
int __attribute__ ((access (read_only)))
|
||||
wronly_v_all (void); // { dg-error "attribute .access\\(read_only\\). missing an argument" }
|
||||
|
||||
@@ -6,19 +6,19 @@ _Complex float
|
||||
f1 (void)
|
||||
{
|
||||
float x;
|
||||
return x; /* { dg-warning "is used uninitialized in this function" } */
|
||||
return x; /* { dg-warning "is used uninitialized" } */
|
||||
}
|
||||
|
||||
_Complex double
|
||||
f2 (void)
|
||||
{
|
||||
double x;
|
||||
return x; /* { dg-warning "is used uninitialized in this function" } */
|
||||
return x; /* { dg-warning "is used uninitialized" } */
|
||||
}
|
||||
|
||||
_Complex int
|
||||
f3 (void)
|
||||
{
|
||||
int x;
|
||||
return x; /* { dg-warning "is used uninitialized in this function" } */
|
||||
return x; /* { dg-warning "is used uninitialized" } */
|
||||
}
|
||||
|
||||
@@ -25,3 +25,6 @@ void f(void)
|
||||
value-numbering, removing the load altogether.
|
||||
??? We now do this after CPP re-writes a into SSA form. */
|
||||
/* { dg-final { scan-tree-dump-times "VIEW_CONVERT_EXPR" 1 "ccp1" } } */
|
||||
|
||||
/* The invalid access above may also trigger -Wuninitialized.
|
||||
{ dg-prune-output "-Wuninitialized" } */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
inline int
|
||||
foo (int i)
|
||||
{
|
||||
if (i) /* { dg-warning "used uninitialized in this function" "" } */
|
||||
if (i) /* { dg-warning "used uninitialized" } */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
312
gcc/testsuite/gcc.dg/uninit-32.c
Normal file
312
gcc/testsuite/gcc.dg/uninit-32.c
Normal file
@@ -0,0 +1,312 @@
|
||||
/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
|
||||
arguments
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O -Wall" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
void* alloca (size_t);
|
||||
void* malloc (size_t);
|
||||
void* realloc (void*, size_t);
|
||||
|
||||
void fpi (int*);
|
||||
void fpci (const int*);
|
||||
void fpcv (const void*);
|
||||
|
||||
|
||||
void nowarn_scalar_fpi (void)
|
||||
{
|
||||
int x;
|
||||
fpi (&x);
|
||||
}
|
||||
|
||||
void nowarn_scalar_plus_cst_fpi (void)
|
||||
{
|
||||
int x;
|
||||
// This deserves a warning other than -Wuninitialized.
|
||||
fpi (&x + 1);
|
||||
}
|
||||
|
||||
void nowarn_scalar_plus_var_fpi (int i)
|
||||
{
|
||||
int x;
|
||||
// Same as above, this deserves a warning other than -Wuninitialized.
|
||||
fpi (&x + i);
|
||||
}
|
||||
|
||||
void nowarn_array_assign_fpci (void)
|
||||
{
|
||||
int a[2];
|
||||
a[0] = 0;
|
||||
fpci (a);
|
||||
}
|
||||
|
||||
void nowarn_array_assign_plus_cst_fpci (void)
|
||||
{
|
||||
int a[4];
|
||||
a[1] = 0;
|
||||
a[2] = 1;
|
||||
fpci (a + 1);
|
||||
}
|
||||
|
||||
void nowarn_array_init_fpci (void)
|
||||
{
|
||||
int a[4] = { 0 };
|
||||
fpci (a);
|
||||
}
|
||||
|
||||
void nowarn_array_compound_fpi (void)
|
||||
{
|
||||
fpi ((int[2]){ 1 });
|
||||
}
|
||||
|
||||
void nowarn_array_compound_fpci (void)
|
||||
{
|
||||
fpci ((int[3]){ 1 });
|
||||
}
|
||||
|
||||
void warn_array_fpci (void)
|
||||
{
|
||||
int a[4]; // { dg-message "declared here" }"
|
||||
fpci (a); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_plus_cst_fpci (void)
|
||||
{
|
||||
int a[4];
|
||||
fpci (a + 1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_plus_var_fpci (int i)
|
||||
{
|
||||
int a[4];
|
||||
fpci (a + i); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_array_end_fpci (void)
|
||||
{
|
||||
int a[4];
|
||||
/* This should be diagnosed by a warning other than -Wuninitialized
|
||||
because the just-past-the-end pointer cannot be dereferenced and
|
||||
the function doesn't take any other pointer to tell where the start
|
||||
of the array is. -Wuninitialized isn't appropriate because there
|
||||
is nothing to initialize at that offset. */
|
||||
fpci (a + 4);
|
||||
}
|
||||
|
||||
void warn_matrix_fpcv (void)
|
||||
{
|
||||
int a[2][2];
|
||||
fpci (a[1]); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_scalar_fpcv (void)
|
||||
{
|
||||
int i;
|
||||
fpci (&i); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_scalar_plus_cst_fpcv (void)
|
||||
{
|
||||
int x;
|
||||
/* Same as above, this deserves a warning other than -Wuninitialized
|
||||
for passing the function a past-the-end pointer with no other
|
||||
argument. */
|
||||
fpci (&x + 1);
|
||||
}
|
||||
|
||||
void warn_scalar_plus_var_fpcv (int i)
|
||||
{
|
||||
int x;
|
||||
fpci (&x + i); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_struct_assign_fpci (void)
|
||||
{
|
||||
struct { int a, b; } s;
|
||||
s.a = 0;
|
||||
fpci (&s.a);
|
||||
}
|
||||
|
||||
void warn_struct_assign_fpci (void)
|
||||
{
|
||||
struct { int a, b; } s;
|
||||
s.a = 0;
|
||||
fpci (&s.b); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_struct_init_fpci (void)
|
||||
{
|
||||
struct { int a, b; } s = { 0 };
|
||||
fpci (&s.a);
|
||||
fpci (&s.b);
|
||||
}
|
||||
|
||||
void nowarn_struct_compound_fpci (void)
|
||||
{
|
||||
struct S { int a, b; };
|
||||
fpci (&(struct S){ }.a);
|
||||
fpci (&(struct S){ }.b);
|
||||
}
|
||||
|
||||
/* Verify that passing a just-past-the-end pointer to a const pointer
|
||||
argument to a function that takes another argument is not diagnosed
|
||||
since the two arguments together could outline a range. */
|
||||
void nowarn_fp_p (void)
|
||||
{
|
||||
extern void fpi_pci (int*, const int*);
|
||||
|
||||
{
|
||||
int i;
|
||||
fpi_pci (&i, &i + 1);
|
||||
}
|
||||
{
|
||||
int j;
|
||||
fpi_pci (&j + 1, &j + 1);
|
||||
}
|
||||
|
||||
extern void fpc_pcc (char*, const char*);
|
||||
|
||||
{
|
||||
char a[2];
|
||||
fpc_pcc (a, a + 2);
|
||||
}
|
||||
{
|
||||
char a[3];
|
||||
fpc_pcc (a, a + 3);
|
||||
}
|
||||
|
||||
extern void fpcc_pcc (const char*, const char*);
|
||||
|
||||
{
|
||||
char a[4];
|
||||
fpcc_pcc (a + 4, a + 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Verify passing addresses of empty uninitialized objects doesn't
|
||||
trigger a warning. */
|
||||
void nowarn_fpcEmpty (void)
|
||||
{
|
||||
struct Empty { };
|
||||
extern void fpcEmpty (const struct Empty*);
|
||||
|
||||
/* Since Empty has no members warning for it isn't really necessary.
|
||||
See also PR 38908. */
|
||||
struct Empty s;
|
||||
fpcEmpty (&s);
|
||||
}
|
||||
|
||||
|
||||
/* Verify passing addresses of uninitialized objects to functions
|
||||
declared without a proptotype doesn't trigger a warning. */
|
||||
void nowarn_noproto (void)
|
||||
{
|
||||
extern void fnoproto ();
|
||||
int i, a[2];
|
||||
|
||||
fnoproto (&i, a, a + 2);
|
||||
}
|
||||
|
||||
|
||||
/* Verify passing addresses of uninitialized objects to variadic
|
||||
functions doesn't trigger a warning. */
|
||||
void nowarn_vararg (void)
|
||||
{
|
||||
extern void fvararg (int, ...);
|
||||
|
||||
int i, a[2];
|
||||
|
||||
fvararg (0, &i, a, a + 2);
|
||||
}
|
||||
|
||||
|
||||
void nowarn_alloca_assign_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)alloca (n);
|
||||
p[0] = 0;
|
||||
fpci (p);
|
||||
}
|
||||
|
||||
void nowarn_alloca_assign_plus_cst_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)alloca (n);
|
||||
p[1] = 0;
|
||||
p[2] = 1;
|
||||
fpci (p + 1);
|
||||
}
|
||||
|
||||
void warn_alloca_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)alloca (n);
|
||||
fpci (p); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_alloca_assign_plus_cst_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)alloca (n);
|
||||
p[1] = 0;
|
||||
p[2] = 1;
|
||||
fpci (p + 3); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
|
||||
void nowarn_vla_assign_fpci (unsigned n)
|
||||
{
|
||||
int a[n];
|
||||
a[0] = 0;
|
||||
fpci (a);
|
||||
}
|
||||
|
||||
void nowarn_vla_assign_plus_cst_fpci (unsigned n)
|
||||
{
|
||||
int vla[n];
|
||||
vla[1] = 0;
|
||||
vla[2] = 1;
|
||||
fpci (vla + 1);
|
||||
}
|
||||
|
||||
void warn_vla_fpci (unsigned n)
|
||||
{
|
||||
int vla[n]; // { dg-message "declared here" "pr?????" { xfail *-*-* } }"
|
||||
fpci (vla); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_vla_assign_plus_cst_fpci (unsigned n)
|
||||
{
|
||||
int vla[n]; // { dg-message "declared here" "pr?????" { xfail *-*-* } }"
|
||||
vla[1] = 0;
|
||||
vla[2] = 1;
|
||||
fpci (vla + 3); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
|
||||
void nowarn_malloc_assign_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)malloc (n);
|
||||
p[0] = 0;
|
||||
fpci (p);
|
||||
}
|
||||
|
||||
void nowarn_malloc_assign_plus_cst_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)malloc (n);
|
||||
p[1] = 0;
|
||||
p[2] = 1;
|
||||
fpci (p + 1);
|
||||
}
|
||||
|
||||
void warn_malloc_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)malloc (n);
|
||||
fpci (p); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
|
||||
void warn_malloc_assign_plus_cst_fpci (unsigned n)
|
||||
{
|
||||
int *p = (int*)malloc (n); // { dg-message "allocated here" "pr?????" { xfail *-*-* } }"
|
||||
p[1] = 0;
|
||||
p[2] = 1;
|
||||
fpci (p + 3); // { dg-warning "\\\[-Wmaybe-uninitialized" }
|
||||
}
|
||||
145
gcc/testsuite/gcc.dg/uninit-33.c
Normal file
145
gcc/testsuite/gcc.dg/uninit-33.c
Normal file
@@ -0,0 +1,145 @@
|
||||
/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
|
||||
arguments
|
||||
Verify that passing pointers to uninitialized objects to arguments
|
||||
to functions declared with attribute access is diagnosed where expected.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O -Wall" } */
|
||||
|
||||
#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
|
||||
#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
|
||||
#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
|
||||
|
||||
RO (1) void fpri (int*); // { dg-message "in a call to 'fpri' declared with attribute 'access \\\(read_only, 1\\\)' here" }
|
||||
|
||||
RO (1) void fpcri (const int*);
|
||||
|
||||
RO (1, 2) void fpcri1_2 (const int*, int);
|
||||
|
||||
|
||||
void warn_scalar_fpri (void)
|
||||
{
|
||||
int i; // { dg-message "declared here" }
|
||||
fpri (&i); // { dg-warning "'i' is used uninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_scalar_plus_fpri (void)
|
||||
{
|
||||
int i;
|
||||
/* This gets a -Wstringop-overflow for reading past the end but not
|
||||
-Wuninitialized because there's nothing to initialize there. */
|
||||
fpri (&i + 1); // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
}
|
||||
|
||||
void nowarn_array_assign_fpcri (void)
|
||||
{
|
||||
int a[2];
|
||||
a[0] = 0;
|
||||
fpcri (a);
|
||||
}
|
||||
|
||||
void nowarn_array_init_fpcri (void)
|
||||
{
|
||||
int a[4] = { 0 };
|
||||
fpcri (a);
|
||||
}
|
||||
|
||||
void nowarn_array_compound_fpri (void)
|
||||
{
|
||||
fpri ((int[2]){ 0 });
|
||||
}
|
||||
|
||||
void nowarn_array_compound_fpcri (void)
|
||||
{
|
||||
fpcri ((int[3]){ 1 });
|
||||
}
|
||||
|
||||
void warn_scalar_fpcri (void)
|
||||
{
|
||||
int i;
|
||||
fpcri (&i); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_fpcri (void)
|
||||
{
|
||||
int a[4];
|
||||
fpcri (a); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_plus_cst_fpcri (void)
|
||||
{
|
||||
int a[4];
|
||||
fpcri (a + 1); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_plus_var_fpcri (int i)
|
||||
{
|
||||
int a[4];
|
||||
fpcri (a + i); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_struct_assign_fpcri (void)
|
||||
{
|
||||
struct { int a, b; } s;
|
||||
s.a = 0;
|
||||
fpcri (&s.a);
|
||||
}
|
||||
|
||||
void warn_struct_assign_fpcri (void)
|
||||
{
|
||||
struct { int a, b; } s;
|
||||
s.a = 0;
|
||||
fpcri (&s.b); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_struct_init_fpcri (void)
|
||||
{
|
||||
struct { int a, b; } s = { 0 };
|
||||
fpcri (&s.a);
|
||||
fpcri (&s.b);
|
||||
}
|
||||
|
||||
void nowarn_struct_compound_fpcri (void)
|
||||
{
|
||||
struct S { int a, b; };
|
||||
fpcri (&(struct S){ }.a);
|
||||
fpcri (&(struct S){ }.b);
|
||||
}
|
||||
|
||||
|
||||
void nowarn_scalar_fpcri1_2 (void)
|
||||
{
|
||||
int i;
|
||||
fpcri1_2 (&i, 0);
|
||||
}
|
||||
|
||||
void nowarn_array_assign_fpcri1_2 (void)
|
||||
{
|
||||
int a[2];
|
||||
a[0] = 0;
|
||||
fpcri1_2 (a, 1);
|
||||
}
|
||||
|
||||
void nowarn_array_assign_fpcri1_2_plus_cst (void)
|
||||
{
|
||||
int a[3];
|
||||
a[1] = 0;
|
||||
fpcri1_2 (a + 1, 1);
|
||||
}
|
||||
|
||||
void nowarn_array_init_fpcri1_2 (void)
|
||||
{
|
||||
int a[4] = { 0 };
|
||||
fpcri1_2 (a, 2);
|
||||
}
|
||||
|
||||
void warn_array_fpcri1_2_rd1 (void)
|
||||
{
|
||||
int a[4];
|
||||
fpcri1_2 (a, 1); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_fpcri1_2_rd2 (void)
|
||||
{
|
||||
int a[4];
|
||||
fpcri1_2 (a, 2); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
58
gcc/testsuite/gcc.dg/uninit-34.c
Normal file
58
gcc/testsuite/gcc.dg/uninit-34.c
Normal file
@@ -0,0 +1,58 @@
|
||||
/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
|
||||
arguments
|
||||
Verify that passing pointers to uninitialized objects to arguments
|
||||
to functions declared with attribute access is diagnosed where expected.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O -Wall" } */
|
||||
|
||||
#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
|
||||
|
||||
RW (1) RW (3) void
|
||||
f4pi (int*, int*, int*, int*); // { dg-message "in a call to 'f4pi' declared with attribute 'access \\\(read_write, \[13\]\\\)'" }
|
||||
|
||||
|
||||
void nowarn_scalar (void)
|
||||
{
|
||||
int i1 = 0, i2, i3 = 1, i4;
|
||||
f4pi (&i1, &i2, &i3, &i4);
|
||||
}
|
||||
|
||||
void warn_scalar_1 (void)
|
||||
{
|
||||
int i1; // { dg-message "declared here" }
|
||||
int i2, i3 = 1, i4;
|
||||
|
||||
f4pi (&i1, &i2, &i3, &i4); // { dg-warning "'i1' may be used uninitialized" }
|
||||
}
|
||||
|
||||
void warn_scalar_2 (void)
|
||||
{
|
||||
int j1 = 0, j2, j4;
|
||||
int j3;
|
||||
|
||||
f4pi (&j1, &j2, &j3, &j4); // { dg-warning "'j3' may be used uninitialized" }
|
||||
}
|
||||
|
||||
|
||||
void nowarn_array_init (void)
|
||||
{
|
||||
int a1[4] = { 0 }, a2[5], a3[6] = { 0 }, a4[7];
|
||||
|
||||
f4pi (a1, a2, a3, a4);
|
||||
}
|
||||
|
||||
void warn_array_1 (void)
|
||||
{
|
||||
int a1[4]; // { dg-message "'a1' declared here" }
|
||||
int a2[5], a3[6] = { 0 }, a4[7];
|
||||
|
||||
f4pi (a1, a2, a3, a4); // { dg-warning "'a1' may be used uninitialized" }
|
||||
}
|
||||
|
||||
void warn_array_2 (void)
|
||||
{
|
||||
int a1[4] = { 0 }, a2[5], a4[7];
|
||||
int a3[6]; // { dg-message "'a3' declared here" }
|
||||
|
||||
f4pi (a1, a2, a3, a4); // { dg-warning "'a3' may be used uninitialized" }
|
||||
}
|
||||
237
gcc/testsuite/gcc.dg/uninit-36.c
Normal file
237
gcc/testsuite/gcc.dg/uninit-36.c
Normal file
@@ -0,0 +1,237 @@
|
||||
/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
|
||||
arguments
|
||||
Verify that passing pointers to uninitialized objects to const
|
||||
arguments to built-ins is diagnosed where expected.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O -Wall" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
void* alloca (size_t);
|
||||
void* malloc (size_t);
|
||||
void* realloc (void*, size_t);
|
||||
|
||||
void* memcpy (void*, const void*, size_t);
|
||||
char* strcpy (char*, const char*);
|
||||
size_t strlen (const char*);
|
||||
|
||||
void sink (void*);
|
||||
|
||||
void nowarn_array_memcpy (void *d, unsigned n)
|
||||
{
|
||||
int a[2];
|
||||
/* Diagnose this? */
|
||||
memcpy (d, a, n /* Non-constant to avoid folding into MEM_REF. */);
|
||||
}
|
||||
|
||||
void nowarn_array_plus_cst_memcpy (void *d, unsigned n)
|
||||
{
|
||||
int a[3];
|
||||
/* Diagnose this? */
|
||||
memcpy (d, a + 1, n);
|
||||
}
|
||||
|
||||
void nowarn_array_plus_var_memcpy (void *d, unsigned n, int i)
|
||||
{
|
||||
int a[4];
|
||||
/* Diagnose this? */
|
||||
memcpy (d, a + i, n);
|
||||
}
|
||||
|
||||
void nowarn_array_assign_memcpy (char *d, unsigned n)
|
||||
{
|
||||
int a[3];
|
||||
a[1] = 3;
|
||||
memcpy (d, a, n);
|
||||
}
|
||||
|
||||
void nowarn_array_init_memcpy (char *d, unsigned n)
|
||||
{
|
||||
int a[4] = { 0 };
|
||||
memcpy (d, a, n);
|
||||
}
|
||||
|
||||
void nowarn_array_compound_memcpy (void *d, unsigned n)
|
||||
{
|
||||
memcpy (d, (int[2]){ 0 }, n);
|
||||
}
|
||||
|
||||
void nowarn_struct_assign_memcpy (void *d, unsigned n)
|
||||
{
|
||||
struct S { int a, b, c, d; } s;
|
||||
s.b = 1;
|
||||
s.d = 2;
|
||||
memcpy (d, &s, n);
|
||||
}
|
||||
|
||||
|
||||
void nowarn_array_init_strcpy (char *d[], unsigned n)
|
||||
{
|
||||
char a[8] = "012";
|
||||
|
||||
strcpy (d[0], a);
|
||||
strcpy (d[1], a + 1);
|
||||
strcpy (d[1], a + 2);
|
||||
strcpy (d[1], a + 3);
|
||||
strcpy (d[1], a + 4);
|
||||
strcpy (d[1], a + 5);
|
||||
strcpy (d[1], a + 6);
|
||||
strcpy (d[1], a + 7);
|
||||
}
|
||||
|
||||
|
||||
void nowarn_array_assign_strcpy (char *d[], unsigned n)
|
||||
{
|
||||
char a[8];
|
||||
a[0] = '0';
|
||||
a[1] = '1';
|
||||
a[2] = '2';
|
||||
a[3] = '\0';
|
||||
|
||||
strcpy (d[0], a);
|
||||
strcpy (d[1], a + 1);
|
||||
strcpy (d[1], a + 2);
|
||||
strcpy (d[1], a + 3);
|
||||
}
|
||||
|
||||
void warn_array_plus_cst_strcpy (char *d, unsigned n)
|
||||
{
|
||||
char a[8];
|
||||
a[0] = '1';
|
||||
a[1] = '2';
|
||||
a[2] = '3';
|
||||
a[3] = '\0';
|
||||
|
||||
strcpy (d, a + 4); // { dg-warning "\\\[-Wuninitialized" }
|
||||
strcpy (d, a + 5); // { dg-warning "\\\[-Wuninitialized" }
|
||||
strcpy (d, a + 6); // { dg-warning "\\\[-Wuninitialized" }
|
||||
strcpy (d, a + 7); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
void nowarn_array_plus_var_strcpy (char *d, int i)
|
||||
{
|
||||
char a[8];
|
||||
a[0] = '1';
|
||||
a[1] = '2';
|
||||
a[2] = '3';
|
||||
a[3] = '\0';
|
||||
|
||||
strcpy (d, a + i);
|
||||
}
|
||||
|
||||
|
||||
size_t nowarn_array_assign_strlen (const char *s)
|
||||
{
|
||||
char a[8];
|
||||
a[0] = s[0];
|
||||
a[1] = s[1];
|
||||
a[2] = s[2];
|
||||
a[3] = s[3];
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
n += strlen (a);
|
||||
n += strlen (a + 1);
|
||||
n += strlen (a + 2);
|
||||
n += strlen (a + 3);
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t warn_array_plus_cst_strlen (const char *s)
|
||||
{
|
||||
char a[8];
|
||||
a[0] = s[0];
|
||||
a[1] = s[1];
|
||||
a[2] = s[2];
|
||||
a[3] = s[3];
|
||||
|
||||
return strlen (a + 4); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
size_t nowarn_array_plus_var_strlen (const char *s, int i)
|
||||
{
|
||||
char a[8];
|
||||
a[0] = s[0];
|
||||
a[1] = s[1];
|
||||
a[2] = s[2];
|
||||
a[3] = s[3];
|
||||
|
||||
return strlen (a + i);
|
||||
}
|
||||
|
||||
|
||||
size_t nowarn_alloca_assign_strlen (int i)
|
||||
{
|
||||
char *p = (char*)alloca (8);
|
||||
p[i] = '\0';
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
size_t nowarn_alloca_escape_strlen (int i)
|
||||
{
|
||||
char *p = (char*)alloca (8);
|
||||
sink (p);
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
size_t warn_alloca_strlen (void)
|
||||
{
|
||||
char *p = (char*)alloca (8);
|
||||
return strlen (p); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
|
||||
size_t nowarn_malloc_assign_strlen (int i)
|
||||
{
|
||||
char *p = (char*)malloc (8);
|
||||
p[i] = '\0';
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
size_t nowarn_malloc_escape_strlen (int i)
|
||||
{
|
||||
char *p = (char*)malloc (8);
|
||||
sink (p);
|
||||
return strlen (p);
|
||||
}
|
||||
|
||||
size_t warn_malloc_strlen (void)
|
||||
{
|
||||
char *p = (char*)malloc (8);
|
||||
return strlen (p); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
|
||||
|
||||
size_t nowarn_realloc_strlen (void *p)
|
||||
{
|
||||
char *q = (char*)realloc (p, 8);
|
||||
return strlen (q);
|
||||
}
|
||||
|
||||
|
||||
size_t nowarn_vla_assign_strlen (int n, int i)
|
||||
{
|
||||
char vla[n];
|
||||
vla[i] = '\0';
|
||||
return strlen (vla);
|
||||
}
|
||||
|
||||
size_t nowarn_vla_strcpy_strlen (int n, const char *s, int i)
|
||||
{
|
||||
char vla[n];
|
||||
strcpy (vla, s);
|
||||
return strlen (vla + i);
|
||||
}
|
||||
|
||||
size_t nowarn_vla_escape_strlen (int n, int i)
|
||||
{
|
||||
char vla[n];
|
||||
sink (vla);
|
||||
return strlen (vla);
|
||||
}
|
||||
|
||||
size_t warn_vla_strlen (unsigned n)
|
||||
{
|
||||
char vla[n];
|
||||
return strlen (vla); // { dg-warning "\\\[-Wuninitialized" }
|
||||
}
|
||||
@@ -9,7 +9,7 @@ void
|
||||
baz (void)
|
||||
{
|
||||
int i;
|
||||
if (i) /* { dg-warning "'i' is used uninitialized in this function" } */
|
||||
if (i) /* { dg-warning "'i' is used uninitialized" } */
|
||||
bar (i);
|
||||
foo (&i);
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
int sys_msgctl (void)
|
||||
{
|
||||
struct { int mode; } setbuf;
|
||||
return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used uninitialized in this function" } */
|
||||
return setbuf.mode; /* { dg-warning "'setbuf\.mode' is used uninitialized" } */
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ extern void baz (int *);
|
||||
int
|
||||
foo (int i)
|
||||
{
|
||||
int j; /* { dg-warning "'j' may be used uninitialized in this function" "uninitialized" { xfail *-*-* } } */
|
||||
int j; /* { dg-warning "'j' may be used uninitialized" "uninitialized" { xfail *-*-* } } */
|
||||
|
||||
if (bar (i)) {
|
||||
baz (&j);
|
||||
@@ -18,7 +18,7 @@ foo (int i)
|
||||
|
||||
int foo2( void ) {
|
||||
int rc;
|
||||
return rc; /* { dg-warning "'rc' is used uninitialized in this function" } */
|
||||
return rc; /* { dg-warning "'rc' is used uninitialized" } */
|
||||
*&rc = 0;
|
||||
}
|
||||
|
||||
@@ -27,16 +27,16 @@ void frob(int *pi);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized in this function" } */
|
||||
int i;
|
||||
printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized" } */
|
||||
frob(&i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo3(int*);
|
||||
void bar3(void) {
|
||||
int x;
|
||||
if(x) /* { dg-warning "'x' is used uninitialized in this function" } */
|
||||
foo3(&x);
|
||||
void bar3(void) {
|
||||
int x;
|
||||
if(x) /* { dg-warning "'x' is used uninitialized" } */
|
||||
foo3(&x);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ extern void baz (int *);
|
||||
int
|
||||
foo (int i)
|
||||
{
|
||||
int j; /* { dg-warning "'j' may be used uninitialized in this function" "uninitialized" { xfail *-*-* } } */
|
||||
int j; /* { dg-warning "'j' may be used uninitialized" "uninitialized" { xfail *-*-* } } */
|
||||
|
||||
if (bar (i)) {
|
||||
if (bar (i)) {
|
||||
baz (&j);
|
||||
} else {
|
||||
}
|
||||
@@ -19,7 +19,7 @@ foo (int i)
|
||||
|
||||
int foo2( void ) {
|
||||
int rc;
|
||||
return rc; /* { dg-warning "'rc' is used uninitialized in this function" } */
|
||||
return rc; /* { dg-warning "'rc' is used uninitialized" } */
|
||||
*&rc = 0;
|
||||
}
|
||||
|
||||
@@ -28,16 +28,16 @@ void frob(int *pi);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized in this function" } */
|
||||
int i;
|
||||
printf("i = %d\n", i); /* { dg-warning "'i' is used uninitialized" } */
|
||||
frob(&i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo3(int*);
|
||||
void bar3(void) {
|
||||
int x;
|
||||
if(x) /* { dg-warning "'x' is used uninitialized in this function" "uninitialized" } */
|
||||
foo3(&x);
|
||||
void bar3(void) {
|
||||
int x;
|
||||
if(x) /* { dg-warning "'x' is used uninitialized" "uninitialized" } */
|
||||
foo3(&x);
|
||||
}
|
||||
|
||||
63
gcc/testsuite/gcc.dg/uninit-pr95136.c
Normal file
63
gcc/testsuite/gcc.dg/uninit-pr95136.c
Normal file
@@ -0,0 +1,63 @@
|
||||
/* PR middle-end/95136 - missing -Wuninitialized on an array access with
|
||||
a variable offset
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O -Wall" } */
|
||||
|
||||
#define NOIPA __attribute__ ((noipa))
|
||||
|
||||
NOIPA int a1_addr_varidx_plus_cst (int i)
|
||||
{
|
||||
int a[4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[i + 1];
|
||||
return *p; // { dg-warning "'a|a\\\[<unknown>]' is used uninitialized" }
|
||||
}
|
||||
|
||||
NOIPA int a1_plus_addr_varidx_cst (int i)
|
||||
{
|
||||
int a[4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[i] + 1;
|
||||
return *p; // { dg-warning "'a' is used uninitialized" }
|
||||
}
|
||||
|
||||
NOIPA int a1_plus_addr_cstidx_var (int i)
|
||||
{
|
||||
int a[4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[1] + i;
|
||||
return *p; // { dg-warning "'a' is used uninitialized" }
|
||||
}
|
||||
|
||||
NOIPA int a1_plus_addr_varidx_var (int i, int j)
|
||||
{
|
||||
int a[4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[i] + j;
|
||||
return *p; // { dg-warning "'a' is used uninitialized" }
|
||||
}
|
||||
|
||||
|
||||
NOIPA int a2_addr_varidx_plus_cst (int i, int j)
|
||||
{
|
||||
int a[4][4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[i + 1][j + 1];
|
||||
return *p; // { dg-warning "'a|a\\\[<unknown>]\\\[<unknown>]' is used uninitialized" }
|
||||
}
|
||||
|
||||
NOIPA int a2_plus_addr_varidx_cst (int i, int j)
|
||||
{
|
||||
int a[4][4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[i][j] + 1;
|
||||
return *p; // { dg-warning "'a' is used uninitialized" }
|
||||
}
|
||||
|
||||
NOIPA int a2_plus_addr_cstidx_var (int i)
|
||||
{
|
||||
int a[4][4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[1][1] + i;
|
||||
return *p; // { dg-warning "'a' is used uninitialized" }
|
||||
}
|
||||
|
||||
NOIPA int a2_plus_addr_varidx_var (int i, int j, int k)
|
||||
{
|
||||
int a[4][4]; // { dg-message "'a' declared here" }
|
||||
int *p = &a[i][j] + k;
|
||||
return *p; // { dg-warning "'a' is used uninitialized" }
|
||||
}
|
||||
@@ -12,5 +12,5 @@
|
||||
logical :: r
|
||||
type(event), pointer :: myEvent
|
||||
allocate(myEvent)
|
||||
r=myEvent%task()
|
||||
r=myEvent%task() ! { dg-warning "uninitialized" }
|
||||
end
|
||||
|
||||
@@ -4,13 +4,13 @@ subroutine acc_parallel
|
||||
implicit none
|
||||
integer :: i, j, k
|
||||
|
||||
!$acc parallel num_gangs(i) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc parallel num_gangs(i) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end parallel
|
||||
|
||||
!$acc parallel num_workers(j) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc parallel num_workers(j) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end parallel
|
||||
|
||||
!$acc parallel vector_length(k) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc parallel vector_length(k) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end parallel
|
||||
end subroutine acc_parallel
|
||||
|
||||
@@ -18,12 +18,12 @@ subroutine acc_kernels
|
||||
implicit none
|
||||
integer :: i, j, k
|
||||
|
||||
!$acc kernels num_gangs(i) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc kernels num_gangs(i) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end kernels
|
||||
|
||||
!$acc kernels num_workers(j) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc kernels num_workers(j) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end kernels
|
||||
|
||||
!$acc kernels vector_length(k) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc kernels vector_length(k) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end kernels
|
||||
end subroutine acc_kernels
|
||||
|
||||
@@ -12,7 +12,7 @@ end subroutine test
|
||||
subroutine test2
|
||||
INTEGER :: i
|
||||
|
||||
!$acc parallel firstprivate (i) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc parallel firstprivate (i) ! { dg-warning "is used uninitialized" }
|
||||
i = 1
|
||||
!$acc end parallel
|
||||
end subroutine test2
|
||||
|
||||
@@ -6,15 +6,15 @@ program test
|
||||
logical :: b, b2, b3, b4
|
||||
integer :: data, data2
|
||||
|
||||
!$acc parallel if(b) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc parallel if(b) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end parallel
|
||||
|
||||
!$acc kernels if(b2) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc kernels if(b2) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end kernels
|
||||
|
||||
!$acc data if(b3) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc data if(b3) ! { dg-warning "is used uninitialized" }
|
||||
!$acc end data
|
||||
|
||||
!$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized in this function" }
|
||||
!$acc update if(b4) self(data2) ! { dg-warning "is used uninitialized" }
|
||||
|
||||
end program test
|
||||
|
||||
@@ -11,13 +11,13 @@ end program foo
|
||||
subroutine p1
|
||||
complex :: c5
|
||||
complex :: c6
|
||||
c5 = (c5) ! { dg-warning "used uninitialized in this" }
|
||||
c6 = c6 ! { dg-warning "used uninitialized in this" }
|
||||
c5 = (c5) ! { dg-warning "used uninitialized" }
|
||||
c6 = c6 ! { dg-warning "used uninitialized" }
|
||||
end subroutine p1
|
||||
|
||||
subroutine q1
|
||||
real :: r5
|
||||
real :: r6
|
||||
r5 = (r5) ! { dg-warning "used uninitialized in this" }
|
||||
r6 = r6 ! { dg-warning "used uninitialized in this" }
|
||||
r5 = (r5) ! { dg-warning "used uninitialized" }
|
||||
r6 = r6 ! { dg-warning "used uninitialized" }
|
||||
end subroutine q1
|
||||
|
||||
@@ -33,6 +33,9 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "tree-ssa.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "cfghooks.h"
|
||||
#include "attribs.h"
|
||||
#include "builtins.h"
|
||||
#include "calls.h"
|
||||
|
||||
/* This implements the pass that does predicate aware warning on uses of
|
||||
possibly uninitialized variables. The pass first collects the set of
|
||||
@@ -217,19 +220,373 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
warn_uninitialized_vars (bool warn_possibly_uninitialized)
|
||||
/* Counters and limits controlling the the depth of analysis and
|
||||
strictness of the warning. */
|
||||
struct wlimits
|
||||
{
|
||||
/* Number of VDEFs encountered. */
|
||||
unsigned int vdef_cnt;
|
||||
/* Number of statements examined by walk_aliased_vdefs. */
|
||||
unsigned int oracle_cnt;
|
||||
/* Limit on the number of statements visited by walk_aliased_vdefs. */
|
||||
unsigned limit;
|
||||
/* Set when basic block with statement is executed unconditionally. */
|
||||
bool always_executed;
|
||||
/* Set to issue -Wmaybe-uninitialized. */
|
||||
bool wmaybe_uninit;
|
||||
};
|
||||
|
||||
/* Determine if REF references an uninitialized operand and diagnose
|
||||
it if so. */
|
||||
|
||||
static tree
|
||||
maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
|
||||
wlimits &wlims)
|
||||
{
|
||||
bool has_bit_insert = false;
|
||||
use_operand_p luse_p;
|
||||
imm_use_iterator liter;
|
||||
|
||||
if (TREE_NO_WARNING (rhs))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Do not warn if the base was marked so or this is a
|
||||
hard register var. */
|
||||
tree base = ao_ref_base (&ref);
|
||||
if ((VAR_P (base)
|
||||
&& DECL_HARD_REGISTER (base))
|
||||
|| TREE_NO_WARNING (base))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Do not warn if the access is fully outside of the variable. */
|
||||
poly_int64 decl_size;
|
||||
if (DECL_P (base)
|
||||
&& ((known_size_p (ref.size)
|
||||
&& known_eq (ref.max_size, ref.size)
|
||||
&& known_le (ref.offset + ref.size, 0))
|
||||
|| (known_ge (ref.offset, 0)
|
||||
&& DECL_SIZE (base)
|
||||
&& poly_int_tree_p (DECL_SIZE (base), &decl_size)
|
||||
&& known_le (decl_size, ref.offset))))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Do not warn if the result of the access is then used for
|
||||
a BIT_INSERT_EXPR. */
|
||||
if (lhs && TREE_CODE (lhs) == SSA_NAME)
|
||||
FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs)
|
||||
{
|
||||
gimple *use_stmt = USE_STMT (luse_p);
|
||||
/* BIT_INSERT_EXPR first operand should not be considered
|
||||
a use for the purpose of uninit warnings. */
|
||||
if (gassign *ass = dyn_cast <gassign *> (use_stmt))
|
||||
{
|
||||
if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR
|
||||
&& luse_p->use == gimple_assign_rhs1_ptr (ass))
|
||||
{
|
||||
has_bit_insert = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_bit_insert)
|
||||
return NULL_TREE;
|
||||
|
||||
/* Limit the walking to a constant number of stmts after
|
||||
we overcommit quadratic behavior for small functions
|
||||
and O(n) behavior. */
|
||||
if (wlims.oracle_cnt > 128 * 128
|
||||
&& wlims.oracle_cnt > wlims.vdef_cnt * 2)
|
||||
wlims.limit = 32;
|
||||
|
||||
check_defs_data data;
|
||||
bool fentry_reached = false;
|
||||
data.found_may_defs = false;
|
||||
tree use = gimple_vuse (stmt);
|
||||
if (!use)
|
||||
return NULL_TREE;
|
||||
int res = walk_aliased_vdefs (&ref, use,
|
||||
check_defs, &data, NULL,
|
||||
&fentry_reached, wlims.limit);
|
||||
if (res == -1)
|
||||
{
|
||||
wlims.oracle_cnt += wlims.limit;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
wlims.oracle_cnt += res;
|
||||
if (data.found_may_defs)
|
||||
return NULL_TREE;
|
||||
|
||||
bool found_alloc = false;
|
||||
|
||||
if (fentry_reached)
|
||||
{
|
||||
if (TREE_CODE (base) == MEM_REF)
|
||||
base = TREE_OPERAND (base, 0);
|
||||
|
||||
/* Follow the chain of SSA_NAME assignments looking for an alloca
|
||||
call (or VLA) or malloc/realloc, or for decls. If any is found
|
||||
(and in the latter case, the operand is a local variable) issue
|
||||
a warning. */
|
||||
while (TREE_CODE (base) == SSA_NAME)
|
||||
{
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (base);
|
||||
|
||||
if (is_gimple_call (def_stmt)
|
||||
&& gimple_call_builtin_p (def_stmt))
|
||||
{
|
||||
/* Detect uses of uninitialized alloca/VLAs. */
|
||||
tree fndecl = gimple_call_fndecl (def_stmt);
|
||||
const built_in_function fncode = DECL_FUNCTION_CODE (fndecl);
|
||||
if (fncode == BUILT_IN_ALLOCA
|
||||
|| fncode == BUILT_IN_ALLOCA_WITH_ALIGN
|
||||
|| fncode == BUILT_IN_MALLOC)
|
||||
found_alloc = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_gimple_assign (def_stmt))
|
||||
break;
|
||||
|
||||
tree_code code = gimple_assign_rhs_code (def_stmt);
|
||||
if (code != ADDR_EXPR && code != POINTER_PLUS_EXPR)
|
||||
break;
|
||||
|
||||
base = gimple_assign_rhs1 (def_stmt);
|
||||
if (TREE_CODE (base) == ADDR_EXPR)
|
||||
base = TREE_OPERAND (base, 0);
|
||||
|
||||
if (DECL_P (base)
|
||||
|| TREE_CODE (base) == COMPONENT_REF)
|
||||
rhs = base;
|
||||
|
||||
if (TREE_CODE (base) == MEM_REF)
|
||||
base = TREE_OPERAND (base, 0);
|
||||
|
||||
if (tree ba = get_base_address (base))
|
||||
base = ba;
|
||||
}
|
||||
|
||||
/* Replace the RHS expression with BASE so that it
|
||||
refers to it in the diagnostic (instead of to
|
||||
'<unknown>'). */
|
||||
if (DECL_P (base)
|
||||
&& EXPR_P (rhs)
|
||||
&& TREE_CODE (rhs) != COMPONENT_REF)
|
||||
rhs = base;
|
||||
}
|
||||
|
||||
/* Do not warn if it can be initialized outside this function.
|
||||
If we did not reach function entry then we found killing
|
||||
clobbers on all paths to entry. */
|
||||
if (!found_alloc
|
||||
&& fentry_reached
|
||||
/* ??? We'd like to use ref_may_alias_global_p but that
|
||||
excludes global readonly memory and thus we get bogus
|
||||
warnings from p = cond ? "a" : "b" for example. */
|
||||
&& (!VAR_P (base)
|
||||
|| is_global_var (base)))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Strip the address-of expression from arrays passed to functions. */
|
||||
if (TREE_CODE (rhs) == ADDR_EXPR)
|
||||
rhs = TREE_OPERAND (rhs, 0);
|
||||
|
||||
/* Check again since RHS may have changed above. */
|
||||
if (TREE_NO_WARNING (rhs))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Avoid warning about empty types such as structs with no members.
|
||||
The first_field() test is important for C++ where the predicate
|
||||
alone isn't always sufficient. */
|
||||
tree rhstype = TREE_TYPE (rhs);
|
||||
if (TYPE_EMPTY_P (rhstype)
|
||||
|| (RECORD_OR_UNION_TYPE_P (rhstype)
|
||||
&& (!first_field (rhstype)
|
||||
|| default_is_empty_record (rhstype))))
|
||||
return NULL_TREE;
|
||||
|
||||
bool warned = false;
|
||||
/* We didn't find any may-defs so on all paths either
|
||||
reached function entry or a killing clobber. */
|
||||
location_t location
|
||||
= linemap_resolve_location (line_table, gimple_location (stmt),
|
||||
LRK_SPELLING_LOCATION, NULL);
|
||||
if (wlims.always_executed)
|
||||
{
|
||||
if (warning_at (location, OPT_Wuninitialized,
|
||||
"%G%qE is used uninitialized", stmt, rhs))
|
||||
{
|
||||
/* ??? This is only effective for decls as in
|
||||
gcc.dg/uninit-B-O0.c. Avoid doing this for maybe-uninit
|
||||
uses or accesses by functions as it may hide important
|
||||
locations. */
|
||||
if (lhs)
|
||||
TREE_NO_WARNING (rhs) = 1;
|
||||
warned = true;
|
||||
}
|
||||
}
|
||||
else if (wlims.wmaybe_uninit)
|
||||
warned = warning_at (location, OPT_Wmaybe_uninitialized,
|
||||
"%G%qE may be used uninitialized", stmt, rhs);
|
||||
|
||||
return warned ? base : NULL_TREE;
|
||||
}
|
||||
|
||||
|
||||
/* Diagnose passing addresses of uninitialized objects to either const
|
||||
pointer arguments to functions, or to functions declared with attribute
|
||||
access implying read access to those objects. */
|
||||
|
||||
static void
|
||||
maybe_warn_pass_by_reference (gimple *stmt, wlimits &wlims)
|
||||
{
|
||||
if (!wlims.wmaybe_uninit)
|
||||
return;
|
||||
|
||||
unsigned nargs = gimple_call_num_args (stmt);
|
||||
if (!nargs)
|
||||
return;
|
||||
|
||||
tree fndecl = gimple_call_fndecl (stmt);
|
||||
tree fntype = gimple_call_fntype (stmt);
|
||||
if (!fntype)
|
||||
return;
|
||||
|
||||
const built_in_function fncode
|
||||
= (fndecl && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)
|
||||
? DECL_FUNCTION_CODE (fndecl) : (built_in_function)BUILT_IN_LAST);
|
||||
|
||||
if (fncode == BUILT_IN_MEMCPY || fncode == BUILT_IN_MEMMOVE)
|
||||
/* Avoid diagnosing calls to raw memory functions (this is overly
|
||||
permissive; consider tightening it up). */
|
||||
return;
|
||||
|
||||
/* Save the current warning setting and replace it either a "maybe"
|
||||
when passing addresses of uninitialized variables to const-qualified
|
||||
pointers or arguments declared with attribute read_write, or with
|
||||
a "certain" when passing them to arguments declared with attribute
|
||||
read_only. */
|
||||
const bool save_always_executed = wlims.always_executed;
|
||||
|
||||
/* Map of attribute access specifications for function arguments. */
|
||||
rdwr_map rdwr_idx;
|
||||
init_attr_rdwr_indices (&rdwr_idx, fntype);
|
||||
|
||||
tree argtype;
|
||||
unsigned argno = 0;
|
||||
function_args_iterator it;
|
||||
|
||||
FOREACH_FUNCTION_ARGS (fntype, argtype, it)
|
||||
{
|
||||
++argno;
|
||||
|
||||
if (!POINTER_TYPE_P (argtype))
|
||||
continue;
|
||||
|
||||
tree access_size = NULL_TREE;
|
||||
attr_access *access = rdwr_idx.get (argno - 1);
|
||||
if (access)
|
||||
{
|
||||
if (access->mode == attr_access::none
|
||||
|| access->mode == attr_access::write_only)
|
||||
continue;
|
||||
if (save_always_executed && access->mode == attr_access::read_only)
|
||||
/* Attribute read_only arguments imply read access. */
|
||||
wlims.always_executed = true;
|
||||
else
|
||||
/* Attribute read_write arguments are documented as requiring
|
||||
initialized objects but it's expected that aggregates may
|
||||
be only partially initialized regardless. */
|
||||
wlims.always_executed = false;
|
||||
|
||||
if (access->sizarg < nargs)
|
||||
access_size = gimple_call_arg (stmt, access->sizarg);
|
||||
}
|
||||
else if (!TYPE_READONLY (TREE_TYPE (argtype)))
|
||||
continue;
|
||||
else if (save_always_executed && fncode != BUILT_IN_LAST)
|
||||
/* Const-qualified arguments to built-ins imply read access. */
|
||||
wlims.always_executed = true;
|
||||
else
|
||||
/* Const-qualified arguments to ordinary functions imply a likely
|
||||
(but not definitive) read access. */
|
||||
wlims.always_executed = false;
|
||||
|
||||
tree arg = gimple_call_arg (stmt, argno - 1);
|
||||
|
||||
ao_ref ref;
|
||||
ao_ref_init_from_ptr_and_size (&ref, arg, access_size);
|
||||
tree argbase = maybe_warn_operand (ref, stmt, NULL_TREE, arg, wlims);
|
||||
if (!argbase)
|
||||
continue;
|
||||
|
||||
if (access)
|
||||
{
|
||||
const char* const mode = (access->mode == attr_access::read_only
|
||||
? "read_only" : "read_write");
|
||||
char attrstr[80];
|
||||
int n = sprintf (attrstr, "access (%s, %u", mode, argno);
|
||||
if (access->sizarg < UINT_MAX)
|
||||
sprintf (attrstr + n, ", %u)", access->sizarg);
|
||||
else
|
||||
strcpy (attrstr + n, ")");
|
||||
|
||||
if (fndecl)
|
||||
{
|
||||
location_t loc = DECL_SOURCE_LOCATION (fndecl);
|
||||
inform (loc, "in a call to %qD declared "
|
||||
"with attribute %<access (%s, %u)%> here",
|
||||
fndecl, mode, argno);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle calls through function pointers. */
|
||||
location_t loc = gimple_location (stmt);
|
||||
inform (loc, "in a call to %qT declared with "
|
||||
"attribute %<access (%s, %u)%>",
|
||||
fntype, mode, argno);
|
||||
}
|
||||
}
|
||||
else if (fndecl)
|
||||
{
|
||||
location_t loc = DECL_SOURCE_LOCATION (fndecl);
|
||||
inform (loc, "by argument %u of type %qT to %qD declared here",
|
||||
argno, argtype, fndecl);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle calls through function pointers. */
|
||||
location_t loc = gimple_location (stmt);
|
||||
inform (loc, "by argument %u of type %qT to %qT",
|
||||
argno, argtype, fntype);
|
||||
}
|
||||
|
||||
if (DECL_P (argbase))
|
||||
{
|
||||
location_t loc = DECL_SOURCE_LOCATION (argbase);
|
||||
inform (loc, "%qD declared here", argbase);
|
||||
}
|
||||
}
|
||||
|
||||
wlims.always_executed = save_always_executed;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
warn_uninitialized_vars (bool wmaybe_uninit)
|
||||
{
|
||||
/* Counters and limits controlling the the depth of the warning. */
|
||||
wlimits wlims = { };
|
||||
wlims.wmaybe_uninit = wmaybe_uninit;
|
||||
|
||||
gimple_stmt_iterator gsi;
|
||||
basic_block bb;
|
||||
unsigned int vdef_cnt = 0;
|
||||
unsigned int oracle_cnt = 0;
|
||||
unsigned limit = 0;
|
||||
|
||||
FOR_EACH_BB_FN (bb, cfun)
|
||||
{
|
||||
basic_block succ = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
|
||||
bool always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb);
|
||||
wlims.always_executed = dominated_by_p (CDI_POST_DOMINATORS, succ, bb);
|
||||
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
|
||||
{
|
||||
gimple *stmt = gsi_stmt (gsi);
|
||||
@@ -253,131 +610,42 @@ warn_uninitialized_vars (bool warn_possibly_uninitialized)
|
||||
continue;
|
||||
}
|
||||
use = USE_FROM_PTR (use_p);
|
||||
if (always_executed)
|
||||
if (wlims.always_executed)
|
||||
warn_uninit (OPT_Wuninitialized, use, SSA_NAME_VAR (use),
|
||||
SSA_NAME_VAR (use),
|
||||
"%qD is used uninitialized in this function", stmt,
|
||||
"%qD is used uninitialized", stmt,
|
||||
UNKNOWN_LOCATION);
|
||||
else if (warn_possibly_uninitialized)
|
||||
else if (wmaybe_uninit)
|
||||
warn_uninit (OPT_Wmaybe_uninitialized, use, SSA_NAME_VAR (use),
|
||||
SSA_NAME_VAR (use),
|
||||
"%qD may be used uninitialized in this function",
|
||||
"%qD may be used uninitialized",
|
||||
stmt, UNKNOWN_LOCATION);
|
||||
}
|
||||
|
||||
/* For limiting the alias walk below we count all
|
||||
vdefs in the function. */
|
||||
if (gimple_vdef (stmt))
|
||||
vdef_cnt++;
|
||||
wlims.vdef_cnt++;
|
||||
|
||||
if (gimple_assign_load_p (stmt)
|
||||
&& gimple_has_location (stmt))
|
||||
if (is_gimple_call (stmt))
|
||||
maybe_warn_pass_by_reference (stmt, wlims);
|
||||
else if (gimple_assign_load_p (stmt)
|
||||
&& gimple_has_location (stmt))
|
||||
{
|
||||
tree rhs = gimple_assign_rhs1 (stmt);
|
||||
tree lhs = gimple_assign_lhs (stmt);
|
||||
bool has_bit_insert = false;
|
||||
use_operand_p luse_p;
|
||||
imm_use_iterator liter;
|
||||
|
||||
if (TREE_NO_WARNING (rhs))
|
||||
continue;
|
||||
|
||||
ao_ref ref;
|
||||
ao_ref_init (&ref, rhs);
|
||||
|
||||
/* Do not warn if the base was marked so or this is a
|
||||
hard register var. */
|
||||
tree base = ao_ref_base (&ref);
|
||||
if ((VAR_P (base)
|
||||
&& DECL_HARD_REGISTER (base))
|
||||
|| TREE_NO_WARNING (base))
|
||||
tree var = maybe_warn_operand (ref, stmt, lhs, rhs, wlims);
|
||||
if (!var)
|
||||
continue;
|
||||
|
||||
/* Do not warn if the access is fully outside of the
|
||||
variable. */
|
||||
poly_int64 decl_size;
|
||||
if (DECL_P (base)
|
||||
&& known_size_p (ref.size)
|
||||
&& ((known_eq (ref.max_size, ref.size)
|
||||
&& known_le (ref.offset + ref.size, 0))
|
||||
|| (known_ge (ref.offset, 0)
|
||||
&& DECL_SIZE (base)
|
||||
&& poly_int_tree_p (DECL_SIZE (base), &decl_size)
|
||||
&& known_le (decl_size, ref.offset))))
|
||||
continue;
|
||||
|
||||
/* Do not warn if the access is then used for a BIT_INSERT_EXPR. */
|
||||
if (TREE_CODE (lhs) == SSA_NAME)
|
||||
FOR_EACH_IMM_USE_FAST (luse_p, liter, lhs)
|
||||
{
|
||||
gimple *use_stmt = USE_STMT (luse_p);
|
||||
/* BIT_INSERT_EXPR first operand should not be considered
|
||||
a use for the purpose of uninit warnings. */
|
||||
if (gassign *ass = dyn_cast <gassign *> (use_stmt))
|
||||
{
|
||||
if (gimple_assign_rhs_code (ass) == BIT_INSERT_EXPR
|
||||
&& luse_p->use == gimple_assign_rhs1_ptr (ass))
|
||||
{
|
||||
has_bit_insert = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (has_bit_insert)
|
||||
continue;
|
||||
|
||||
/* Limit the walking to a constant number of stmts after
|
||||
we overcommit quadratic behavior for small functions
|
||||
and O(n) behavior. */
|
||||
if (oracle_cnt > 128 * 128
|
||||
&& oracle_cnt > vdef_cnt * 2)
|
||||
limit = 32;
|
||||
check_defs_data data;
|
||||
bool fentry_reached = false;
|
||||
data.found_may_defs = false;
|
||||
use = gimple_vuse (stmt);
|
||||
int res = walk_aliased_vdefs (&ref, use,
|
||||
check_defs, &data, NULL,
|
||||
&fentry_reached, limit);
|
||||
if (res == -1)
|
||||
if (DECL_P (var))
|
||||
{
|
||||
oracle_cnt += limit;
|
||||
continue;
|
||||
location_t loc = DECL_SOURCE_LOCATION (var);
|
||||
inform (loc, "%qD declared here", var);
|
||||
}
|
||||
oracle_cnt += res;
|
||||
if (data.found_may_defs)
|
||||
continue;
|
||||
/* Do not warn if it can be initialized outside this function.
|
||||
If we did not reach function entry then we found killing
|
||||
clobbers on all paths to entry. */
|
||||
if (fentry_reached
|
||||
/* ??? We'd like to use ref_may_alias_global_p but that
|
||||
excludes global readonly memory and thus we get bougs
|
||||
warnings from p = cond ? "a" : "b" for example. */
|
||||
&& (!VAR_P (base)
|
||||
|| is_global_var (base)))
|
||||
continue;
|
||||
|
||||
/* We didn't find any may-defs so on all paths either
|
||||
reached function entry or a killing clobber. */
|
||||
location_t location
|
||||
= linemap_resolve_location (line_table, gimple_location (stmt),
|
||||
LRK_SPELLING_LOCATION, NULL);
|
||||
if (always_executed)
|
||||
{
|
||||
if (warning_at (location, OPT_Wuninitialized,
|
||||
"%qE is used uninitialized in this function",
|
||||
rhs))
|
||||
/* ??? This is only effective for decls as in
|
||||
gcc.dg/uninit-B-O0.c. Avoid doing this for
|
||||
maybe-uninit uses as it may hide important
|
||||
locations. */
|
||||
TREE_NO_WARNING (rhs) = 1;
|
||||
}
|
||||
else if (warn_possibly_uninitialized)
|
||||
warning_at (location, OPT_Wmaybe_uninitialized,
|
||||
"%qE may be used uninitialized in this function",
|
||||
rhs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2665,7 +2933,7 @@ pass_late_warn_uninitialized::execute (function *fun)
|
||||
/* Re-do the plain uninitialized variable check, as optimization may have
|
||||
straightened control flow. Do this first so that we don't accidentally
|
||||
get a "may be" warning when we'd have seen an "is" warning later. */
|
||||
warn_uninitialized_vars (/*warn_possibly_uninitialized=*/1);
|
||||
warn_uninitialized_vars (/*warn_maybe_uninitialized=*/1);
|
||||
|
||||
timevar_push (TV_TREE_UNINIT);
|
||||
|
||||
@@ -2735,7 +3003,7 @@ execute_early_warn_uninitialized (void)
|
||||
optimization we need to warn here about "may be uninitialized". */
|
||||
calculate_dominance_info (CDI_POST_DOMINATORS);
|
||||
|
||||
warn_uninitialized_vars (/*warn_possibly_uninitialized=*/!optimize);
|
||||
warn_uninitialized_vars (/*warn_maybe_uninitialized=*/!optimize);
|
||||
|
||||
/* Post-dominator information cannot be reliably updated. Free it
|
||||
after the use. */
|
||||
|
||||
Reference in New Issue
Block a user