PR c++/80560 - warn on undefined memory operations involving non-trivial types

gcc/c-family/ChangeLog:

	PR c++/80560
	* c.opt (-Wclass-memaccess): New option.

gcc/cp/ChangeLog:

	PR c++/80560
	* call.c (first_non_public_field, maybe_warn_class_memaccess): New
	functions.
	(has_trivial_copy_assign_p, has_trivial_copy_p): Ditto.
	(build_cxx_call): Call maybe_warn_class_memaccess.

gcc/ChangeLog:

	PR c++/80560
	* dumpfile.c (dump_register): Avoid calling memset to initialize
	a class with a default ctor.
	* gcc.c (struct compiler): Remove const qualification.
	* genattrtab.c (gen_insn_reserv): Replace memset with initialization.
	* hash-table.h: Ditto.
	* ipa-cp.c (allocate_and_init_ipcp_value): Replace memset with
	  assignment.
	* ipa-prop.c (ipa_free_edge_args_substructures): Ditto.
	* omp-low.c (lower_omp_ordered_clauses): Replace memset with
	default ctor.
	* params.h (struct param_info): Make struct members non-const.
	* tree-switch-conversion.c (emit_case_bit_tests): Replace memset
	with default initialization.
	* vec.h (vec_copy_construct, vec_default_construct): New helper
	functions.
	(vec<T>::copy, vec<T>::splice, vec<T>::reserve): Replace memcpy
	with vec_copy_construct.
	(vect<T>::quick_grow_cleared): Replace memset with default ctor.
	(vect<T>::vec_safe_grow_cleared, vec_safe_grow_cleared): Same.
	* doc/invoke.texi (-Wclass-memaccess): Document.

libcpp/ChangeLog:

	PR c++/80560
	* line-map.c (line_maps::~line_maps): Avoid calling htab_delete
	with a null pointer.
	(linemap_init): Avoid calling memset on an object of a non-trivial
	type.

libitm/ChangeLog:

	PR c++/80560
	* beginend.cc (GTM::gtm_thread::rollback): Avoid calling memset
	on an object of a non-trivial type.
	(GTM::gtm_transaction_cp::commit): Use assignment instead of memcpy
	to copy an object.
	* method-ml.cc (orec_iterator::reinit): Avoid -Wclass-memaccess.

gcc/testsuite/ChangeLog:

	PR c++/80560
	* g++.dg/Wclass-memaccess.C: New test.

From-SVN: r249234
This commit is contained in:
Martin Sebor 2017-06-16 03:48:59 +00:00 committed by Martin Sebor
parent 6a382041dd
commit c3684b7b86
21 changed files with 2196 additions and 35 deletions

View File

@ -1,3 +1,27 @@
2017-06-15 Martin Sebor <msebor@redhat.com>
PR c++/80560
* dumpfile.c (dump_register): Avoid calling memset to initialize
a class with a default ctor.
* gcc.c (struct compiler): Remove const qualification.
* genattrtab.c (gen_insn_reserv): Replace memset with initialization.
* hash-table.h: Ditto.
* ipa-cp.c (allocate_and_init_ipcp_value): Replace memset with
assignment.
* ipa-prop.c (ipa_free_edge_args_substructures): Ditto.
* omp-low.c (lower_omp_ordered_clauses): Replace memset with
default ctor.
* params.h (struct param_info): Make struct members non-const.
* tree-switch-conversion.c (emit_case_bit_tests): Replace memset
with default initialization.
* vec.h (vec_copy_construct, vec_default_construct): New helper
functions.
(vec<T>::copy, vec<T>::splice, vec<T>::reserve): Replace memcpy
with vec_copy_construct.
(vect<T>::quick_grow_cleared): Replace memset with default ctor.
(vect<T>::vec_safe_grow_cleared, vec_safe_grow_cleared): Same.
* doc/invoke.texi (-Wclass-memaccess): Document.
2017-06-15 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com>
* emit-rtl.h (is_leaf): Update comment about local

View File

@ -1,3 +1,8 @@
2017-06-15 Martin Sebor <msebor@redhat.com>
PR c++/80560
* c.opt (-Wclass-memaccess): New option.
2017-06-14 Boris Kolpackov <boris@codesynthesis.com>
* c-opts.c (c_common_finish): Handle '-' special value to -MF.

View File

@ -804,6 +804,10 @@ Wnon-template-friend
C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning
Warn when non-templatized friend functions are declared within a template.
Wclass-memaccess
C++ ObjC++ Var(warn_class_memaccess) Warning LangEnabledBy(C++ ObjC++, Wall)
Warn for unsafe raw memory writes to objects of class types.
Wnon-virtual-dtor
C++ ObjC++ Var(warn_nonvdtor) Warning LangEnabledBy(C++ ObjC++,Weffc++)
Warn about non-virtual destructors.

View File

@ -1,3 +1,11 @@
2017-06-15 Martin Sebor <msebor@redhat.com>
PR c++/80560
* call.c (first_non_public_field, maybe_warn_class_memaccess): New
functions.
(has_trivial_copy_assign_p, has_trivial_copy_p): Ditto.
(build_cxx_call): Call maybe_warn_class_memaccess.
2017-06-14 Jakub Jelinek <jakub@redhat.com>
* cp-gimplify.c (cp_genericize_r): Turn most of the function

View File

@ -8184,6 +8184,393 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
return call;
}
/* Return the DECL of the first non-public data member of class TYPE
or null if none can be found. */
static tree
first_non_public_field (tree type)
{
if (!CLASS_TYPE_P (type))
return NULL_TREE;
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
if (TREE_CODE (field) != FIELD_DECL)
continue;
if (TREE_STATIC (field))
continue;
if (TREE_PRIVATE (field) || TREE_PROTECTED (field))
return field;
}
int i = 0;
for (tree base_binfo, binfo = TYPE_BINFO (type);
BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
{
tree base = TREE_TYPE (base_binfo);
if (tree field = first_non_public_field (base))
return field;
}
return NULL_TREE;
}
/* Return true if all copy and move assignment operator overloads for
class TYPE are trivial and at least one of them is not deleted and,
when ACCESS is set, accessible. Return false otherwise. Set
HASASSIGN to true when the TYPE has a (not necessarily trivial)
copy or move assignment. */
static bool
has_trivial_copy_assign_p (tree type, bool access, bool *hasassign)
{
tree fns = cp_assignment_operator_id (NOP_EXPR);
fns = lookup_fnfields_slot (type, fns);
bool all_trivial = true;
/* Iterate over overloads of the assignment operator, checking
accessible copy assignments for triviality. */
for (ovl_iterator oi (fns); oi; ++oi)
{
tree f = *oi;
/* Skip operators that aren't copy assignments. */
if (!copy_fn_p (f))
continue;
bool accessible = (!access || !(TREE_PRIVATE (f) || TREE_PROTECTED (f))
|| accessible_p (TYPE_BINFO (type), f, true));
/* Skip template assignment operators and deleted functions. */
if (TREE_CODE (f) != FUNCTION_DECL || DECL_DELETED_FN (f))
continue;
if (accessible)
*hasassign = true;
if (!accessible || !trivial_fn_p (f))
all_trivial = false;
/* Break early when both properties have been determined. */
if (*hasassign && !all_trivial)
break;
}
/* Return true if they're all trivial and one of the expressions
TYPE() = TYPE() or TYPE() = (TYPE&)() is valid. */
tree ref = cp_build_reference_type (type, false);
return (all_trivial
&& (is_trivially_xible (MODIFY_EXPR, type, type)
|| is_trivially_xible (MODIFY_EXPR, type, ref)));
}
/* Return true if all copy and move ctor overloads for class TYPE are
trivial and at least one of them is not deleted and, when ACCESS is
set, accessible. Return false otherwise. Set each element of HASCTOR[]
to true when the TYPE has a (not necessarily trivial) default and copy
(or move) ctor, respectively. */
static bool
has_trivial_copy_p (tree type, bool access, bool hasctor[2])
{
tree fns = lookup_fnfields_slot (type, complete_ctor_identifier);
bool all_trivial = true;
for (ovl_iterator oi (fns); oi; ++oi)
{
tree f = *oi;
/* Skip template constructors. */
if (TREE_CODE (f) != FUNCTION_DECL)
continue;
bool cpy_or_move_ctor_p = copy_fn_p (f);
/* Skip ctors other than default, copy, and move. */
if (!cpy_or_move_ctor_p && !default_ctor_p (f))
continue;
if (DECL_DELETED_FN (f))
continue;
bool accessible = (!access || !(TREE_PRIVATE (f) || TREE_PROTECTED (f))
|| accessible_p (TYPE_BINFO (type), f, true));
if (accessible)
hasctor[cpy_or_move_ctor_p] = true;
if (cpy_or_move_ctor_p && (!accessible || !trivial_fn_p (f)))
all_trivial = false;
/* Break early when both properties have been determined. */
if (hasctor[0] && hasctor[1] && !all_trivial)
break;
}
return all_trivial;
}
/* Issue a warning on a call to the built-in function FNDECL if it is
a raw memory write whose destination is not an object of (something
like) trivial or standard layout type with a non-deleted assignment
and copy ctor. Detects const correctness violations, corrupting
references, virtual table pointers, and bypassing non-trivial
assignments. */
static void
maybe_warn_class_memaccess (location_t loc, tree fndecl, tree *args)
{
/* Except for bcopy where it's second, the destination pointer is
the first argument for all functions handled here. Compute
the index of the destination and source arguments. */
unsigned dstidx = DECL_FUNCTION_CODE (fndecl) == BUILT_IN_BCOPY;
unsigned srcidx = !dstidx;
tree dest = args[dstidx];
if (!dest || !TREE_TYPE (dest) || !POINTER_TYPE_P (TREE_TYPE (dest)))
return;
STRIP_NOPS (dest);
tree srctype = NULL_TREE;
/* Determine the type of the pointed-to object and whether it's
a complete class type. */
tree desttype = TREE_TYPE (TREE_TYPE (dest));
if (!desttype || !COMPLETE_TYPE_P (desttype) || !CLASS_TYPE_P (desttype))
return;
/* Check to see if the raw memory call is made by a ctor or dtor
with this as the destination argument for the destination type.
If so, be more permissive. */
if (current_function_decl
&& (DECL_CONSTRUCTOR_P (current_function_decl)
|| DECL_DESTRUCTOR_P (current_function_decl))
&& is_this_parameter (dest))
{
tree ctx = DECL_CONTEXT (current_function_decl);
bool special = same_type_ignoring_top_level_qualifiers_p (ctx, desttype);
tree binfo = TYPE_BINFO (ctx);
/* A ctor and dtor for a class with no bases and no virtual functions
can do whatever they want. Bail early with no further checking. */
if (special && !BINFO_VTABLE (binfo) && !BINFO_N_BASE_BINFOS (binfo))
return;
}
/* True if the class is trivial. */
bool trivial = trivial_type_p (desttype);
/* Set to true if DESTYPE has an accessible copy assignment. */
bool hasassign = false;
/* True if all of the class' overloaded copy assignment operators
are all trivial (and not deleted) and at least one of them is
accessible. */
bool trivassign = has_trivial_copy_assign_p (desttype, true, &hasassign);
/* Set to true if DESTTYPE has an accessible default and copy ctor,
respectively. */
bool hasctors[2] = { false, false };
/* True if all of the class' overloaded copy constructors are all
trivial (and not deleted) and at least one of them is accessible. */
bool trivcopy = has_trivial_copy_p (desttype, true, hasctors);
/* Set FLD to the first private/protected member of the class. */
tree fld = trivial ? first_non_public_field (desttype) : NULL_TREE;
/* The warning format string. */
const char *warnfmt = NULL;
/* A suggested alternative to offer instead of the raw memory call.
Empty string when none can be come up with. */
const char *suggest = "";
bool warned = false;
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_MEMSET:
if (!integer_zerop (args[1]))
{
/* Diagnose setting non-copy-assignable or non-trivial types,
or types with a private member, to (potentially) non-zero
bytes. Since the value of the bytes being written is unknown,
suggest using assignment instead (if one exists). Also warn
for writes into objects for which zero-initialization doesn't
mean all bits clear (pointer-to-member data, where null is all
bits set). Since the value being written is (most likely)
non-zero, simply suggest assignment (but not copy assignment). */
suggest = "; use assignment instead";
if (!trivassign)
warnfmt = G_("%qD writing to an object of type %#qT with "
"no trivial copy-assignment");
else if (!trivial)
warnfmt = G_("%qD writing to an object of non-trivial type %#qT%s");
else if (fld)
{
const char *access = TREE_PRIVATE (fld) ? "private" : "protected";
warned = warning_at (loc, OPT_Wclass_memaccess,
"%qD writing to an object of type %#qT with "
"%qs member %qD",
fndecl, desttype, access, fld);
}
else if (!zero_init_p (desttype))
warnfmt = G_("%qD writing to an object of type %#qT containing "
"a pointer to data member%s");
break;
}
/* Fall through. */
case BUILT_IN_BZERO:
/* Similarly to the above, diagnose clearing non-trivial or non-
standard layout objects, or objects of types with no assignmenmt.
Since the value being written is known to be zero, suggest either
copy assignment, copy ctor, or default ctor as an alternative,
depending on what's available. */
if (hasassign && hasctors[0])
suggest = G_("; use assignment or value-initialization instead");
else if (hasassign)
suggest = G_("; use assignment instead");
else if (hasctors[0])
suggest = G_("; use value-initialization instead");
if (!trivassign)
warnfmt = G_("%qD clearing an object of type %#qT with "
"no trivial copy-assignment%s");
else if (!trivial)
warnfmt = G_("%qD clearing an object of non-trivial type %#qT%s");
else if (!zero_init_p (desttype))
warnfmt = G_("%qD clearing an object of type %#qT containing "
"a pointer-to-member%s");
break;
case BUILT_IN_BCOPY:
case BUILT_IN_MEMCPY:
case BUILT_IN_MEMMOVE:
case BUILT_IN_MEMPCPY:
/* Determine the type of the source object. */
srctype = STRIP_NOPS (args[srcidx]);
srctype = TREE_TYPE (TREE_TYPE (srctype));
/* Since it's impossible to determine wheter the byte copy is
being used in place of assignment to an existing object or
as a substitute for initialization, assume it's the former.
Determine the best alternative to use instead depending on
what's not deleted. */
if (hasassign && hasctors[1])
suggest = G_("; use copy-assignment or copy-initialization instead");
else if (hasassign)
suggest = G_("; use copy-assignment instead");
else if (hasctors[1])
suggest = G_("; use copy-initialization instead");
if (!trivassign)
warnfmt = G_("%qD writing to an object of type %#qT with no trivial "
"copy-assignment%s");
else if (!trivially_copyable_p (desttype))
warnfmt = G_("%qD writing to an object of non-trivially copyable "
"type %#qT%s");
else if (!trivcopy)
warnfmt = G_("%qD writing to an object with a deleted copy constructor");
else if (!trivial
&& !VOID_TYPE_P (srctype)
&& !char_type_p (TYPE_MAIN_VARIANT (srctype))
&& !same_type_ignoring_top_level_qualifiers_p (desttype,
srctype))
{
/* Warn when copying into a non-trivial object from an object
of a different type other than void or char. */
warned = warning_at (loc, OPT_Wclass_memaccess,
"%qD copying an object of non-trivial type "
"%#qT from an array of %#qT",
fndecl, desttype, srctype);
}
else if (fld
&& !VOID_TYPE_P (srctype)
&& !char_type_p (TYPE_MAIN_VARIANT (srctype))
&& !same_type_ignoring_top_level_qualifiers_p (desttype,
srctype))
{
const char *access = TREE_PRIVATE (fld) ? "private" : "protected";
warned = warning_at (loc, OPT_Wclass_memaccess,
"%qD copying an object of type %#qT with "
"%qs member %qD from an array of %#qT; use "
"assignment or copy-initialization instead",
fndecl, desttype, access, fld, srctype);
}
else if (!trivial && TREE_CODE (args[2]) == INTEGER_CST)
{
/* Finally, warn on partial copies. */
unsigned HOST_WIDE_INT typesize
= tree_to_uhwi (TYPE_SIZE_UNIT (desttype));
if (unsigned HOST_WIDE_INT partial
= tree_to_uhwi (args[2]) % typesize)
warned = warning_at (loc, OPT_Wclass_memaccess,
(typesize - partial > 1
? G_("%qD writing to an object of "
"a non-trivial type %#qT leaves %wu "
"bytes unchanged")
: G_("%qD writing to an object of "
"a non-trivial type %#qT leaves %wu "
"byte unchanged")),
fndecl, desttype, typesize - partial);
}
break;
case BUILT_IN_REALLOC:
if (!trivially_copyable_p (desttype))
warnfmt = G_("%qD moving an object of non-trivially copyable type "
"%#qT; use %<new%> and %<delete%> instead");
else if (!trivcopy)
warnfmt = G_("%qD moving an object of type %#qT with deleted copy "
"constructor; use %<new%> and %<delete%> instead");
else if (!get_dtor (desttype, tf_none))
warnfmt = G_("%qD moving an object of type %#qT with deleted "
"destructor");
else if (!trivial
&& TREE_CODE (args[1]) == INTEGER_CST
&& tree_int_cst_lt (args[1], TYPE_SIZE_UNIT (desttype)))
{
/* Finally, warn on reallocation into insufficient space. */
warned = warning_at (loc, OPT_Wclass_memaccess,
"%qD moving an object of non-trivial type "
"%#qT and size %E into a region of size %E",
fndecl, desttype, TYPE_SIZE_UNIT (desttype),
args[1]);
}
break;
default:
return;
}
if (!warned && !warnfmt)
return;
if (warnfmt)
{
if (suggest)
warned = warning_at (loc, OPT_Wclass_memaccess,
warnfmt, fndecl, desttype, suggest);
else
warned = warning_at (loc, OPT_Wclass_memaccess,
warnfmt, fndecl, desttype);
}
if (warned)
inform (location_of (desttype), "%#qT declared here", desttype);
}
/* Build and return a call to FN, using NARGS arguments in ARGARRAY.
This function performs no overload resolution, conversion, or other
high-level operations. */
@ -8216,6 +8603,10 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl,
nargs, argarray))
return error_mark_node;
/* Warn if the built-in writes to an object of a non-trivial type. */
if (nargs)
maybe_warn_class_memaccess (loc, fndecl, argarray);
}
/* If it is a built-in array notation function, then the return type of

View File

@ -215,7 +215,8 @@ in the following sections.
-Wabi=@var{n} -Wabi-tag -Wconversion-null -Wctor-dtor-privacy @gol
-Wdelete-non-virtual-dtor -Wliteral-suffix -Wmultiple-inheritance @gol
-Wnamespaces -Wnarrowing @gol
-Wnoexcept -Wnoexcept-type -Wnon-virtual-dtor -Wreorder -Wregister @gol
-Wnoexcept -Wnoexcept-type -Wclass-memaccess @gol
-Wnon-virtual-dtor -Wreorder -Wregister @gol
-Weffc++ -Wstrict-null-sentinel -Wtemplates @gol
-Wno-non-template-friend -Wold-style-cast @gol
-Woverloaded-virtual -Wno-pmf-conversions @gol
@ -2920,6 +2921,23 @@ void g() noexcept;
void h() @{ f(g); @} // in C++14 calls f<void(*)()>, in C++1z calls f<void(*)()noexcept>
@end smallexample
@item -Wclass-memaccess @r{(C++ and Objective-C++ only)}
@opindex Wclass-memaccess
Warn when the destination of a call to a raw memory function such as
@code{memset} or @code{memcpy} is an object of class type writing into which
might bypass the class non-trivial or deleted constructor or copy assignment,
violate const-correctness or encapsulation, or corrupt the virtual table.
Modifying the representation of such objects may violate invariants maintained
by member functions of the class. For example, the call to @code{memset}
below is undefined becase it modifies a non-trivial class object and is,
therefore, diagnosed. The safe way to either initialize or clear the storage
of objects of such types is by using the appropriate constructor or assignment
operator, if one is available.
@smallexample
std::string str = "abc";
memset (&str, 0, 3);
@end smallexample
The @option{-Wclass-memaccess} option is enabled by @option{-Wall}.
@item -Wnon-virtual-dtor @r{(C++ and Objective-C++ only)}
@opindex Wnon-virtual-dtor

View File

@ -187,9 +187,16 @@ dump_register (const char *suffix, const char *swtch, const char *glob,
m_extra_dump_files = XRESIZEVEC (struct dump_file_info,
m_extra_dump_files,
m_extra_dump_files_alloced);
/* Construct a new object in the space allocated above. */
new (m_extra_dump_files + count) dump_file_info ();
}
else
{
/* Zero out the already constructed object. */
m_extra_dump_files[count] = dump_file_info ();
}
memset (&m_extra_dump_files[count], 0, sizeof (struct dump_file_info));
m_extra_dump_files[count].suffix = suffix;
m_extra_dump_files[count].swtch = swtch;
m_extra_dump_files[count].glob = glob;

View File

@ -1259,9 +1259,9 @@ struct compiler
const char *cpp_spec; /* If non-NULL, substitute this spec
for `%C', rather than the usual
cpp_spec. */
const int combinable; /* If nonzero, compiler can deal with
int combinable; /* If nonzero, compiler can deal with
multiple source files at once (IMA). */
const int needs_preprocessing; /* If nonzero, source files need to
int needs_preprocessing; /* If nonzero, source files need to
be run through a preprocessor. */
};

View File

@ -4703,8 +4703,8 @@ gen_insn_reserv (md_rtx_info *info)
struct insn_reserv *decl = oballoc (struct insn_reserv);
rtx def = info->def;
struct attr_desc attr;
memset (&attr, 0, sizeof (attr));
struct attr_desc attr = { };
attr.name = DEF_ATTR_STRING (XSTR (def, 0));
attr.loc = info->loc;

View File

@ -803,7 +803,10 @@ hash_table<Descriptor, Allocator>::empty_slow ()
m_size_prime_index = nindex;
}
else
memset (entries, 0, size * sizeof (value_type));
{
for ( ; size; ++entries, --size)
*entries = value_type ();
}
m_n_deleted = 0;
m_n_elements = 0;
}

View File

@ -1471,8 +1471,7 @@ allocate_and_init_ipcp_value (tree source)
{
ipcp_value<tree> *val;
val = ipcp_cst_values_pool.allocate ();
memset (val, 0, sizeof (*val));
val = new (ipcp_cst_values_pool.allocate ()) ipcp_value<tree>();
val->value = source;
return val;
}
@ -1486,8 +1485,8 @@ allocate_and_init_ipcp_value (ipa_polymorphic_call_context source)
ipcp_value<ipa_polymorphic_call_context> *val;
// TODO
val = ipcp_poly_ctx_values_pool.allocate ();
memset (val, 0, sizeof (*val));
val = new (ipcp_poly_ctx_values_pool.allocate ())
ipcp_value<ipa_polymorphic_call_context>();
val->value = source;
return val;
}

View File

@ -3711,7 +3711,7 @@ void
ipa_free_edge_args_substructures (struct ipa_edge_args *args)
{
vec_free (args->jump_functions);
memset (args, 0, sizeof (*args));
*args = ipa_edge_args ();
}
/* Free all ipa_edge structures. */

View File

@ -6320,7 +6320,11 @@ lower_omp_ordered_clauses (gimple_stmt_iterator *gsi_p, gomp_ordered *ord_stmt,
return;
wide_int *folded_deps = XALLOCAVEC (wide_int, 2 * len - 1);
memset (folded_deps, 0, sizeof (*folded_deps) * (2 * len - 1));
/* wide_int is not a POD so it must be default-constructed. */
for (unsigned i = 0; i != 2 * len - 1; ++i)
new (static_cast<void*>(folded_deps + i)) wide_int ();
tree folded_dep = NULL_TREE;
/* TRUE if the first dimension's offset is negative. */
bool neg_offset_p = false;

View File

@ -42,7 +42,7 @@ struct param_info
{
/* The name used with the `--param <name>=<value>' switch to set this
value. */
const char *const option;
const char *option;
/* The default value. */
int default_value;
@ -54,7 +54,7 @@ struct param_info
int max_value;
/* A short description of the option. */
const char *const help;
const char *help;
/* The optional names corresponding to the values. */
const char **value_names;

View File

@ -1,3 +1,8 @@
2017-06-15 Martin Sebor <msebor@redhat.com>
PR c++/80560
* g++.dg/Wclass-memaccess.C: New test.
2017-06-15 Janus Weil <janus@gcc.gnu.org>
PR fortran/80983

File diff suppressed because it is too large Load Diff

View File

@ -268,7 +268,7 @@ static void
emit_case_bit_tests (gswitch *swtch, tree index_expr,
tree minval, tree range, tree maxval)
{
struct case_bit_test test[MAX_CASE_BIT_TESTS];
struct case_bit_test test[MAX_CASE_BIT_TESTS] = { };
unsigned int i, j, k;
unsigned int count;
@ -293,8 +293,6 @@ emit_case_bit_tests (gswitch *swtch, tree index_expr,
int prec = TYPE_PRECISION (word_type_node);
wide_int wone = wi::one (prec);
memset (&test, 0, sizeof (test));
/* Get the edge for the default case. */
tmp = gimple_switch_default_label (swtch);
default_bb = label_to_block (CASE_LABEL (tmp));

View File

@ -407,6 +407,26 @@ struct GTY((user)) vec
{
};
/* Default-construct N elements in DST. */
template <typename T>
inline void
vec_default_construct (T *dst, unsigned n)
{
for ( ; n; ++dst, --n)
::new (static_cast<void*>(dst)) T ();
}
/* Copy-construct N elements in DST from *SRC. */
template <typename T>
inline void
vec_copy_construct (T *dst, const T *src, unsigned n)
{
for ( ; n; ++dst, ++src, --n)
::new (static_cast<void*>(dst)) T (*src);
}
/* Type to provide NULL values for vec<T, A, L>. This is used to
provide nil initializers for vec instances. Since vec must be
a POD, we cannot have proper ctor/dtor for it. To initialize
@ -612,7 +632,7 @@ vec_safe_grow_cleared (vec<T, A, vl_embed> *&v, unsigned len CXX_MEM_STAT_INFO)
{
unsigned oldlen = vec_safe_length (v);
vec_safe_grow (v, len PASS_MEM_STAT);
memset (&(v->address ()[oldlen]), 0, sizeof (T) * (len - oldlen));
vec_default_construct (v->address () + oldlen, len - oldlen);
}
@ -818,7 +838,7 @@ vec<T, A, vl_embed>::copy (ALONE_MEM_STAT_DECL) const
{
vec_alloc (new_vec, len PASS_MEM_STAT);
new_vec->embedded_init (len, len);
memcpy (new_vec->address (), m_vecdata, sizeof (T) * len);
vec_copy_construct (new_vec->address (), m_vecdata, len);
}
return new_vec;
}
@ -835,7 +855,7 @@ vec<T, A, vl_embed>::splice (const vec<T, A, vl_embed> &src)
if (len)
{
gcc_checking_assert (space (len));
memcpy (address () + length (), src.address (), len * sizeof (T));
vec_copy_construct (end (), src.address (), len);
m_vecpfx.m_num += len;
}
}
@ -1089,13 +1109,12 @@ inline void
vec<T, A, vl_embed>::quick_grow_cleared (unsigned len)
{
unsigned oldlen = length ();
size_t sz = sizeof (T) * (len - oldlen);
size_t growby = len - oldlen;
quick_grow (len);
if (sz != 0)
memset (&(address ()[oldlen]), 0, sz);
if (growby != 0)
vec_default_construct (address () + oldlen, growby);
}
/* Garbage collection support for vec<T, A, vl_embed>. */
template<typename T>
@ -1454,7 +1473,7 @@ vec<T, va_heap, vl_ptr>::reserve (unsigned nelems, bool exact MEM_STAT_DECL)
va_heap::reserve (m_vec, nelems, exact PASS_MEM_STAT);
if (handle_auto_vec)
{
memcpy (m_vec->address (), oldvec->address (), sizeof (T) * oldsize);
vec_copy_construct (m_vec->address (), oldvec->address (), oldsize);
m_vec->m_vecpfx.m_num = oldsize;
}
@ -1616,10 +1635,10 @@ inline void
vec<T, va_heap, vl_ptr>::safe_grow_cleared (unsigned len MEM_STAT_DECL)
{
unsigned oldlen = length ();
size_t sz = sizeof (T) * (len - oldlen);
size_t growby = len - oldlen;
safe_grow (len PASS_MEM_STAT);
if (sz != 0)
memset (&(address ()[oldlen]), 0, sz);
if (growby != 0)
vec_default_construct (address () + oldlen, growby);
}

View File

@ -62,7 +62,8 @@ extern unsigned num_macro_tokens_counter;
line_maps::~line_maps ()
{
htab_delete (location_adhoc_data_map.htab);
if (location_adhoc_data_map.htab)
htab_delete (location_adhoc_data_map.htab);
}
/* Hash function for location_adhoc_data hashtable. */
@ -347,7 +348,7 @@ void
linemap_init (struct line_maps *set,
source_location builtin_location)
{
memset (set, 0, sizeof (struct line_maps));
*set = line_maps ();
set->highest_location = RESERVED_LOCATION_COUNT - 1;
set->highest_line = RESERVED_LOCATION_COUNT - 1;
set->location_adhoc_data_map.htab =

View File

@ -431,7 +431,7 @@ GTM::gtm_transaction_cp::save(gtm_thread* tx)
// Save everything that we might have to restore on restarts or aborts.
jb = tx->jb;
undolog_size = tx->undolog.size();
memcpy(&alloc_actions, &tx->alloc_actions, sizeof(alloc_actions));
alloc_actions = tx->alloc_actions;
user_actions_size = tx->user_actions.size();
id = tx->id;
prop = tx->prop;
@ -449,7 +449,7 @@ GTM::gtm_transaction_cp::commit(gtm_thread* tx)
// commits of nested transactions. Allocation actions must be committed
// before committing the snapshot.
tx->jb = jb;
memcpy(&tx->alloc_actions, &alloc_actions, sizeof(alloc_actions));
tx->alloc_actions = alloc_actions;
tx->id = id;
tx->prop = prop;
}
@ -485,7 +485,7 @@ GTM::gtm_thread::rollback (gtm_transaction_cp *cp, bool aborting)
prop = cp->prop;
if (cp->disp != abi_disp())
set_abi_disp(cp->disp);
memcpy(&alloc_actions, &cp->alloc_actions, sizeof(alloc_actions));
alloc_actions = cp->alloc_actions;
nesting = cp->nesting;
}
else

View File

@ -138,7 +138,11 @@ struct ml_mg : public method_group
// This store is only executed while holding the serial lock, so relaxed
// memory order is sufficient here. Same holds for the memset.
time.store(0, memory_order_relaxed);
memset(orecs, 0, sizeof(atomic<gtm_word>) * L2O_ORECS);
// The memset below isn't strictly kosher because it bypasses
// the non-trivial assignment operator defined by std::atomic. Using
// a local void* is enough to prevent GCC from warning for this.
void *p = orecs;
memset(p, 0, sizeof(atomic<gtm_word>) * L2O_ORECS);
}
};