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-store-merging.o \
|
||||||
gimple-ssa-strength-reduction.o \
|
gimple-ssa-strength-reduction.o \
|
||||||
gimple-ssa-sprintf.o \
|
gimple-ssa-sprintf.o \
|
||||||
|
gimple-ssa-warn-access.o \
|
||||||
gimple-ssa-warn-alloca.o \
|
gimple-ssa-warn-alloca.o \
|
||||||
gimple-ssa-warn-restrict.o \
|
gimple-ssa-warn-restrict.o \
|
||||||
gimple-streamer-in.o \
|
gimple-streamer-in.o \
|
||||||
@ -1524,6 +1525,7 @@ OBJS = \
|
|||||||
ordered-hash-map-tests.o \
|
ordered-hash-map-tests.o \
|
||||||
passes.o \
|
passes.o \
|
||||||
plugin.o \
|
plugin.o \
|
||||||
|
pointer-query.o \
|
||||||
postreload-gcse.o \
|
postreload-gcse.o \
|
||||||
postreload.o \
|
postreload.o \
|
||||||
predict.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,
|
extern attr_access *get_parm_access (rdwr_map &, tree,
|
||||||
tree = current_function_decl);
|
tree = current_function_decl);
|
||||||
|
|
||||||
extern unsigned fndecl_dealloc_argno (tree fndecl);
|
|
||||||
|
|
||||||
#endif // GCC_ATTRIBS_H
|
#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 associated_internal_fn (tree);
|
||||||
extern internal_fn replacement_internal_fn (gcall *);
|
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);
|
extern bool builtin_with_linkage_p (tree);
|
||||||
|
|
||||||
/* Describes recursion limits used by functions that follow use-def
|
class access_data;
|
||||||
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);
|
|
||||||
extern bool check_access (tree, tree, tree, tree, tree,
|
extern bool check_access (tree, tree, tree, tree, tree,
|
||||||
access_mode, const access_data * = NULL);
|
access_mode, const access_data * = NULL);
|
||||||
extern void maybe_emit_free_warning (tree);
|
|
||||||
|
|
||||||
#endif /* GCC_BUILTINS_H */
|
#endif /* GCC_BUILTINS_H */
|
||||||
|
@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
#include "gimple-fold.h"
|
#include "gimple-fold.h"
|
||||||
#include "attr-fnspec.h"
|
#include "attr-fnspec.h"
|
||||||
#include "value-query.h"
|
#include "value-query.h"
|
||||||
|
#include "pointer-query.h"
|
||||||
|
|
||||||
#include "tree-pretty-print.h"
|
#include "tree-pretty-print.h"
|
||||||
|
|
||||||
@ -2628,10 +2629,6 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
|
|||||||
|
|
||||||
/* Check attribute access arguments. */
|
/* Check attribute access arguments. */
|
||||||
maybe_warn_rdwr_sizes (&rdwr_idx, fndecl, fntype, exp);
|
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.
|
/* 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 "attribs.h"
|
||||||
#include "asan.h"
|
#include "asan.h"
|
||||||
#include "stor-layout.h"
|
#include "stor-layout.h"
|
||||||
#include "builtins.h"
|
#include "pointer-query.h"
|
||||||
|
|
||||||
static bool begin_init_stmts (tree *, tree *);
|
static bool begin_init_stmts (tree *, tree *);
|
||||||
static tree finish_init_stmts (bool, 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 "domwalk.h"
|
||||||
#include "tree-cfg.h"
|
#include "tree-cfg.h"
|
||||||
#include "attribs.h"
|
#include "attribs.h"
|
||||||
#include "builtins.h"
|
#include "pointer-query.h"
|
||||||
|
|
||||||
// This purposely returns a value_range, not a value_range_equiv, to
|
// This purposely returns a value_range, not a value_range_equiv, to
|
||||||
// break the dependency on equivalences for this pass.
|
// 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 "ssa.h"
|
||||||
#include "cgraph.h"
|
#include "cgraph.h"
|
||||||
#include "gimple-pretty-print.h"
|
#include "gimple-pretty-print.h"
|
||||||
|
#include "gimple-ssa-warn-access.h"
|
||||||
#include "gimple-ssa-warn-restrict.h"
|
#include "gimple-ssa-warn-restrict.h"
|
||||||
#include "fold-const.h"
|
#include "fold-const.h"
|
||||||
#include "stmt.h"
|
#include "stmt.h"
|
||||||
|
@ -71,6 +71,7 @@ along with GCC; see the file COPYING3. If not see
|
|||||||
|
|
||||||
#include "attribs.h"
|
#include "attribs.h"
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
|
#include "pointer-query.h"
|
||||||
#include "stor-layout.h"
|
#include "stor-layout.h"
|
||||||
|
|
||||||
#include "realmpfr.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 "tree.h"
|
||||||
#include "gimple.h"
|
#include "gimple.h"
|
||||||
#include "tree-pass.h"
|
#include "tree-pass.h"
|
||||||
#include "builtins.h"
|
#include "pointer-query.h"
|
||||||
#include "ssa.h"
|
#include "ssa.h"
|
||||||
#include "gimple-pretty-print.h"
|
#include "gimple-pretty-print.h"
|
||||||
#include "gimple-ssa-warn-restrict.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_gimple_isel);
|
||||||
NEXT_PASS (pass_cleanup_cfg_post_optimizing);
|
NEXT_PASS (pass_cleanup_cfg_post_optimizing);
|
||||||
NEXT_PASS (pass_warn_function_noreturn);
|
NEXT_PASS (pass_warn_function_noreturn);
|
||||||
|
NEXT_PASS (pass_warn_access);
|
||||||
|
|
||||||
NEXT_PASS (pass_expand);
|
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_omp_device_lower (gcc::context *ctxt);
|
||||||
extern gimple_opt_pass *make_pass_object_sizes (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_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_warn_printf (gcc::context *ctxt);
|
||||||
extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt);
|
extern gimple_opt_pass *make_pass_strlen (gcc::context *ctxt);
|
||||||
extern gimple_opt_pass *make_pass_fold_builtins (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 "ssa.h"
|
||||||
#include "cgraph.h"
|
#include "cgraph.h"
|
||||||
#include "gimple-pretty-print.h"
|
#include "gimple-pretty-print.h"
|
||||||
|
#include "gimple-ssa-warn-access.h"
|
||||||
#include "gimple-ssa-warn-restrict.h"
|
#include "gimple-ssa-warn-restrict.h"
|
||||||
#include "fold-const.h"
|
#include "fold-const.h"
|
||||||
#include "stor-layout.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-ssa-strlen.h"
|
||||||
#include "tree-hash-traits.h"
|
#include "tree-hash-traits.h"
|
||||||
#include "builtins.h"
|
#include "builtins.h"
|
||||||
|
#include "pointer-query.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "diagnostic-core.h"
|
#include "diagnostic-core.h"
|
||||||
#include "diagnostic.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 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
|
#if CHECKING_P
|
||||||
|
|
||||||
namespace selftest {
|
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. */
|
/* Copy warning disposition from one expression to another. */
|
||||||
extern void copy_warning (tree, const_tree);
|
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 */
|
#endif /* GCC_TREE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user