PR tree-optimization/89688 - -Wstringop-overflow confused by const 2D array of char

gcc/c/ChangeLog:

	PR tree-optimization/89688
	* c-decl.c (finish_decl): Call braced_lists_to_string for more
	kinds of initializers.

gcc/c-family/ChangeLog:

	PR tree-optimization/89688
	* c-common.c (braced_list_to_string): Make static.
	(braced_lists_to_strings): Define new function.
	* c-common.h (braced_list_to_string): Remove.
	(braced_lists_to_strings): Declare.

gcc/cp/ChangeLog:

	PR tree-optimization/89688
	* typeck2.c (store_init_value): Call braced_lists_to_string for more
	kinds of initializers.

gcc/testsuite/ChangeLog:

	PR tree-optimization/89688
	* gcc.dg/strlenopt-61.c: New test.
	* g++.dg/warn/Wstringop-overflow-2.C: New test.

From-SVN: r269814
This commit is contained in:
Martin Sebor 2019-03-19 22:43:10 +00:00 committed by Martin Sebor
parent 026216a753
commit bec1da64ae
10 changed files with 331 additions and 11 deletions

View File

@ -1,3 +1,11 @@
2019-03-19 Martin Sebor <msebor@redhat.com>
PR tree-optimization/89688
* c-common.c (braced_list_to_string): Make static.
(braced_lists_to_strings): Define new function.
* c-common.h (braced_list_to_string): Remove.
(braced_lists_to_strings): Declare.
2019-03-12 Martin Liska <mliska@suse.cz>
* c-opts.c (c_common_handle_option): Wrap option with %< and %>.

View File

@ -8814,7 +8814,7 @@ maybe_add_include_fixit (rich_location *richloc, const char *header,
TYPE into a STRING_CST for convenience and efficiency. Return
the converted string on success or the original ctor on failure. */
tree
static tree
braced_list_to_string (tree type, tree ctor)
{
if (!tree_fits_uhwi_p (TYPE_SIZE_UNIT (type)))
@ -8895,4 +8895,52 @@ braced_list_to_string (tree type, tree ctor)
return res;
}
/* Attempt to convert a CTOR containing braced array initializer lists
for array TYPE into one containing STRING_CSTs, for convenience and
efficiency. Recurse for arrays of arrays and member initializers.
Return the converted CTOR or STRING_CST on success or the original
CTOR otherwise. */
tree
braced_lists_to_strings (tree type, tree ctor)
{
if (TREE_CODE (ctor) != CONSTRUCTOR)
return ctor;
tree_code code = TREE_CODE (type);
tree ttp;
if (code == ARRAY_TYPE)
ttp = TREE_TYPE (type);
else if (code == RECORD_TYPE)
{
ttp = TREE_TYPE (ctor);
if (TREE_CODE (ttp) == ARRAY_TYPE)
{
type = ttp;
ttp = TREE_TYPE (ttp);
}
}
else
return ctor;
if (TYPE_STRING_FLAG (ttp))
return braced_list_to_string (type, ctor);
code = TREE_CODE (ttp);
if (code == ARRAY_TYPE || code == RECORD_TYPE)
{
/* Handle array of arrays or struct member initializers. */
tree val;
unsigned HOST_WIDE_INT idx;
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (ctor), idx, val)
{
val = braced_lists_to_strings (ttp, val);
CONSTRUCTOR_ELT (ctor, idx)->value = val;
}
}
return ctor;
}
#include "gt-c-family-c-common.h"

View File

@ -1372,7 +1372,8 @@ extern void maybe_add_include_fixit (rich_location *, const char *, bool);
extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
enum cpp_ttype token_type,
location_t prev_token_loc);
extern tree braced_list_to_string (tree, tree);
extern tree braced_lists_to_strings (tree, tree);
extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
#if CHECKING_P

View File

@ -1,3 +1,9 @@
2019-03-19 Martin Sebor <msebor@redhat.com>
PR tree-optimization/89688
* c-decl.c (finish_decl): Call braced_lists_to_string for more
kinds of initializers.
2019-03-19 Jakub Jelinek <jakub@redhat.com>
PR c/89734

View File

@ -5165,11 +5165,10 @@ finish_decl (tree decl, location_t init_loc, tree init,
relayout_decl (decl);
}
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_STRING_FLAG (TREE_TYPE (type))
&& DECL_INITIAL (decl)
&& TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR)
DECL_INITIAL (decl) = braced_list_to_string (type, DECL_INITIAL (decl));
/* Look for braced array initializers for character arrays and
recursively convert them into STRING_CSTs. */
if (tree init = DECL_INITIAL (decl))
DECL_INITIAL (decl) = braced_lists_to_strings (type, init);
if (VAR_P (decl))
{

View File

@ -1,3 +1,9 @@
2019-03-19 Martin Sebor <msebor@redhat.com>
PR tree-optimization/89688
* typeck2.c (store_init_value): Call braced_lists_to_string for more
kinds of initializers.
2019-03-18 Jason Merrill <jason@redhat.com>
PR c++/89630 - ICE with dependent using-decl as template arg.

View File

@ -824,10 +824,9 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
value = digest_init_flags (type, init, flags, tf_warning_or_error);
}
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_STRING_FLAG (TREE_TYPE (type))
&& TREE_CODE (value) == CONSTRUCTOR)
value = braced_list_to_string (type, value);
/* Look for braced array initializers for character arrays and
recursively convert them into STRING_CSTs. */
value = braced_lists_to_strings (type, value);
current_ref_temp_count = 0;
value = extend_ref_init_temps (decl, value, cleanups);

View File

@ -1,3 +1,9 @@
2019-03-19 Martin Sebor <msebor@redhat.com>
PR tree-optimization/89688
* gcc.dg/strlenopt-61.c: New test.
* g++.dg/warn/Wstringop-overflow-2.C: New test.
2019-03-19 Jim Wilson <jimw@sifive.com>
PR target/89411

View File

@ -0,0 +1,29 @@
/* PR tree-optimization/89688 - -Wstringop-overflow confused by const 2D
array of char
{ dg-do compile }
{ dg-options "-Wall -fdump-tree-gimple -fdump-tree-optimized" } */
extern "C" __SIZE_TYPE__ strlen (const char*);
const char a2[2] = { '1' };
void a2_len ()
{
if (strlen (a2) != 1)
__builtin_abort ();
}
const char a2_2[2][3] = { { '1' }, { '1', '2' } };
void a2_2_len ()
{
if (strlen (a2_2[0]) != 1) // { dg-bogus "-Wstringop-overflow" }
__builtin_abort ();
if (strlen (a2_2[1]) != 2) // { dg-bogus "-Wstringop-overflow" }
__builtin_abort ();
}
/* { dg-final { scan-tree-dump-not "abort" "optimized" } }
{ dg-final { scan-tree-dump-not "strlen" "gimple" } } */

View File

@ -0,0 +1,218 @@
/* PR tree-optimization/89688 - -Wstringop-overflow confused by const
2D array of char
{ dg-do compile }
{ dg-options "-Wall -fdump-tree-gimple -fdump-tree-optimized" } */
typedef __SIZE_TYPE__ size_t;
size_t strlen (const char*);
#define CAT(x, y) x ## y
#define CONCAT(x, y) CAT (x, y)
#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
#define FAIL(name) do { \
extern __attribute__ ((noreturn)) void FAILNAME (name) (void); \
FAILNAME (name)(); \
} while (0)
#define A(ref, len) \
if (strlen (ref) != len) FAIL (failure); else (void)0
const char a3_4[3][4] = { { 1 }, { 1, 2 }, { 1, 2, 3 } };
void test_a4_4 (void)
{
A (a3_4[0], 1);
A (a3_4[1], 2);
A (a3_4[2], 3);
A (&a3_4[0][0], 1);
A (&a3_4[0][1], 0);
A (&a3_4[0][2], 0);
A (&a3_4[0][3], 0);
A (&a3_4[1][0], 2);
A (&a3_4[1][1], 1);
A (&a3_4[1][2], 0);
A (&a3_4[1][3], 0);
A (&a3_4[2][0], 3);
A (&a3_4[2][1], 2);
A (&a3_4[2][2], 1);
A (&a3_4[2][3], 0);
}
const char a3_4_5[3][4][5] =
{
{ { 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 } },
{ { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 } },
{ { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 } },
};
void test_a3_4_5 (void)
{
A (a3_4_5[0][0], 1);
A (a3_4_5[0][1], 2);
A (a3_4_5[0][2], 3);
A (a3_4_5[0][3], 4);
A (a3_4_5[1][0], 2);
A (a3_4_5[1][1], 3);
A (a3_4_5[1][2], 4);
A (a3_4_5[1][3], 1);
A (a3_4_5[2][0], 3);
A (a3_4_5[2][1], 4);
A (a3_4_5[2][2], 1);
A (a3_4_5[2][3], 2);
}
struct S
{
char a3[3];
char a4_5[4][5];
};
const struct S sa4[4] =
{
{ .a3 = { 0 },
.a4_5 =
{
{ 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }
}
},
{ .a3 = { 1 },
.a4_5 =
{
{ 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }
}
},
{ .a3 = { 1, 2 },
.a4_5 =
{
{ 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 }
}
},
{ .a3 = { 1 },
.a4_5 =
{
{ 1, 2, 3, 4 }, "1", { 1, 2 }, "123"
}
}
};
void test_sa4 (void)
{
A (sa4[0].a3, 0);
A (sa4[0].a4_5[0], 1);
A (sa4[0].a4_5[1], 2);
A (sa4[0].a4_5[2], 3);
A (sa4[0].a4_5[3], 4);
A (sa4[1].a3, 1);
A (sa4[1].a4_5[0], 2);
A (sa4[1].a4_5[1], 3);
A (sa4[1].a4_5[2], 4);
A (sa4[1].a4_5[3], 1);
A (sa4[2].a3, 2);
A (sa4[2].a4_5[0], 3);
A (sa4[2].a4_5[1], 4);
A (sa4[2].a4_5[2], 1);
A (sa4[2].a4_5[3], 2);
A (sa4[3].a3, 1);
A (sa4[3].a4_5[0], 4);
A (sa4[3].a4_5[1], 1);
A (sa4[3].a4_5[2], 2);
A (sa4[3].a4_5[3], 3);
}
struct T
{
struct S sa2[2];
char a4[4];
};
const struct T ta2[2] =
{
[0] =
{
.sa2 =
{
[0] =
{ .a3 = { 0 },
.a4_5 =
{
{ 1 }, { 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }
}
},
[1] =
{ .a3 = { 1 },
.a4_5 =
{
{ 1, 2 }, { 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }
}
},
},
.a4 = "12"
},
[1] =
{
.sa2 =
{
[0] =
{ .a3 = { 1, 2 },
.a4_5 =
{
{ 1, 2, 3 }, { 1, 2, 3, 4 }, { 1 }, { 1, 2 }
}
},
{ .a3 = { 1 },
.a4_5 =
{
{ 1, 2, 3, 4 }, "1", { 1, 2 }, "123"
}
}
},
.a4 = "123"
}
};
void test_ta2 (void)
{
A (ta2[0].sa2[0].a3, 0);
A (ta2[0].sa2[0].a4_5[0], 1);
A (ta2[0].sa2[0].a4_5[1], 2);
A (ta2[0].sa2[0].a4_5[2], 3);
A (ta2[0].sa2[0].a4_5[3], 4);
A (ta2[0].sa2[1].a3, 1);
A (ta2[0].sa2[1].a4_5[0], 2);
A (ta2[0].sa2[1].a4_5[1], 3);
A (ta2[0].sa2[1].a4_5[2], 4);
A (ta2[0].sa2[1].a4_5[3], 1);
A (ta2[0].a4, 2);
A (ta2[1].sa2[0].a3, 2);
A (ta2[1].sa2[0].a4_5[0], 3);
A (ta2[1].sa2[0].a4_5[1], 4);
A (ta2[1].sa2[0].a4_5[2], 1);
A (ta2[1].sa2[0].a4_5[3], 2);
A (ta2[1].sa2[1].a3, 1);
A (ta2[1].sa2[1].a4_5[0], 4);
A (ta2[1].sa2[1].a4_5[1], 1);
A (ta2[1].sa2[1].a4_5[2], 2);
A (ta2[1].sa2[1].a4_5[3], 3);
A (ta2[1].a4, 3);
}
/* { dg-final { scan-tree-dump-not "failure" "optimized" } }
{ dg-final { scan-tree-dump-not "strlen" "gimple" } } */