diff options
Diffstat (limited to 'gcc/tree-ssa-alias-warnings.c')
-rw-r--r-- | gcc/tree-ssa-alias-warnings.c | 1033 |
1 files changed, 0 insertions, 1033 deletions
diff --git a/gcc/tree-ssa-alias-warnings.c b/gcc/tree-ssa-alias-warnings.c deleted file mode 100644 index 5bae978..0000000 --- a/gcc/tree-ssa-alias-warnings.c +++ /dev/null @@ -1,1033 +0,0 @@ -/* Strict aliasing checks. - Copyright (C) 2007, 2008 Free Software Foundation, Inc. - Contributed by Silvius Rus <rus@google.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/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "alloc-pool.h" -#include "tree.h" -#include "tree-dump.h" -#include "tree-flow.h" -#include "params.h" -#include "function.h" -#include "expr.h" -#include "toplev.h" -#include "diagnostic.h" -#include "tree-ssa-structalias.h" -#include "tree-ssa-propagate.h" -#include "langhooks.h" - -/* Module to issue a warning when a program uses data through a type - different from the type through which the data were defined. - Implements -Wstrict-aliasing and -Wstrict-aliasing=n. - These checks only happen when -fstrict-aliasing is present. - - The idea is to use the compiler to identify occurrences of nonstandard - aliasing, and report them to programmers. Programs free of such aliasing - are more portable, maintainable, and can usually be optimized better. - - The current, as of April 2007, C and C++ language standards forbid - accessing data of type A through an lvalue of another type B, - with certain exceptions. See the C Standard ISO/IEC 9899:1999, - section 6.5, paragraph 7, and the C++ Standard ISO/IEC 14882:1998, - section 3.10, paragraph 15. - - Example 1:*a is used as int but was defined as a float, *b. - int* a = ...; - float* b = reinterpret_cast<float*> (a); - *b = 2.0; - return *a - - Unfortunately, the problem is in general undecidable if we take into - account arithmetic expressions such as array indices or pointer arithmetic. - (It is at least as hard as Peano arithmetic decidability.) - Even ignoring arithmetic, the problem is still NP-hard, because it is - at least as hard as flow-insensitive may-alias analysis, which was proved - NP-hard by Horwitz et al, TOPLAS 1997. - - It is clear that we need to choose some heuristics. - Unfortunately, various users have different goals which correspond to - different time budgets so a common approach will not suit all. - We present the user with three effort/accuracy levels. By accuracy, we mean - a common-sense mix of low count of false positives with a - reasonably low number of false negatives. We are heavily biased - towards a low count of false positives. - The effort (compilation time) is likely to increase with the level. - - -Wstrict-aliasing=1 - =================== - Most aggressive, least accurate. Possibly useful when higher levels - do not warn but -fstrict-aliasing still breaks the code, as - it has very few false negatives. - Warn for all bad pointer conversions, even if never dereferenced. - Implemented in the front end (c-common.c). - Uses alias_sets_might_conflict to compare types. - - -Wstrict-aliasing=2 - =================== - Aggressive, not too precise. - May still have many false positives (not as many as level 1 though), - and few false negatives (but possibly more than level 1). - Runs only in the front end. Uses alias_sets_might_conflict to - compare types. Does not check for pointer dereferences. - Only warns when an address is taken. Warns about incomplete type punning. - - -Wstrict-aliasing=3 (default) - =================== - Should have very few false positives and few false negatives. - Takes care of the common pun+dereference pattern in the front end: - *(int*)&some_float. - Takes care of multiple statement cases in the back end, - using flow-sensitive points-to information (-O required). - Uses alias_sets_conflict_p to compare types and only warns - when the converted pointer is dereferenced. - Does not warn about incomplete type punning. - - Future improvements can be included by adding higher levels. - - In summary, expression level analysis is performed in the front-end, - and multiple-statement analysis is performed in the backend. - The remainder of this discussion is only about the backend analysis. - - This implementation uses flow-sensitive points-to information. - Flow-sensitivity refers to accesses to the pointer, and not the object - pointed. For instance, we do not warn about the following case. - - Example 2. - int* a = (int*)malloc (...); - float* b = reinterpret_cast<float*> (a); - *b = 2.0; - a = (int*)malloc (...); - return *a; - - In SSA, it becomes clear that the INT value *A_2 referenced in the - return statement is not aliased to the FLOAT defined through *B_1. - int* a_1 = (int*)malloc (...); - float* b_1 = reinterpret_cast<float*> (a_1); - *b_1 = 2.0; - a_2 = (int*)malloc (...); - return *a_2; - - - Algorithm Outline - ================= - - ForEach (ptr, object) in the points-to table - If (incompatible_types (*ptr, object)) - If (referenced (ptr, current function) - and referenced (object, current function)) - Issue warning (ptr, object, reference locations) - - The complexity is: - O (sizeof (points-to table) - + sizeof (function body) * lookup_time (points-to table)) - - Pointer dereference locations are looked up on demand. The search is - a single scan of the function body, in which all references to pointers - and objects in the points-to table are recorded. However, this dominant - time factor occurs rarely, only when cross-type aliasing was detected. - - - Limitations of the Proposed Implementation - ========================================== - - 1. We do not catch the following case, because -fstrict-aliasing will - associate different tags with MEM while building points-to information, - thus before we get to analyze it. - XXX: this could be solved by either running with -fno-strict-aliasing - or by recording the points-to information before splitting the original - tag based on type. - - Example 3. - void* mem = malloc (...); - int* pi = reinterpret_cast<int*> (mem); - float* b = reinterpret_cast<float*> (mem); - *b = 2.0; - return *pi+1; - - 2. We do not check whether the two conflicting (de)references can - reach each other in the control flow sense. If we fixed limitation - 1, we would wrongly issue a warning in the following case. - - Example 4. - void* raw = malloc (...); - if (...) { - float* b = reinterpret_cast<float*> (raw); - *b = 2.0; - return (int)*b; - } else { - int* a = reinterpret_cast<int*> (raw); - *a = 1; - return *a; - - 3. Only simple types are compared, thus no structures, unions or classes - are analyzed. A first attempt to deal with structures introduced much - complication and has not showed much improvement in preliminary tests, - so it was left out. - - 4. All analysis is intraprocedural. */ - - -/* Local declarations. */ -static void find_references_in_function (void); - - - -/* Get main type of tree TYPE, stripping array dimensions and qualifiers. */ - -static tree -get_main_type (tree type) -{ - while (TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - return TYPE_MAIN_VARIANT (type); -} - - -/* Get the type of the given object. If IS_PTR is true, get the type of the - object pointed to or referenced by OBJECT instead. - For arrays, return the element type. Ignore all qualifiers. */ - -static tree -get_otype (tree object, bool is_ptr) -{ - tree otype = TREE_TYPE (object); - - if (is_ptr) - { - gcc_assert (POINTER_TYPE_P (otype)); - otype = TREE_TYPE (otype); - } - return get_main_type (otype); -} - - -/* Return true if tree TYPE is struct, class or union. */ - -static bool -struct_class_union_p (tree type) -{ - return (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == UNION_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE); -} - - - -/* Keep data during a search for an aliasing site. - RHS = object or pointer aliased. No LHS is specified because we are only - looking in the UseDef paths of a given variable, so LHS will always be - an SSA name of the same variable. - When IS_RHS_POINTER = true, we are looking for ... = RHS. Otherwise, - we are looking for ... = &RHS. - SITE is the output of a search, non-NULL if the search succeeded. */ - -struct alias_match -{ - tree rhs; - bool is_rhs_pointer; - gimple site; -}; - - -/* Callback for find_alias_site. Return true if the right hand site - of STMT matches DATA. */ - -static bool -find_alias_site_helper (tree var ATTRIBUTE_UNUSED, gimple stmt, void *data) -{ - struct alias_match *match = (struct alias_match *) data; - tree rhs_pointer = NULL_TREE; - tree to_match = NULL_TREE; - - if (gimple_assign_cast_p (stmt)) - rhs_pointer = gimple_assign_rhs1 (stmt); - - if (!rhs_pointer) - /* Not a type conversion. */ - return false; - - if (TREE_CODE (rhs_pointer) == ADDR_EXPR && !match->is_rhs_pointer) - to_match = TREE_OPERAND (rhs_pointer, 0); - else if (POINTER_TYPE_P (rhs_pointer) && match->is_rhs_pointer) - to_match = rhs_pointer; - - if (to_match != match->rhs) - /* Type conversion, but not a name match. */ - return false; - - /* Found it. */ - match->site = stmt; - return true; -} - - -/* Find the statement where OBJECT1 gets aliased to OBJECT2. - If IS_PTR2 is true, consider OBJECT2 to be the name of a pointer or - reference rather than the actual aliased object. - For now, just implement the case where OBJECT1 is an SSA name defined - by a PHI statement. */ - -static gimple -find_alias_site (tree object1, bool is_ptr1 ATTRIBUTE_UNUSED, - tree object2, bool is_ptr2) -{ - struct alias_match match; - - match.rhs = object2; - match.is_rhs_pointer = is_ptr2; - match.site = NULL; - - if (TREE_CODE (object1) != SSA_NAME) - return NULL; - - walk_use_def_chains (object1, find_alias_site_helper, &match, false); - return match.site; -} - - -/* Structure to store temporary results when trying to figure out whether - an object is referenced. Just its presence in the text is not enough, - as we may just be taking its address. */ - -struct match_info -{ - tree object; - bool is_ptr; - /* The difference between the number of references to OBJECT - and the number of occurrences of &OBJECT. */ - int found; -}; - - -/* Return the base if EXPR is an SSA name. Return EXPR otherwise. */ - -static tree -get_ssa_base (tree expr) -{ - if (TREE_CODE (expr) == SSA_NAME) - return SSA_NAME_VAR (expr); - else - return expr; -} - - -/* Record references to objects and pointer dereferences across some piece of - code. The number of references is recorded for each item. - References to an object just to take its address are not counted. - For instance, if PTR is a pointer and OBJ is an object: - 1. Expression &obj + *ptr will have the following reference match structure: - ptrs: <ptr, 1> - objs: <ptr, 1> - OBJ does not appear as referenced because we just take its address. - 2. Expression ptr + *ptr will have the following reference match structure: - ptrs: <ptr, 1> - objs: <ptr, 2> - PTR shows up twice as an object, but is dereferenced only once. - - The elements of the hash tables are gimple_map objects. */ -struct reference_matches -{ - htab_t ptrs; - htab_t objs; -}; - -struct gimple_tree_map -{ - tree from; - gimple to; -}; - -/* Return true if the from tree in both gimple-tree maps are equal. - VA and VB are really instances of struct gimple_tree_map. */ - -static int -gimple_tree_map_eq (const void *va, const void *vb) -{ - const struct gimple_tree_map *const a = (const struct gimple_tree_map *) va; - const struct gimple_tree_map *const b = (const struct gimple_tree_map *) vb; - return (a->from == b->from); -} - -/* Hash a from tree in a gimple_tree_map. ITEM is really an instance - of struct gimple_tree_map. */ - -static unsigned int -gimple_tree_map_hash (const void *item) -{ - return htab_hash_pointer (((const struct gimple_tree_map *)item)->from); -} - -/* Return the match, if any. Otherwise, return NULL. It will return - NULL even when a match was found, if the value associated to KEY is - NULL. */ - -static inline gimple -match (htab_t ref_map, tree key) -{ - struct gimple_tree_map *found; - void **slot = NULL; - slot = htab_find_slot (ref_map, &key, NO_INSERT); - - if (!slot) - return NULL; - - found = (struct gimple_tree_map *) *slot; - - return found->to; -} - - -/* Set the entry corresponding to KEY, but only if the entry - already exists and its value is NULL_TREE. Otherwise, do nothing. */ - -static inline void -maybe_add_match (htab_t ref_map, struct gimple_tree_map *key) -{ - struct gimple_tree_map *found; - - found = (struct gimple_tree_map *) htab_find (ref_map, key); - - if (found && !found->to) - found->to = key->to; -} - - -/* Add an entry to HT, with key T and value NULL_TREE. */ - -static void -add_key (htab_t ht, tree t, alloc_pool references_pool) -{ - void **slot; - struct gimple_tree_map *tp; - - tp = (struct gimple_tree_map *) pool_alloc (references_pool); - - tp->from = t; - tp->to = NULL; - slot = htab_find_slot (ht, &t, INSERT); - *slot = (void *) tp; -} - - -/* Some memory to keep the objects in the reference table. */ - -static alloc_pool ref_table_alloc_pool = NULL; - - -/* Get some memory to keep the objects in the reference table. */ - -static inline alloc_pool -reference_table_alloc_pool (bool build) -{ - if (ref_table_alloc_pool || !build) - return ref_table_alloc_pool; - - ref_table_alloc_pool = create_alloc_pool ("ref_table_alloc_pool", - sizeof (struct gimple_tree_map), - 20); - - return ref_table_alloc_pool; -} - - -/* Initialize the reference table by adding all pointers in the points-to - table as keys, and NULL_TREE as associated values. */ - -static struct reference_matches * -build_reference_table (void) -{ - unsigned int i; - struct reference_matches *ref_table = NULL; - alloc_pool references_pool = reference_table_alloc_pool (true); - - ref_table = XNEW (struct reference_matches); - ref_table->objs = htab_create (10, gimple_tree_map_hash, gimple_tree_map_eq, - NULL); - ref_table->ptrs = htab_create (10, gimple_tree_map_hash, gimple_tree_map_eq, - NULL); - - for (i = 1; i < num_ssa_names; i++) - { - tree ptr = ssa_name (i); - struct ptr_info_def *pi; - - if (ptr == NULL_TREE) - continue; - - pi = SSA_NAME_PTR_INFO (ptr); - - if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->name_mem_tag) - { - /* Add pointer to the interesting dereference list. */ - add_key (ref_table->ptrs, ptr, references_pool); - - /* Add all aliased names to the interesting reference list. */ - if (pi->pt_vars) - { - unsigned ix; - bitmap_iterator bi; - - EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi) - { - tree alias = referenced_var (ix); - add_key (ref_table->objs, alias, references_pool); - } - } - } - } - - return ref_table; -} - - -/* Reference table. */ - -static struct reference_matches *ref_table = NULL; - - -/* Clean up the reference table if allocated. */ - -static void -maybe_free_reference_table (void) -{ - if (ref_table) - { - htab_delete (ref_table->ptrs); - htab_delete (ref_table->objs); - free (ref_table); - ref_table = NULL; - } - - if (ref_table_alloc_pool) - { - free_alloc_pool (ref_table_alloc_pool); - ref_table_alloc_pool = NULL; - } -} - - -/* Get the reference table. Initialize it if needed. */ - -static inline struct reference_matches * -reference_table (bool build) -{ - if (ref_table || !build) - return ref_table; - - ref_table = build_reference_table (); - find_references_in_function (); - return ref_table; -} - - -/* Callback for find_references_in_function. - Check whether *TP is an object reference or pointer dereference for the - variables given in ((struct match_info*)DATA)->OBJS or - ((struct match_info*)DATA)->PTRS. The total number of references - is stored in the same structures. */ - -static tree -find_references_in_tree_helper (tree *tp, - int *walk_subtrees ATTRIBUTE_UNUSED, - void *data) -{ - struct gimple_tree_map match; - static int parent_tree_code = ERROR_MARK; - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - - /* Do not report references just for the purpose of taking an address. - XXX: we rely on the fact that the tree walk is in preorder - and that ADDR_EXPR is not a leaf, thus cannot be carried over across - walks. */ - if (parent_tree_code == ADDR_EXPR) - goto finish; - - match.to = (gimple) wi->info; - - if (TREE_CODE (*tp) == INDIRECT_REF) - { - match.from = TREE_OPERAND (*tp, 0); - maybe_add_match (reference_table (true)->ptrs, &match); - } - else - { - match.from = *tp; - maybe_add_match (reference_table (true)->objs, &match); - } - -finish: - parent_tree_code = TREE_CODE (*tp); - return NULL_TREE; -} - - -/* Find all the references to aliased variables in the current function. */ - -static void -find_references_in_function (void) -{ - basic_block bb; - gimple_stmt_iterator i; - - FOR_EACH_BB (bb) - for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) - { - struct walk_stmt_info wi; - memset (&wi, 0, sizeof (wi)); - wi.info = (void *) gsi_stmt (i); - walk_gimple_op (gsi_stmt (i), find_references_in_tree_helper, &wi); - } -} - - -/* Find the reference site for OBJECT. - If IS_PTR is true, look for dereferences of OBJECT instead. - XXX: only the first site is returned in the current - implementation. If there are no matching sites, return NULL_TREE. */ - -static gimple -reference_site (tree object, bool is_ptr) -{ - if (is_ptr) - return match (reference_table (true)->ptrs, object); - else - return match (reference_table (true)->objs, object); -} - - -/* Try to get more location info when something is missing. - OBJECT1 and OBJECT2 are aliased names. If IS_PTR1 or IS_PTR2, the alias - is on the memory referenced or pointed to by OBJECT1 and OBJECT2. - ALIAS_SITE, DEREF_SITE1 and DEREF_SITE2 are the statements where the - alias takes place (some pointer assignment usually) and where the - alias is referenced through OBJECT1 and OBJECT2 respectively. - REF_TYPE1 and REF_TYPE2 will return the type of the reference at the - respective sites. Only the first matching reference is returned for - each name. If no statement is found, the function header is returned. */ - -static void -maybe_find_missing_stmts (tree object1, bool is_ptr1, - tree object2, bool is_ptr2, - gimple *alias_site, - gimple *deref_site1, - gimple *deref_site2) -{ - if (object1 && object2) - { - if (!*alias_site || !gimple_has_location (*alias_site)) - *alias_site = find_alias_site (object1, is_ptr1, object2, is_ptr2); - - if (!*deref_site1 || !gimple_has_location (*deref_site1)) - *deref_site1 = reference_site (object1, is_ptr1); - - if (!*deref_site2 || !gimple_has_location (*deref_site2)) - *deref_site2 = reference_site (object2, is_ptr2); - } - - /* If we could not find the alias site, set it to one of the dereference - sites, if available. */ - if (!*alias_site) - { - if (*deref_site1) - *alias_site = *deref_site1; - else if (*deref_site2) - *alias_site = *deref_site2; - } - - /* If we could not find the dereference sites, set them to the alias site, - if known. */ - if (!*deref_site1 && *alias_site) - *deref_site1 = *alias_site; - if (!*deref_site2 && *alias_site) - *deref_site2 = *alias_site; -} - - -/* Callback for find_first_artificial_name. - Find out if there are no artificial names at tree node *T. */ - -static tree -ffan_walker (tree *t, - int *go_below ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - if (DECL_P (*t) && !MTAG_P (*t) && DECL_ARTIFICIAL (*t)) - return *t; - else - return NULL_TREE; -} - -/* Return the first artificial name within EXPR, or NULL_TREE if - none exists. */ - -static tree -find_first_artificial_name (tree expr) -{ - return walk_tree_without_duplicates (&expr, ffan_walker, NULL); -} - - -/* Get a name from the original program for VAR. */ - -static const char * -get_var_name (tree var) -{ - if (TREE_CODE (var) == SSA_NAME) - return get_var_name (get_ssa_base (var)); - - if (find_first_artificial_name (var)) - return "{unknown}"; - - if (TREE_CODE (var) == VAR_DECL || TREE_CODE (var) == PARM_DECL) - if (DECL_NAME (var)) - return IDENTIFIER_POINTER (DECL_NAME (var)); - - return "{unknown}"; -} - - -/* Return "*" if OBJECT is not the actual alias but a pointer to it, or - "" otherwise. - IS_PTR is true when OBJECT is not the actual alias. - In addition to checking IS_PTR, we also make sure that OBJECT is a pointer - since IS_PTR would also be true for C++ references, but we should only - print a * before a pointer and not before a reference. */ - -static const char * -get_maybe_star_prefix (tree object, bool is_ptr) -{ - gcc_assert (object); - return (is_ptr - && TREE_CODE (TREE_TYPE (object)) == POINTER_TYPE) ? "*" : ""; -} - -/* Callback for contains_node_type_p. - Returns true if *T has tree code *(int*)DATA. */ - -static tree -contains_node_type_p_callback (tree *t, - int *go_below ATTRIBUTE_UNUSED, - void *data) -{ - return ((int) TREE_CODE (*t) == *((int *) data)) ? *t : NULL_TREE; -} - - -/* Return true if T contains a node with tree code TYPE. */ - -static bool -contains_node_type_p (tree t, int type) -{ - return (walk_tree_without_duplicates (&t, contains_node_type_p_callback, - (void *) &type) - != NULL_TREE); -} - - -/* Return true if a warning was issued in the front end at STMT. */ - -static bool -already_warned_in_frontend_p (gimple stmt) -{ - if (stmt == NULL) - return false; - - if (gimple_assign_cast_p (stmt) - && TREE_NO_WARNING (gimple_assign_rhs1 (stmt))) - return true; - else - return false; -} - - -/* Return true if and only if TYPE is a function or method pointer type, - or pointer to a pointer to ... to a function or method. */ - -static bool -is_method_pointer (tree type) -{ - while (TREE_CODE (type) == POINTER_TYPE) - type = TREE_TYPE (type); - return TREE_CODE (type) == METHOD_TYPE || TREE_CODE (type) == FUNCTION_TYPE; -} - - -/* Issue a -Wstrict-aliasing warning. - OBJECT1 and OBJECT2 are aliased names. - If IS_PTR1 and/or IS_PTR2 is true, then the corresponding name - OBJECT1/OBJECT2 is a pointer or reference to the aliased memory, - rather than actual storage. - ALIAS_SITE is a statement where the alias took place. In the most common - case, that is where a pointer was assigned to the address of an object. */ - -static bool -strict_aliasing_warn (gimple alias_site, - tree object1, bool is_ptr1, - tree object2, bool is_ptr2, - bool filter_artificials) -{ - gimple ref_site1 = NULL; - gimple ref_site2 = NULL; - const char *name1; - const char *name2; - location_t alias_loc; - location_t ref1_loc; - location_t ref2_loc; - gcc_assert (object1); - gcc_assert (object2); - name1 = get_var_name (object1); - name2 = get_var_name (object2); - - - if (is_method_pointer (get_main_type (TREE_TYPE (object2)))) - return false; - - maybe_find_missing_stmts (object1, is_ptr1, object2, is_ptr2, &alias_site, - &ref_site1, &ref_site2); - - if (gimple_has_location (alias_site)) - alias_loc = gimple_location (alias_site); - else - return false; - - if (gimple_has_location (ref_site1)) - ref1_loc = gimple_location (ref_site1); - else - ref1_loc = alias_loc; - - if (gimple_has_location (ref_site2)) - ref2_loc = gimple_location (ref_site2); - else - ref2_loc = alias_loc; - - if (already_warned_in_frontend_p (alias_site)) - return false; - - /* If they are not SSA names, but contain SSA names, drop the warning - because it cannot be displayed well. - Also drop it if they both contain artificials. - XXX: this is a hack, must figure out a better way to display them. */ - if (filter_artificials) - if ((find_first_artificial_name (get_ssa_base (object1)) - && find_first_artificial_name (get_ssa_base (object2))) - || (TREE_CODE (object1) != SSA_NAME - && contains_node_type_p (object1, SSA_NAME)) - || (TREE_CODE (object2) != SSA_NAME - && contains_node_type_p (object2, SSA_NAME))) - return false; - - - /* XXX: In the following format string, %s:%d should be replaced by %H. - However, in my tests only the first %H printed ok, while the - second and third were printed as blanks. */ - warning (OPT_Wstrict_aliasing, - "%Hlikely type-punning may break strict-aliasing rules: " - "object %<%s%s%> of main type %qT is referenced at or around " - "%s:%d and may be " - "aliased to object %<%s%s%> of main type %qT which is referenced " - "at or around %s:%d.", - &alias_loc, - get_maybe_star_prefix (object1, is_ptr1), - name1, get_otype (object1, is_ptr1), - LOCATION_FILE (ref1_loc), LOCATION_LINE (ref1_loc), - get_maybe_star_prefix (object2, is_ptr2), - name2, get_otype (object2, is_ptr2), - LOCATION_FILE (ref2_loc), LOCATION_LINE (ref2_loc)); - - return true; -} - - - -/* Return true when any objects of TYPE1 and TYPE2 respectively - may not be aliased according to the language standard. */ - -static bool -nonstandard_alias_types_p (tree type1, tree type2) -{ - alias_set_type set1; - alias_set_type set2; - - if (VOID_TYPE_P (type1) || VOID_TYPE_P (type2)) - return false; - - set1 = get_alias_set (type1); - set2 = get_alias_set (type2); - return !alias_sets_conflict_p (set1, set2); -} - - - -/* Returns true when *PTR may not be aliased to ALIAS. - See C standard 6.5p7 and C++ standard 3.10p15. - If PTR_PTR is true, ALIAS represents a pointer or reference to the - aliased storage rather than its actual name. */ - -static bool -nonstandard_alias_p (tree ptr, tree alias, bool ptr_ptr) -{ - /* Find the types to compare. */ - tree ptr_type = get_otype (ptr, true); - tree alias_type = get_otype (alias, ptr_ptr); - - /* If this is a ref-all pointer the access is ok. */ - if (TYPE_REF_CAN_ALIAS_ALL (TREE_TYPE (ptr))) - return false; - - /* XXX: for now, say it's OK if the alias escapes. - Not sure this is needed in general, but otherwise GCC will not - bootstrap. */ - if (var_ann (get_ssa_base (alias))->escape_mask != NO_ESCAPE) - return false; - - /* XXX: don't get into structures for now. It brings much complication - and little benefit. */ - if (struct_class_union_p (ptr_type) || struct_class_union_p (alias_type)) - return false; - - /* If they are both SSA names of artificials, let it go, the warning - is too confusing. */ - if (find_first_artificial_name (ptr) && find_first_artificial_name (alias)) - return false; - - /* Compare the types. */ - return nonstandard_alias_types_p (ptr_type, alias_type); -} - - -/* Return true when we should skip analysis for pointer PTR based on the - fact that their alias information *PI is not considered relevant. */ - -static bool -skip_this_pointer (tree ptr ATTRIBUTE_UNUSED, struct ptr_info_def *pi) -{ - /* If it is not dereferenced, it is not a problem (locally). */ - if (!pi->is_dereferenced) - return true; - - /* This would probably cause too many false positives. */ - if (pi->value_escapes_p || pi->pt_anything) - return true; - - return false; -} - - -/* Find aliasing to named objects for pointer PTR. */ - -static void -dsa_named_for (tree ptr ATTRIBUTE_UNUSED) -{ - struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr); - - if (pi) - { - if (skip_this_pointer (ptr, pi)) - return; - - /* For all the variables it could be aliased to. */ - if (pi->pt_vars) - { - unsigned ix; - bitmap_iterator bi; - bool any = false; - - EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi) - { - tree alias = referenced_var (ix); - - if (nonstandard_alias_p (ptr, alias, false)) - strict_aliasing_warn (SSA_NAME_DEF_STMT (ptr), - ptr, true, alias, false, true); - else - any = true; - } - - /* If there was no object in the points-to set that the pointer - may alias, unconditionally warn. */ - if (!any) - warning (OPT_Wstrict_aliasing, - "dereferencing type-punned pointer %D will " - "break strict-aliasing rules", SSA_NAME_VAR (ptr)); - } - } -} - - -/* Detect and report strict aliasing violation of named objects. */ - -static void -detect_strict_aliasing_named (void) -{ - unsigned int i; - - for (i = 1; i < num_ssa_names; i++) - { - tree ptr = ssa_name (i); - struct ptr_info_def *pi; - - if (ptr == NULL_TREE) - continue; - - pi = SSA_NAME_PTR_INFO (ptr); - - if (!SSA_NAME_IN_FREE_LIST (ptr) && pi && pi->name_mem_tag) - dsa_named_for (ptr); - } -} - - -/* Return false only the first time I see each instance of FUNC. */ - -static bool -processed_func_p (tree func) -{ - static htab_t seen = NULL; - void **slot = NULL; - - if (!seen) - seen = htab_create (10, gimple_tree_map_hash, gimple_tree_map_eq, NULL); - - slot = htab_find_slot (seen, &func, INSERT); - gcc_assert (slot); - - if (*slot) - return true; - - gcc_assert (slot); - *slot = &func; - return false; -} - - -/* Detect and warn about type-punning using points-to information. */ - -void -strict_aliasing_warning_backend (void) -{ - if (flag_strict_aliasing && warn_strict_aliasing == 3 - && !processed_func_p (current_function_decl)) - { - detect_strict_aliasing_named (); - maybe_free_reference_table (); - } -} |