Add new gimple-ssa-warn-access pass.
gcc/ChangeLog: * Makefile.in (OBJS): Add gimple-ssa-warn-access.o and pointer-query.o. * attribs.h (fndecl_dealloc_argno): Move fndecl_dealloc_argno to tree.h. * builtins.c (compute_objsize_r): Move to pointer-query.cc. (access_ref::access_ref): Same. (access_ref::phi): Same. (access_ref::get_ref): Same. (access_ref::size_remaining): Same. (access_ref::offset_in_range): Same. (access_ref::add_offset): Same. (access_ref::inform_access): Same. (ssa_name_limit_t::visit_phi): Same. (ssa_name_limit_t::leave_phi): Same. (ssa_name_limit_t::next): Same. (ssa_name_limit_t::next_phi): Same. (ssa_name_limit_t::~ssa_name_limit_t): Same. (pointer_query::pointer_query): Same. (pointer_query::get_ref): Same. (pointer_query::put_ref): Same. (pointer_query::flush_cache): Same. (warn_string_no_nul): Move to gimple-ssa-warn-access.cc. (check_nul_terminated_array): Same. (unterminated_array): Same. (maybe_warn_for_bound): Same. (check_read_access): Same. (warn_for_access): Same. (get_size_range): Same. (check_access): Same. (gimple_call_alloc_size): Move to tree.c. (gimple_parm_array_size): Move to pointer-query.cc. (get_offset_range): Same. (gimple_call_return_array): Same. (handle_min_max_size): Same. (handle_array_ref): Same. (handle_mem_ref): Same. (compute_objsize): Same. (gimple_call_alloc_p): Move to gimple-ssa-warn-access.cc. (call_dealloc_argno): Same. (fndecl_dealloc_argno): Same. (new_delete_mismatch_p): Same. (matching_alloc_calls_p): Same. (warn_dealloc_offset): Same. (maybe_emit_free_warning): Same. * builtins.h (check_nul_terminated_array): Move to gimple-ssa-warn-access.h. (check_nul_terminated_array): Same. (warn_string_no_nul): Same. (unterminated_array): Same. (class ssa_name_limit_t): Same. (class pointer_query): Same. (struct access_ref): Same. (class range_query): Same. (struct access_data): Same. (gimple_call_alloc_size): Same. (gimple_parm_array_size): Same. (compute_objsize): Same. (class access_data): Same. (maybe_emit_free_warning): Same. * calls.c (initialize_argument_information): Remove call to maybe_emit_free_warning. * gimple-array-bounds.cc: Include new header.. * gimple-fold.c: Same. * gimple-ssa-sprintf.c: Same. * gimple-ssa-warn-restrict.c: Same. * passes.def: Add pass_warn_access. * tree-pass.h (make_pass_warn_access): Declare. * tree-ssa-strlen.c: Include new headers. * tree.c (fndecl_dealloc_argno): Move here from builtins.c. * tree.h (fndecl_dealloc_argno): Move here from attribs.h. * gimple-ssa-warn-access.cc: New file. * gimple-ssa-warn-access.h: New file. * pointer-query.cc: New file. * pointer-query.h: New file. gcc/cp/ChangeLog: * init.c: Include new header.
This commit is contained in:
parent
f471739e63
commit
2a837de28e
@ -1414,6 +1414,7 @@ OBJS = \
|
||||
gimple-ssa-store-merging.o \
|
||||
gimple-ssa-strength-reduction.o \
|
||||
gimple-ssa-sprintf.o \
|
||||
gimple-ssa-warn-access.o \
|
||||
gimple-ssa-warn-alloca.o \
|
||||
gimple-ssa-warn-restrict.o \
|
||||
gimple-streamer-in.o \
|
||||
@ -1524,6 +1525,7 @@ OBJS = \
|
||||
ordered-hash-map-tests.o \
|
||||
passes.o \
|
||||
plugin.o \
|
||||
pointer-query.o \
|
||||
postreload-gcse.o \
|
||||
postreload.o \
|
||||
predict.o \
|
||||
|
@ -316,6 +316,4 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
|
||||
extern attr_access *get_parm_access (rdwr_map &, tree,
|
||||
tree = current_function_decl);
|
||||
|
||||
extern unsigned fndecl_dealloc_argno (tree fndecl);
|
||||
|
||||
#endif // GCC_ATTRIBS_H
|
||||
|
3519
gcc/builtins.c
3519
gcc/builtins.c
File diff suppressed because it is too large
Load Diff
215
gcc/builtins.h
215
gcc/builtins.h
@ -149,223 +149,10 @@ extern bool target_char_cst_p (tree t, char *p);
|
||||
extern internal_fn associated_internal_fn (tree);
|
||||
extern internal_fn replacement_internal_fn (gcall *);
|
||||
|
||||
extern bool check_nul_terminated_array (tree, tree, tree = NULL_TREE);
|
||||
extern void warn_string_no_nul (location_t, tree, const char *, tree,
|
||||
tree, tree = NULL_TREE, bool = false,
|
||||
const wide_int[2] = NULL);
|
||||
extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
|
||||
extern bool builtin_with_linkage_p (tree);
|
||||
|
||||
/* Describes recursion limits used by functions that follow use-def
|
||||
chains of SSA_NAMEs. */
|
||||
|
||||
class ssa_name_limit_t
|
||||
{
|
||||
bitmap visited; /* Bitmap of visited SSA_NAMEs. */
|
||||
unsigned ssa_def_max; /* Longest chain of SSA_NAMEs to follow. */
|
||||
|
||||
/* Not copyable or assignable. */
|
||||
DISABLE_COPY_AND_ASSIGN (ssa_name_limit_t);
|
||||
|
||||
public:
|
||||
|
||||
ssa_name_limit_t ()
|
||||
: visited (),
|
||||
ssa_def_max (param_ssa_name_def_chain_limit) { }
|
||||
|
||||
/* Set a bit for the PHI in VISITED and return true if it wasn't
|
||||
already set. */
|
||||
bool visit_phi (tree);
|
||||
/* Clear a bit for the PHI in VISITED. */
|
||||
void leave_phi (tree);
|
||||
/* Return false if the SSA_NAME chain length counter has reached
|
||||
the limit, otherwise increment the counter and return true. */
|
||||
bool next ();
|
||||
|
||||
/* If the SSA_NAME has already been "seen" return a positive value.
|
||||
Otherwise add it to VISITED. If the SSA_NAME limit has been
|
||||
reached, return a negative value. Otherwise return zero. */
|
||||
int next_phi (tree);
|
||||
|
||||
~ssa_name_limit_t ();
|
||||
};
|
||||
|
||||
class pointer_query;
|
||||
|
||||
/* Describes a reference to an object used in an access. */
|
||||
struct access_ref
|
||||
{
|
||||
/* Set the bounds of the reference to at most as many bytes
|
||||
as the first argument or unknown when null, and at least
|
||||
one when the second argument is true unless the first one
|
||||
is a constant zero. */
|
||||
access_ref (tree = NULL_TREE, bool = false);
|
||||
|
||||
/* Return the PHI node REF refers to or null if it doesn't. */
|
||||
gphi *phi () const;
|
||||
|
||||
/* Return the object to which REF refers. */
|
||||
tree get_ref (vec<access_ref> *, access_ref * = NULL, int = 1,
|
||||
ssa_name_limit_t * = NULL, pointer_query * = NULL) const;
|
||||
|
||||
/* Return true if OFFRNG is the constant zero. */
|
||||
bool offset_zero () const
|
||||
{
|
||||
return offrng[0] == 0 && offrng[1] == 0;
|
||||
}
|
||||
|
||||
/* Return true if OFFRNG is bounded to a subrange of offset values
|
||||
valid for the largest possible object. */
|
||||
bool offset_bounded () const;
|
||||
|
||||
/* Return the maximum amount of space remaining and if non-null, set
|
||||
argument to the minimum. */
|
||||
offset_int size_remaining (offset_int * = NULL) const;
|
||||
|
||||
/* Return true if the offset and object size are in range for SIZE. */
|
||||
bool offset_in_range (const offset_int &) const;
|
||||
|
||||
/* Return true if *THIS is an access to a declared object. */
|
||||
bool ref_declared () const
|
||||
{
|
||||
return DECL_P (ref) && base0 && deref < 1;
|
||||
}
|
||||
|
||||
/* Set the size range to the maximum. */
|
||||
void set_max_size_range ()
|
||||
{
|
||||
sizrng[0] = 0;
|
||||
sizrng[1] = wi::to_offset (max_object_size ());
|
||||
}
|
||||
|
||||
/* Add OFF to the offset range. */
|
||||
void add_offset (const offset_int &off)
|
||||
{
|
||||
add_offset (off, off);
|
||||
}
|
||||
|
||||
/* Add the range [MIN, MAX] to the offset range. */
|
||||
void add_offset (const offset_int &, const offset_int &);
|
||||
|
||||
/* Add the maximum representable offset to the offset range. */
|
||||
void add_max_offset ()
|
||||
{
|
||||
offset_int maxoff = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
|
||||
add_offset (-maxoff - 1, maxoff);
|
||||
}
|
||||
|
||||
/* Issue an informational message describing the target of an access
|
||||
with the given mode. */
|
||||
void inform_access (access_mode) const;
|
||||
|
||||
/* Reference to the accessed object(s). */
|
||||
tree ref;
|
||||
|
||||
/* Range of byte offsets into and sizes of the object(s). */
|
||||
offset_int offrng[2];
|
||||
offset_int sizrng[2];
|
||||
/* The minimum and maximum offset computed. */
|
||||
offset_int offmax[2];
|
||||
/* Range of the bound of the access: denotes that the access
|
||||
is at least BNDRNG[0] bytes but no more than BNDRNG[1].
|
||||
For string functions the size of the actual access is
|
||||
further constrained by the length of the string. */
|
||||
offset_int bndrng[2];
|
||||
|
||||
/* Used to fold integer expressions when called from front ends. */
|
||||
tree (*eval)(tree);
|
||||
/* Positive when REF is dereferenced, negative when its address is
|
||||
taken. */
|
||||
int deref;
|
||||
/* Set if trailing one-element arrays should be treated as flexible
|
||||
array members. */
|
||||
bool trail1special;
|
||||
/* Set if valid offsets must start at zero (for declared and allocated
|
||||
objects but not for others referenced by pointers). */
|
||||
bool base0;
|
||||
/* Set if REF refers to a function array parameter not declared
|
||||
static. */
|
||||
bool parmarray;
|
||||
};
|
||||
|
||||
class range_query;
|
||||
|
||||
/* Queries and caches compute_objsize results. */
|
||||
class pointer_query
|
||||
{
|
||||
DISABLE_COPY_AND_ASSIGN (pointer_query);
|
||||
|
||||
public:
|
||||
/* Type of the two-level cache object defined by clients of the class
|
||||
to have pointer SSA_NAMEs cached for speedy access. */
|
||||
struct cache_type
|
||||
{
|
||||
/* 1-based indices into cache. */
|
||||
vec<unsigned> indices;
|
||||
/* The cache itself. */
|
||||
vec<access_ref> access_refs;
|
||||
};
|
||||
|
||||
/* Construct an object with the given Ranger instance and cache. */
|
||||
explicit pointer_query (range_query * = NULL, cache_type * = NULL);
|
||||
|
||||
/* Retrieve the access_ref for a variable from cache if it's there. */
|
||||
const access_ref* get_ref (tree, int = 1) const;
|
||||
|
||||
/* Retrieve the access_ref for a variable from cache or compute it. */
|
||||
bool get_ref (tree, access_ref*, int = 1);
|
||||
|
||||
/* Add an access_ref for the SSA_NAME to the cache. */
|
||||
void put_ref (tree, const access_ref&, int = 1);
|
||||
|
||||
/* Flush the cache. */
|
||||
void flush_cache ();
|
||||
|
||||
/* A Ranger instance. May be null to use global ranges. */
|
||||
range_query *rvals;
|
||||
/* Cache of SSA_NAMEs. May be null to disable caching. */
|
||||
cache_type *var_cache;
|
||||
|
||||
/* Cache performance counters. */
|
||||
mutable unsigned hits;
|
||||
mutable unsigned misses;
|
||||
mutable unsigned failures;
|
||||
mutable unsigned depth;
|
||||
mutable unsigned max_depth;
|
||||
};
|
||||
|
||||
/* Describes a pair of references used in an access by built-in
|
||||
functions like memcpy. */
|
||||
struct access_data
|
||||
{
|
||||
/* Set the access to at most MAXWRITE and MAXREAD bytes, and
|
||||
at least 1 when MINWRITE or MINREAD, respectively, is set. */
|
||||
access_data (tree expr, access_mode mode,
|
||||
tree maxwrite = NULL_TREE, bool minwrite = false,
|
||||
tree maxread = NULL_TREE, bool minread = false)
|
||||
: call (expr),
|
||||
dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { }
|
||||
|
||||
/* Built-in function call. */
|
||||
tree call;
|
||||
/* Destination and source of the access. */
|
||||
access_ref dst, src;
|
||||
/* Read-only for functions like memcmp or strlen, write-only
|
||||
for memset, read-write for memcpy or strcat. */
|
||||
access_mode mode;
|
||||
};
|
||||
|
||||
extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
|
||||
range_query * = NULL);
|
||||
extern tree gimple_parm_array_size (tree, wide_int[2], bool * = NULL);
|
||||
|
||||
extern tree compute_objsize (tree, int, access_ref *, range_query * = NULL);
|
||||
/* Legacy/transitional API. Should not be used in new code. */
|
||||
extern tree compute_objsize (tree, int, access_ref *, pointer_query *);
|
||||
extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL,
|
||||
range_query * = NULL);
|
||||
class access_data;
|
||||
extern bool check_access (tree, tree, tree, tree, tree,
|
||||
access_mode, const access_data * = NULL);
|
||||
extern void maybe_emit_free_warning (tree);
|
||||
|
||||
#endif /* GCC_BUILTINS_H */
|
||||
|
@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "gimple-fold.h"
|
||||
#include "attr-fnspec.h"
|
||||
#include "value-query.h"
|
||||
#include "pointer-query.h"
|
||||
|
||||
#include "tree-pretty-print.h"
|
||||
|
||||
@ -2628,10 +2629,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
|
||||
|
||||
/* Check attribute access arguments. */
|
||||
maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp);
|
||||
|
||||
/* Check calls to operator new for mismatched forms and attempts
|
||||
to deallocate unallocated objects. */
|
||||
maybe_emit_free_warning (exp);
|
||||
}
|
||||
|
||||
/* Update ARGS_SIZE to contain the total size for the argument block.
|
||||
|
@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "attribs.h"
|
||||
#include "asan.h"
|
||||
#include "stor-layout.h"
|
||||
#include "builtins.h"
|
||||
#include "pointer-query.h"
|
||||
|
||||
static bool begin_init_stmts (tree *, tree *);
|
||||
static tree finish_init_stmts (bool, tree, tree);
|
||||
|
@ -37,7 +37,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "domwalk.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "attribs.h"
|
||||
#include "builtins.h"
|
||||
#include "pointer-query.h"
|
||||
|
||||
// This purposely returns a value_range, not a value_range_equiv, to
|
||||
// break the dependency on equivalences for this pass.
|
||||
|
@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "ssa.h"
|
||||
#include "cgraph.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "gimple-ssa-warn-access.h"
|
||||
#include "gimple-ssa-warn-restrict.h"
|
||||
#include "fold-const.h"
|
||||
#include "stmt.h"
|
||||
|
@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
#include "attribs.h"
|
||||
#include "builtins.h"
|
||||
#include "pointer-query.h"
|
||||
#include "stor-layout.h"
|
||||
|
||||
#include "realmpfr.h"
|
||||
|
1765
gcc/gimple-ssa-warn-access.cc
Normal file
1765
gcc/gimple-ssa-warn-access.cc
Normal file
File diff suppressed because it is too large
Load Diff
37
gcc/gimple-ssa-warn-access.h
Normal file
37
gcc/gimple-ssa-warn-access.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* Pass to detect and issue warnings for invalid accesses, including
|
||||
invalid or mismatched allocation/deallocation calls.
|
||||
|
||||
Copyright (C) 2020-2021 Free Software Foundation, Inc.
|
||||
Contributed by Martin Sebor <msebor@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_GIMPLE_SSA_WARN_ACCESS_H
|
||||
#define GCC_GIMPLE_SSA_WARN_ACCESS_H
|
||||
|
||||
extern bool check_nul_terminated_array (tree, tree, tree = NULL_TREE);
|
||||
extern void warn_string_no_nul (location_t, tree, const char *, tree,
|
||||
tree, tree = NULL_TREE, bool = false,
|
||||
const wide_int[2] = NULL);
|
||||
extern tree unterminated_array (tree, tree * = NULL, bool * = NULL);
|
||||
extern void get_size_range (tree, tree[2], const offset_int[2]);
|
||||
|
||||
class access_data;
|
||||
extern bool maybe_warn_for_bound (opt_code, location_t, tree, tree,
|
||||
tree[2], tree, const access_data * = NULL);
|
||||
|
||||
#endif // GCC_GIMPLE_SSA_WARN_ACCESS_H
|
@ -26,7 +26,7 @@
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "tree-pass.h"
|
||||
#include "builtins.h"
|
||||
#include "pointer-query.h"
|
||||
#include "ssa.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "gimple-ssa-warn-restrict.h"
|
||||
|
@ -419,6 +419,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
NEXT_PASS (pass_gimple_isel);
|
||||
NEXT_PASS (pass_cleanup_cfg_post_optimizing);
|
||||
NEXT_PASS (pass_warn_function_noreturn);
|
||||
NEXT_PASS (pass_warn_access);
|
||||
|
||||
NEXT_PASS (pass_expand);
|
||||
|
||||
|
1895
gcc/pointer-query.cc
Normal file
1895
gcc/pointer-query.cc
Normal file
File diff suppressed because it is too large
Load Diff
234
gcc/pointer-query.h
Normal file
234
gcc/pointer-query.h
Normal file
@ -0,0 +1,234 @@
|
||||
/* Definitions of the pointer_query and related classes.
|
||||
|
||||
Copyright (C) 2020-2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GCC_POINTER_QUERY_H
|
||||
#define GCC_POINTER_QUERY_H
|
||||
|
||||
/* Describes recursion limits used by functions that follow use-def
|
||||
chains of SSA_NAMEs. */
|
||||
|
||||
class ssa_name_limit_t
|
||||
{
|
||||
bitmap visited; /* Bitmap of visited SSA_NAMEs. */
|
||||
unsigned ssa_def_max; /* Longest chain of SSA_NAMEs to follow. */
|
||||
|
||||
/* Not copyable or assignable. */
|
||||
DISABLE_COPY_AND_ASSIGN (ssa_name_limit_t);
|
||||
|
||||
public:
|
||||
|
||||
ssa_name_limit_t ()
|
||||
: visited (),
|
||||
ssa_def_max (param_ssa_name_def_chain_limit) { }
|
||||
|
||||
/* Set a bit for the PHI in VISITED and return true if it wasn't
|
||||
already set. */
|
||||
bool visit_phi (tree);
|
||||
/* Clear a bit for the PHI in VISITED. */
|
||||
void leave_phi (tree);
|
||||
/* Return false if the SSA_NAME chain length counter has reached
|
||||
the limit, otherwise increment the counter and return true. */
|
||||
bool next ();
|
||||
|
||||
/* If the SSA_NAME has already been "seen" return a positive value.
|
||||
Otherwise add it to VISITED. If the SSA_NAME limit has been
|
||||
reached, return a negative value. Otherwise return zero. */
|
||||
int next_phi (tree);
|
||||
|
||||
~ssa_name_limit_t ();
|
||||
};
|
||||
|
||||
class pointer_query;
|
||||
|
||||
/* Describes a reference to an object used in an access. */
|
||||
struct access_ref
|
||||
{
|
||||
/* Set the bounds of the reference to at most as many bytes
|
||||
as the first argument or unknown when null, and at least
|
||||
one when the second argument is true unless the first one
|
||||
is a constant zero. */
|
||||
access_ref (tree = NULL_TREE, bool = false);
|
||||
|
||||
/* Return the PHI node REF refers to or null if it doesn't. */
|
||||
gphi *phi () const;
|
||||
|
||||
/* Return the object to which REF refers. */
|
||||
tree get_ref (vec<access_ref> *, access_ref * = NULL, int = 1,
|
||||
ssa_name_limit_t * = NULL, pointer_query * = NULL) const;
|
||||
|
||||
/* Return true if OFFRNG is the constant zero. */
|
||||
bool offset_zero () const
|
||||
{
|
||||
return offrng[0] == 0 && offrng[1] == 0;
|
||||
}
|
||||
|
||||
/* Return true if OFFRNG is bounded to a subrange of offset values
|
||||
valid for the largest possible object. */
|
||||
bool offset_bounded () const;
|
||||
|
||||
/* Return the maximum amount of space remaining and if non-null, set
|
||||
argument to the minimum. */
|
||||
offset_int size_remaining (offset_int * = NULL) const;
|
||||
|
||||
/* Return true if the offset and object size are in range for SIZE. */
|
||||
bool offset_in_range (const offset_int &) const;
|
||||
|
||||
/* Return true if *THIS is an access to a declared object. */
|
||||
bool ref_declared () const
|
||||
{
|
||||
return DECL_P (ref) && base0 && deref < 1;
|
||||
}
|
||||
|
||||
/* Set the size range to the maximum. */
|
||||
void set_max_size_range ()
|
||||
{
|
||||
sizrng[0] = 0;
|
||||
sizrng[1] = wi::to_offset (max_object_size ());
|
||||
}
|
||||
|
||||
/* Add OFF to the offset range. */
|
||||
void add_offset (const offset_int &off)
|
||||
{
|
||||
add_offset (off, off);
|
||||
}
|
||||
|
||||
/* Add the range [MIN, MAX] to the offset range. */
|
||||
void add_offset (const offset_int &, const offset_int &);
|
||||
|
||||
/* Add the maximum representable offset to the offset range. */
|
||||
void add_max_offset ()
|
||||
{
|
||||
offset_int maxoff = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node));
|
||||
add_offset (-maxoff - 1, maxoff);
|
||||
}
|
||||
|
||||
/* Issue an informational message describing the target of an access
|
||||
with the given mode. */
|
||||
void inform_access (access_mode) const;
|
||||
|
||||
/* Reference to the accessed object(s). */
|
||||
tree ref;
|
||||
|
||||
/* Range of byte offsets into and sizes of the object(s). */
|
||||
offset_int offrng[2];
|
||||
offset_int sizrng[2];
|
||||
/* The minimum and maximum offset computed. */
|
||||
offset_int offmax[2];
|
||||
/* Range of the bound of the access: denotes that the access
|
||||
is at least BNDRNG[0] bytes but no more than BNDRNG[1].
|
||||
For string functions the size of the actual access is
|
||||
further constrained by the length of the string. */
|
||||
offset_int bndrng[2];
|
||||
|
||||
/* Used to fold integer expressions when called from front ends. */
|
||||
tree (*eval)(tree);
|
||||
/* Positive when REF is dereferenced, negative when its address is
|
||||
taken. */
|
||||
int deref;
|
||||
/* Set if trailing one-element arrays should be treated as flexible
|
||||
array members. */
|
||||
bool trail1special;
|
||||
/* Set if valid offsets must start at zero (for declared and allocated
|
||||
objects but not for others referenced by pointers). */
|
||||
bool base0;
|
||||
/* Set if REF refers to a function array parameter not declared
|
||||
static. */
|
||||
bool parmarray;
|
||||
};
|
||||
|
||||
class range_query;
|
||||
|
||||
/* Queries and caches compute_objsize results. */
|
||||
class pointer_query
|
||||
{
|
||||
DISABLE_COPY_AND_ASSIGN (pointer_query);
|
||||
|
||||
public:
|
||||
/* Type of the two-level cache object defined by clients of the class
|
||||
to have pointer SSA_NAMEs cached for speedy access. */
|
||||
struct cache_type
|
||||
{
|
||||
/* 1-based indices into cache. */
|
||||
vec<unsigned> indices;
|
||||
/* The cache itself. */
|
||||
vec<access_ref> access_refs;
|
||||
};
|
||||
|
||||
/* Construct an object with the given Ranger instance and cache. */
|
||||
explicit pointer_query (range_query * = NULL, cache_type * = NULL);
|
||||
|
||||
/* Retrieve the access_ref for a variable from cache if it's there. */
|
||||
const access_ref* get_ref (tree, int = 1) const;
|
||||
|
||||
/* Retrieve the access_ref for a variable from cache or compute it. */
|
||||
bool get_ref (tree, access_ref*, int = 1);
|
||||
|
||||
/* Add an access_ref for the SSA_NAME to the cache. */
|
||||
void put_ref (tree, const access_ref&, int = 1);
|
||||
|
||||
/* Flush the cache. */
|
||||
void flush_cache ();
|
||||
|
||||
/* A Ranger instance. May be null to use global ranges. */
|
||||
range_query *rvals;
|
||||
/* Cache of SSA_NAMEs. May be null to disable caching. */
|
||||
cache_type *var_cache;
|
||||
|
||||
/* Cache performance counters. */
|
||||
mutable unsigned hits;
|
||||
mutable unsigned misses;
|
||||
mutable unsigned failures;
|
||||
mutable unsigned depth;
|
||||
mutable unsigned max_depth;
|
||||
};
|
||||
|
||||
/* Describes a pair of references used in an access by built-in
|
||||
functions like memcpy. */
|
||||
struct access_data
|
||||
{
|
||||
/* Set the access to at most MAXWRITE and MAXREAD bytes, and
|
||||
at least 1 when MINWRITE or MINREAD, respectively, is set. */
|
||||
access_data (tree expr, access_mode mode,
|
||||
tree maxwrite = NULL_TREE, bool minwrite = false,
|
||||
tree maxread = NULL_TREE, bool minread = false)
|
||||
: call (expr),
|
||||
dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { }
|
||||
|
||||
/* Built-in function call. */
|
||||
tree call;
|
||||
/* Destination and source of the access. */
|
||||
access_ref dst, src;
|
||||
/* Read-only for functions like memcmp or strlen, write-only
|
||||
for memset, read-write for memcpy or strcat. */
|
||||
access_mode mode;
|
||||
};
|
||||
|
||||
class range_query;
|
||||
extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
|
||||
range_query * = NULL);
|
||||
extern tree gimple_parm_array_size (tree, wide_int[2], bool * = NULL);
|
||||
|
||||
extern tree compute_objsize (tree, int, access_ref *, range_query * = NULL);
|
||||
/* Legacy/transitional API. Should not be used in new code. */
|
||||
extern tree compute_objsize (tree, int, access_ref *, pointer_query *);
|
||||
extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL,
|
||||
range_query * = NULL);
|
||||
|
||||
#endif // GCC_POINTER_QUERY_H
|
@ -428,6 +428,7 @@ extern gimple_opt_pass *make_pass_oacc_device_lower (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_omp_device_lower (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_object_sizes (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_early_object_sizes (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_warn_access (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_warn_printf (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt);
|
||||
extern gimple_opt_pass *make_pass_fold_builtins (gcc::context *ctxt);
|
||||
|
@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "ssa.h"
|
||||
#include "cgraph.h"
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "gimple-ssa-warn-access.h"
|
||||
#include "gimple-ssa-warn-restrict.h"
|
||||
#include "fold-const.h"
|
||||
#include "stor-layout.h"
|
||||
@ -47,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "tree-ssa-strlen.h"
|
||||
#include "tree-hash-traits.h"
|
||||
#include "builtins.h"
|
||||
#include "pointer-query.h"
|
||||
#include "target.h"
|
||||
#include "diagnostic-core.h"
|
||||
#include "diagnostic.h"
|
||||
|
59
gcc/tree.c
59
gcc/tree.c
@ -14380,6 +14380,65 @@ valid_new_delete_pair_p (tree new_asm, tree delete_asm)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Return the zero-based number corresponding to the argument being
|
||||
deallocated if FNDECL is a deallocation function or an out-of-bounds
|
||||
value if it isn't. */
|
||||
|
||||
unsigned
|
||||
fndecl_dealloc_argno (tree fndecl)
|
||||
{
|
||||
/* A call to operator delete isn't recognized as one to a built-in. */
|
||||
if (DECL_IS_OPERATOR_DELETE_P (fndecl))
|
||||
{
|
||||
if (DECL_IS_REPLACEABLE_OPERATOR (fndecl))
|
||||
return 0;
|
||||
|
||||
/* Avoid placement delete that's not been inlined. */
|
||||
tree fname = DECL_ASSEMBLER_NAME (fndecl);
|
||||
if (id_equal (fname, "_ZdlPvS_") // ordinary form
|
||||
|| id_equal (fname, "_ZdaPvS_")) // array form
|
||||
return UINT_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Handle user-defined functions with attribute malloc? Handle
|
||||
known non-built-ins like fopen? */
|
||||
if (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL))
|
||||
{
|
||||
switch (DECL_FUNCTION_CODE (fndecl))
|
||||
{
|
||||
case BUILT_IN_FREE:
|
||||
case BUILT_IN_REALLOC:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
tree attrs = DECL_ATTRIBUTES (fndecl);
|
||||
if (!attrs)
|
||||
return UINT_MAX;
|
||||
|
||||
for (tree atfree = attrs;
|
||||
(atfree = lookup_attribute ("*dealloc", atfree));
|
||||
atfree = TREE_CHAIN (atfree))
|
||||
{
|
||||
tree alloc = TREE_VALUE (atfree);
|
||||
if (!alloc)
|
||||
continue;
|
||||
|
||||
tree pos = TREE_CHAIN (alloc);
|
||||
if (!pos)
|
||||
return 0;
|
||||
|
||||
pos = TREE_VALUE (pos);
|
||||
return TREE_INT_CST_LOW (pos) - 1;
|
||||
}
|
||||
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
#if CHECKING_P
|
||||
|
||||
namespace selftest {
|
||||
|
@ -6468,4 +6468,9 @@ extern void suppress_warning (tree, opt_code = all_warnings, bool = true)
|
||||
/* Copy warning disposition from one expression to another. */
|
||||
extern void copy_warning (tree, const_tree);
|
||||
|
||||
/* Return the zero-based number corresponding to the argument being
|
||||
deallocated if FNDECL is a deallocation function or an out-of-bounds
|
||||
value if it isn't. */
|
||||
extern unsigned fndecl_dealloc_argno (tree);
|
||||
|
||||
#endif /* GCC_TREE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user