From 2a837de28ee94b4ec201059a9a7aaa852e6808da Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 28 Jul 2021 15:28:10 -0600 Subject: 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. --- gcc/pointer-query.h | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 gcc/pointer-query.h (limited to 'gcc/pointer-query.h') diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h new file mode 100644 index 0000000..6168c80 --- /dev/null +++ b/gcc/pointer-query.h @@ -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 + . */ + +#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 * = 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 indices; + /* The cache itself. */ + vec 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 -- cgit v1.1 From 81d6cdd335ffc60c216a020d5c99306f659377a2 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 6 Aug 2021 15:29:33 -0600 Subject: Move more code to new gimple-ssa-warn-access pass. gcc/ChangeLog: * builtins.c (expand_builtin_memchr): Move to gimple-ssa-warn-access.cc. (expand_builtin_strcat): Same. (expand_builtin_stpncpy): Same. (expand_builtin_strncat): Same. (check_read_access): Same. (check_memop_access): Same. (expand_builtin_strlen): Move checks to gimple-ssa-warn-access.cc. (expand_builtin_strnlen): Same. (expand_builtin_memcpy): Same. (expand_builtin_memmove): Same. (expand_builtin_mempcpy): Same. (expand_builtin_strcpy): Same. (expand_builtin_strcpy_args): Same. (expand_builtin_stpcpy_1): Same. (expand_builtin_strncpy): Same. (expand_builtin_memset): Same. (expand_builtin_bzero): Same. (expand_builtin_strcmp): Same. (expand_builtin_strncmp): Same. (expand_builtin): Remove handlers. (fold_builtin_strlen): Add a comment. * builtins.h (check_access): Move to gimple-ssa-warn-access.cc. * calls.c (maybe_warn_nonstring_arg): Same. * diagnostic-spec.c (nowarn_spec_t::nowarn_spec_t): Add warning option. * gimple-fold.c (gimple_fold_builtin_strcpy): Pass argument to callee. (gimple_fold_builtin_stpcpy): Same. * gimple-ssa-warn-access.cc (has_location): New function. (get_location): Same. (get_callee_fndecl): Same. (call_nargs): Same. (call_arg): Same. (warn_string_no_nul): Define. (unterminated_array): Same. (check_nul_terminated_array): Same. (maybe_warn_nonstring_arg): Same. (maybe_warn_for_bound): Same. (warn_for_access): Same. (check_access): Same. (check_memop_access): Same. (check_read_access): Same. (warn_dealloc_offset): Use helper functions. (maybe_emit_free_warning): Same. (class pass_waccess): Add members. (check_strcat): New function. (check_strncat): New function. (check_stxcpy): New function. (check_stxncpy): New function. (check_strncmp): New function. (pass_waccess::check_builtin): New function. (pass_waccess::check): Call it. * gimple-ssa-warn-access.h (warn_string_no_nul): Move here from builtins.h. (maybe_warn_for_bound): Same. (check_access): Same. (check_memop_access): Same. (check_read_access): Same. * pointer-query.h (struct access_data): Define a ctor overload. gcc/testsuite/ChangeLog: * c-c++-common/Wsizeof-pointer-memaccess1.c: Also disable -Wstringop-overread. * c-c++-common/attr-nonstring-3.c: Adjust pattern of expected message. * gcc.dg/Warray-bounds-39.c: Add an xfail due to a known bug. * gcc.dg/Wstring-compare-3.c: Also disable -Wstringop-overread. * gcc.dg/attr-nonstring-2.c: Adjust pattern of expected message. * gcc.dg/attr-nonstring-4.c: Same. * gcc.dg/Wstringop-overread-6.c: New test. * gcc.dg/sso-14.c: Fix typos to avoid buffer overflow. --- gcc/pointer-query.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'gcc/pointer-query.h') diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index 6168c80..8bd538a 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -205,12 +205,22 @@ 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 (gimple *stmt, access_mode mode, + tree maxwrite = NULL_TREE, bool minwrite = false, + tree maxread = NULL_TREE, bool minread = false) + : stmt (stmt), call (), + dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { } + + /* 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), + : stmt (), call (expr), dst (maxwrite, minwrite), src (maxread, minread), mode (mode) { } + /* Access statement. */ + gimple *stmt; /* Built-in function call. */ tree call; /* Destination and source of the access. */ -- cgit v1.1 From b48d4e6818674898f90d9358378c127511ef0f9f Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 17 Aug 2021 14:49:05 -0600 Subject: Move more warning code to gimple-ssa-warn-access etc. Also resolves: PR middle-end/101854 - Invalid warning -Wstringop-overflow wrong argument gcc/ChangeLog: PR middle-end/101854 * builtins.c (expand_builtin_alloca): Move warning code to check_alloca in gimple-ssa-warn-access.cc. * calls.c (alloc_max_size): Move code to check_alloca. (get_size_range): Move to pointer-query.cc. (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.cc. (get_attr_nonstring_decl): Move to tree.c. (fntype_argno_type): Move to gimple-ssa-warn-access.cc. (append_attrname): Same. (maybe_warn_rdwr_sizes): Same. (initialize_argument_information): Move code to gimple-ssa-warn-access.cc. * calls.h (maybe_warn_alloc_args_overflow): Move to gimple-ssa-warn-access.h. (get_attr_nonstring_decl): Move to tree.h. (maybe_warn_nonstring_arg): Move to gimple-ssa-warn-access.h. (enum size_range_flags): Move to pointer-query.h. (get_size_range): Same. * gimple-ssa-warn-access.cc (has_location): Remove unused overload to avoid Clang -Wunused-function. (get_size_range): Declare static. (maybe_emit_free_warning): Rename... (maybe_check_dealloc_call): ...to this for consistency. (class pass_waccess): Add members. (pass_waccess::~pass_waccess): Defined. (alloc_max_size): Move here from calls.c. (maybe_warn_alloc_args_overflow): Same. (check_alloca): New function. (check_alloc_size_call): New function. (check_strncat): Handle another warning flag. (pass_waccess::check_builtin): Handle alloca. (fntype_argno_type): Move here from calls.c. (append_attrname): Same. (maybe_warn_rdwr_sizes): Same. (pass_waccess::check_call): Define. (check_nonstring_args): New function. (pass_waccess::check): Call new member functions. (pass_waccess::execute): Enable ranger. * gimple-ssa-warn-access.h (get_size_range): Move here from calls.h. (maybe_warn_nonstring_arg): Same. * gimple-ssa-warn-restrict.c: Remove #include. * pointer-query.cc (get_size_range): Move here from calls.c. * pointer-query.h (enum size_range_flags): Same. (get_size_range): Same. * tree.c (get_attr_nonstring_decl): Move here from calls.c. * tree.h (get_attr_nonstring_decl): Move here from calls.h. gcc/testsuite/ChangeLog: * gcc.dg/attr-alloc_size-5.c: Adjust optimization to -O1. * gcc.dg/attr-alloc_size-7.c: Use #pragmas to adjust optimization. * gcc.dg/attr-alloc_size-8.c: Adjust optimization to -O1. PR middle-end/101854 * gcc.dg/Wstringop-overflow-72.c: New test. --- gcc/pointer-query.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/pointer-query.h') diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index 8bd538a..eb7e90d 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -230,6 +230,17 @@ struct access_data access_mode mode; }; +enum size_range_flags + { + /* Set to consider zero a valid range. */ + SR_ALLOW_ZERO = 1, + /* Set to use the largest subrange of a set of ranges as opposed + to the smallest. */ + SR_USE_LARGEST = 2 + }; +extern bool get_size_range (tree, tree[2], int = 0); +extern bool get_size_range (range_query *, tree, gimple *, tree[2], int = 0); + class range_query; extern tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL, range_query * = NULL); -- cgit v1.1 From ece28da924ddda8b379c94c9df7cd01168f75fbb Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 1 Sep 2021 13:46:19 -0600 Subject: Enable ranger and caching in pass_waccess. gcc/ChangeLog: * gimple-ssa-warn-access.cc (get_size_range): Add argument. (check_access): Pass additional argument. (check_memop_access): Remove template and make a member function. (maybe_check_dealloc_call): Make a pass_waccess member function. (class pass_waccess): Add, rename, and remove members. (pass_waccess::pass_waccess): Adjust to name change. (pass_waccess::~pass_waccess): Same. (check_alloca): Make a member function. (check_alloc_size_call): Same. (check_strcat): Same. (check_strncat): Same. (check_stxcpy): Same. (check_stxncpy): Same. (check_strncmp): Same. (maybe_warn_rdwr_sizes): Rename... (pass_waccess::maybe_check_access_sizes): ...to this. (pass_waccess::check_call): Adjust to name changes. (pass_waccess::maybe_check_dealloc_call): Make a pass_waccess member function. (pass_waccess::execute): Adjust to name changes. * gimple-ssa-warn-access.h (check_memop_access): Remove. * pointer-query.cc (access_ref::phi): Handle null pointer. (access_ref::inform_access): Same. (pointer_query::put_ref): Modify a cached value, not a copy of it. (pointer_query::dump): New function. (compute_objsize_r): Avoid overwriting access_ref::bndrng. Cache more results. * pointer-query.h (pointer_query::dump): Declare. * tree-ssa-strlen.c (get_range): Simplify. Use function query. (dump_strlen_info): Use function query. (printf_strlen_execute): Factor code out into pointer_query::put_ref. gcc/testsuite/ChangeLog: * gcc.dg/Wstringop-overflow-11.c: Remove xfails. * gcc.dg/Wstringop-overflow-12.c: Same. * gcc.dg/Wstringop-overflow-43.c: Add xfails. * gcc.dg/Wstringop-overflow-73.c: New test. --- gcc/pointer-query.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/pointer-query.h') diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h index eb7e90d..3c8172c 100644 --- a/gcc/pointer-query.h +++ b/gcc/pointer-query.h @@ -186,6 +186,9 @@ public: /* Flush the cache. */ void flush_cache (); + /* Dump statistics and optionally cache contents to DUMP_FILE. */ + void dump (FILE *, bool = false); + /* A Ranger instance. May be null to use global ranges. */ range_query *rvals; /* Cache of SSA_NAMEs. May be null to disable caching. */ -- cgit v1.1