1  /* PR tree-optimization/83671 - fix for false positive reported by
       2     -Wstringop-overflow does not work with inlining
       3     { dg-do compile }
       4     { dg-options "-O1 -fdump-tree-optimized" } */
       5  
       6  #include "strlenopt.h"
       7  
       8  #define DIFF_MAX __PTRDIFF_MAX__
       9  
      10  #define CAT(x, y) x ## y
      11  #define CONCAT(x, y) CAT (x, y)
      12  #define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__)
      13  
      14  #define FAIL(name) do {				\
      15      extern void FAILNAME (name) (void);		\
      16      FAILNAME (name)();				\
      17    } while (0)
      18  
      19  /* Macros to emit a call to funcation named
      20       call_in_{true,false}_branch_not_eliminated_on_line_NNN()
      21     for each call that's expected to be eliminated.  The dg-final
      22     scan-tree-dump-time directive at the bottom of the test verifies
      23     that no such call appears in output.  */
      24  #define ELIM_TRUE(expr) \
      25    if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
      26  
      27  #define ELIM_FALSE(expr)					\
      28    if (!!(expr)) FAIL (in_false_branch_not_eliminated); else (void)0
      29  
      30  /* Macro to emit a call to a function named
      31       call_made_in_{true,false}_branch_on_line_NNN()
      32     for each call that's expected to be retained.  The dg-final
      33     scan-tree-dump-time directive at the bottom of the test verifies
      34     that the expected number of both kinds of calls appears in output
      35     (a pair for each line with the invocation of the KEEP() macro.  */
      36  #define KEEP(expr)				\
      37    if (expr)					\
      38      FAIL (made_in_true_branch);			\
      39    else						\
      40      FAIL (made_in_false_branch)
      41  
      42  typedef char A3[3], A5[5], A7[7], AX[];
      43  
      44  typedef A3 A7_3[7];
      45  typedef A3 AX_3[];
      46  typedef A5 A7_5[7];
      47  typedef A7 A5_7[5];
      48  
      49  extern A7_3 a7_3;
      50  extern A5_7 a5_7;
      51  extern AX_3 ax_3;
      52  
      53  extern A3 a3;
      54  extern A7 a5;
      55  extern A7 a7;
      56  extern AX ax;
      57  
      58  extern A3 *pa3;
      59  extern A5 *pa5;
      60  extern A7 *pa7;
      61  
      62  extern A7_3 *pa7_3;
      63  extern AX_3 *pax_3;
      64  extern A5_7 *pa5_7;
      65  extern A7_5 *pa7_5;
      66  
      67  extern char *ptr;
      68  
      69  struct MemArrays0 {
      70    A7_3 a7_3;
      71    A5_7 a5_7;
      72    char a3[3], a5[5], a0[0];
      73  };
      74  struct MemArraysX { char a3[3], a5[5], ax[]; };
      75  struct MemArrays7 { char a3[3], a5[5], a7[7]; };
      76  
      77  struct MemArrays0 ma0_3_5_7[3][5][7];
      78  
      79  void elim_strings (int i)
      80  {
      81    ELIM_TRUE (strlen (i < 0 ? "123" : "321") == 3);
      82    ELIM_FALSE (strlen (i < 0 ? "123" : "321") > 3);
      83    ELIM_FALSE (strlen (i < 0 ? "123" : "321") < 3);
      84  
      85    ELIM_TRUE (strlen (i < 0 ? "123" : "4321") >= 3);
      86    ELIM_FALSE (strlen (i < 0 ? "123" : "4321") > 4);
      87    ELIM_FALSE (strlen (i < 0 ? "123" : "4321") < 3);
      88  
      89    ELIM_TRUE (strlen (i < 0 ? "1234" : "321") >= 3);
      90    ELIM_FALSE (strlen (i < 0 ? "1234" : "321") < 3);
      91    ELIM_FALSE (strlen (i < 0 ? "1234" : "321") > 4);
      92  
      93    ELIM_TRUE (strlen (i < 0 ? "123" : "4321") <= 4);
      94    ELIM_TRUE (strlen (i < 0 ? "1234" : "321") <= 4);
      95  
      96    ELIM_TRUE (strlen (i < 0 ? "1" : "123456789") <= 9);
      97    ELIM_TRUE (strlen (i < 0 ? "1" : "123456789") >= 1);
      98  }
      99  
     100  /* Verify that strlen calls involving uninitialized global arrays
     101     of known size are eliminated when they appear in expressions
     102     that test for results that must be true.  */
     103  void elim_global_arrays (int i)
     104  {
     105    /* Verify that the expression involving the strlen call as well
     106       as whatever depends on it is eliminated  from the test output.
     107       All these expressions must be trivially true.  */
     108    ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3);
     109    ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3 - sizeof *a7_3);
     110    ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3 - 5 * sizeof *a7_3);
     111    ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3);
     112  
     113    ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7);
     114    ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7 - sizeof *a5_7);
     115    ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7 - 3 * sizeof *a5_7);
     116    ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7);
     117  
     118    /* Even when treating a multi-dimensional array as a single string
     119       the length must be less DIFF_MAX - (ax_3[i] - ax_3[0]) but GCC
     120       doesn't do that computation yet so avoid testing it.  */
     121    ELIM_TRUE (strlen (ax_3[0]) < DIFF_MAX);
     122    ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX);
     123    ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX);
     124    ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX);
     125  
     126    ELIM_TRUE (strlen (a3) < sizeof a3);
     127    ELIM_TRUE (strlen (a7) < sizeof a7);
     128  
     129    ELIM_TRUE (strlen (ax) != DIFF_MAX);
     130    /* ELIM_TRUE (strlen (ax) != DIFF_MAX - 1); */
     131    /* ELIM_TRUE (strlen (ax) < DIFF_MAX - 1); */
     132  }
     133  
     134  void elim_pointer_to_arrays (void)
     135  {
     136    /* Unfortunately, GCC cannot be trusted not to misuse a pointer
     137       to a smaller array to point to an object of a bigger type so
     138       the strlen range optimization must assume each array pointer
     139       points effectively to an array of an unknown bound.  */
     140    ELIM_TRUE (strlen (*pa7) < DIFF_MAX);
     141    ELIM_TRUE (strlen (*pa5) < DIFF_MAX);
     142    ELIM_TRUE (strlen (*pa3) < DIFF_MAX);
     143  
     144    ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX);
     145    ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX);
     146    ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX);
     147  
     148    ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX);
     149    ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX);
     150    ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX);
     151  
     152    ELIM_TRUE (strlen ((*pa5_7)[0]) < DIFF_MAX);
     153    ELIM_TRUE (strlen ((*pa5_7)[1]) < DIFF_MAX);
     154    ELIM_TRUE (strlen ((*pa5_7)[4]) < DIFF_MAX);
     155  }
     156  
     157  void elim_global_arrays_and_strings (int i)
     158  {
     159    ELIM_TRUE (strlen (i < 0 ? a3 : "") < 3);
     160    ELIM_TRUE (strlen (i < 0 ? a3 : "1") < 3);
     161    ELIM_TRUE (strlen (i < 0 ? a3 : "12") < 3);
     162    ELIM_TRUE (strlen (i < 0 ? a3 : "123") < 4);
     163  
     164    ELIM_FALSE (strlen (i < 0 ? a3 : "") > 3);
     165    ELIM_FALSE (strlen (i < 0 ? a3 : "1") > 3);
     166    ELIM_FALSE (strlen (i < 0 ? a3 : "12") > 3);
     167    ELIM_FALSE (strlen (i < 0 ? a3 : "123") > 4);
     168  
     169    ELIM_TRUE (strlen (i < 0 ? a7 : "") < 7);
     170    ELIM_TRUE (strlen (i < 0 ? a7 : "1") < 7);
     171    ELIM_TRUE (strlen (i < 0 ? a7 : "12") < 7);
     172    ELIM_TRUE (strlen (i < 0 ? a7 : "123") < 7);
     173    ELIM_TRUE (strlen (i < 0 ? a7 : "123456") < 7);
     174    ELIM_TRUE (strlen (i < 0 ? a7 : "1234567") < 8);
     175  
     176    ELIM_FALSE (strlen (i < 0 ? a7 : "") > 6);
     177    ELIM_FALSE (strlen (i < 0 ? a7 : "1") > 6);
     178    ELIM_FALSE (strlen (i < 0 ? a7 : "12") > 6);
     179    ELIM_FALSE (strlen (i < 0 ? a7 : "123") > 6);
     180    ELIM_FALSE (strlen (i < 0 ? a7 : "123456") > 7);
     181    ELIM_FALSE (strlen (i < 0 ? a7 : "1234567") > 8);
     182  }
     183  
     184  void elim_member_arrays_obj (int i)
     185  {
     186    ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < sizeof ma0_3_5_7);
     187    ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < sizeof ma0_3_5_7);
     188    ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < sizeof ma0_3_5_7);
     189    ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < sizeof ma0_3_5_7);
     190  
     191    ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < sizeof ma0_3_5_7);
     192    ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < sizeof ma0_3_5_7);
     193  
     194    ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < sizeof ma0_3_5_7);
     195    ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < sizeof ma0_3_5_7);
     196  
     197    ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < sizeof ma0_3_5_7);
     198    ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < sizeof ma0_3_5_7);
     199    ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < sizeof ma0_3_5_7);
     200    ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < sizeof ma0_3_5_7);
     201  
     202    ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < sizeof ma0_3_5_7);
     203    ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < sizeof ma0_3_5_7);
     204  
     205    ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < sizeof ma0_3_5_7);
     206    ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < sizeof ma0_3_5_7);
     207  
     208    ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < sizeof ma0_3_5_7);
     209    ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < sizeof ma0_3_5_7);
     210  
     211    ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < sizeof ma0_3_5_7);
     212    ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < sizeof ma0_3_5_7);
     213  }
     214  
     215  
     216  #line 1000
     217  
     218  /* Verify that strlen calls involving uninitialized global arrays
     219     of unknown size are not eliminated when they appear in expressions
     220     that test for results that need not be true.  */
     221  void keep_global_arrays (int i)
     222  {
     223    KEEP (strlen (a7_3[0]) < 2);
     224    KEEP (strlen (a7_3[1]) < 2);
     225    KEEP (strlen (a7_3[6]) < 2);
     226    KEEP (strlen (a7_3[i]) < 2);
     227  
     228    KEEP (strlen (a5_7[0]) < 6);
     229    KEEP (strlen (a5_7[1]) < 6);
     230    KEEP (strlen (a5_7[4]) < 6);
     231    KEEP (strlen (a5_7[i]) < 6);
     232  
     233    /* Verify also that tests (and strlen calls) are not eliminated
     234       for results greater than what would the size of the innermost
     235       array suggest might be possible (in case the element array is
     236       not nul-terminated), even though such calls are undefined.  */
     237    KEEP (strlen (a5_7[0]) > sizeof a5_7 - 2);
     238    KEEP (strlen (a5_7[1]) > sizeof a5_7 - sizeof a5_7[1] - 2);
     239    KEEP (strlen (a5_7[i]) > sizeof a5_7 - 2);
     240  
     241    KEEP (strlen (ax_3[0]) < 2);
     242    KEEP (strlen (ax_3[1]) < 2);
     243    KEEP (strlen (ax_3[2]) < 2);
     244    KEEP (strlen (ax_3[i]) < 2);
     245  
     246    /* Here again, verify that the ax_3 matrix is treated essentially
     247       as a flat array of unknown bound for the benefit of all the
     248       undefined code out there that might rely on it.  */
     249    KEEP (strlen (ax_3[0]) > 3);
     250    KEEP (strlen (ax_3[1]) > 9);
     251    KEEP (strlen (ax_3[2]) > 99);
     252    KEEP (strlen (ax_3[i]) > 999);
     253  
     254    KEEP (strlen (a3) < 2);
     255    KEEP (strlen (a7) < 6);
     256  
     257    KEEP (strlen (a3 + i) < 2);
     258    KEEP (strlen (a7 + i) < 2);
     259  
     260    /* The length of an array of unknown size may be as large as
     261       DIFF_MAX - 2.  */
     262    KEEP (strlen (ax) != DIFF_MAX - 2);
     263    KEEP (strlen (ax) < DIFF_MAX - 2);
     264    KEEP (strlen (ax) < 999);
     265    KEEP (strlen (ax) < 1);
     266  }
     267  
     268  void keep_pointer_to_arrays (int i)
     269  {
     270    KEEP (strlen (*pa7) < 6);
     271    KEEP (strlen (*pa5) < 4);
     272    KEEP (strlen (*pa3) < 2);
     273  
     274    /* Since GCC cannot be trusted not to misuse a pointer to a smaller
     275       array to point to an object of a larger type verify that the bound
     276       in a pointer to an array of a known bound isn't relied on for
     277       the strlen range optimization.  If GCC is fixed to avoid these
     278       misuses these tests can be removed.  */
     279    KEEP (strlen (*pa7) > sizeof *pa7);
     280    KEEP (strlen (*pa5) > sizeof *pa5);
     281    KEEP (strlen (*pa3) > sizeof *pa3);
     282  
     283    KEEP (strlen ((*pa7_3)[0]) < 2);
     284    KEEP (strlen ((*pa7_3)[1]) < 2);
     285    KEEP (strlen ((*pa7_3)[6]) < 2);
     286    KEEP (strlen ((*pa7_3)[i]) < 2);
     287  
     288    /* Same as above.  */
     289    KEEP (strlen ((*pa7_3)[0]) > sizeof *pa7_3);
     290    KEEP (strlen ((*pa7_3)[i]) > sizeof *pa7_3);
     291  
     292    KEEP (strlen ((*pax_3)[0]) < 2);
     293    KEEP (strlen ((*pax_3)[1]) < 2);
     294    KEEP (strlen ((*pax_3)[9]) < 2);
     295    KEEP (strlen ((*pax_3)[i]) < 2);
     296  
     297    /* Same as above.  */
     298    KEEP (strlen ((*pax_3)[0]) > 3);
     299    KEEP (strlen ((*pax_3)[i]) > 333);
     300  
     301    KEEP (strlen ((*pa5_7)[0]) < 6);
     302    KEEP (strlen ((*pa5_7)[1]) < 6);
     303    KEEP (strlen ((*pa5_7)[4]) < 6);
     304    KEEP (strlen ((*pa5_7)[i]) < 6);
     305  
     306    /* Same as above.  */
     307    KEEP (strlen ((*pa5_7)[0]) > sizeof *pa5_7);
     308    KEEP (strlen ((*pa5_7)[i]) > sizeof *pa5_7);
     309   }
     310  
     311  void keep_global_arrays_and_strings (int i)
     312  {
     313    KEEP (strlen (i < 0 ? a3 : "") < 2);
     314    KEEP (strlen (i < 0 ? a3 : "1") < 2);
     315    KEEP (strlen (i < 0 ? a3 : "12") < 2);
     316    KEEP (strlen (i < 0 ? a3 : "123") < 3);
     317  
     318    KEEP (strlen (i < 0 ? a7 : "") < 5);
     319    KEEP (strlen (i < 0 ? a7 : "1") < 5);
     320    KEEP (strlen (i < 0 ? a7 : "12") < 5);
     321    KEEP (strlen (i < 0 ? a7 : "123") < 5);
     322    KEEP (strlen (i < 0 ? a7 : "123456") < 6);
     323    KEEP (strlen (i < 0 ? a7 : "1234567") < 6);
     324  
     325    /* Verify that a matrix is treated as a flat array even in a conditional
     326       expression (i.e., don't assume that a7_3[0] is nul-terminated, even
     327       though calling strlen() on such an array is undefined).  */
     328    KEEP (strlen (i < 0 ? a7_3[0] : "") > 7);
     329    KEEP (strlen (i < 0 ? a7_3[i] : "") > 7);
     330  }
     331  
     332  void keep_member_arrays_obj (int i)
     333  {
     334    KEEP (strlen (ma0_3_5_7[0][0][0].a3) < 2);
     335    KEEP (strlen (ma0_3_5_7[0][0][1].a3) < 2);
     336    KEEP (strlen (ma0_3_5_7[0][0][2].a3) < 2);
     337    KEEP (strlen (ma0_3_5_7[0][0][6].a3) < 2);
     338  
     339    KEEP (strlen (ma0_3_5_7[1][0][0].a3) < 2);
     340    KEEP (strlen (ma0_3_5_7[2][0][1].a3) < 2);
     341  
     342    KEEP (strlen (ma0_3_5_7[1][1][0].a3) < 2);
     343    KEEP (strlen (ma0_3_5_7[2][4][6].a3) < 2);
     344  
     345    KEEP (strlen (ma0_3_5_7[0][0][0].a5) < 4);
     346    KEEP (strlen (ma0_3_5_7[0][0][1].a5) < 4);
     347    KEEP (strlen (ma0_3_5_7[0][0][2].a5) < 4);
     348    KEEP (strlen (ma0_3_5_7[0][0][6].a5) < 4);
     349  
     350    KEEP (strlen (ma0_3_5_7[1][0][0].a5) < 4);
     351    KEEP (strlen (ma0_3_5_7[2][0][1].a5) < 4);
     352  
     353    KEEP (strlen (ma0_3_5_7[1][1][0].a5) < 4);
     354    KEEP (strlen (ma0_3_5_7[2][4][6].a5) < 4);
     355  
     356    KEEP (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < 2);
     357    KEEP (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 2);
     358  
     359    KEEP (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 6);
     360    KEEP (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 6);
     361  
     362    /* Again, verify that the .a3 array isn't assumed to necessarily
     363       be nul-terminated.  */
     364    KEEP (strlen (ma0_3_5_7[0][0][0].a3) > 2);
     365    KEEP (strlen (ma0_3_5_7[0][0][6].a3) > 2);
     366    KEEP (strlen (ma0_3_5_7[0][0][i].a3) > 2);
     367  }
     368  
     369  void keep_member_arrays_ptr (struct MemArrays0 *ma0,
     370  			     struct MemArraysX *max,
     371  			     struct MemArrays7 *ma7,
     372  			     int i)
     373  {
     374    KEEP (strlen (ma0->a7_3[0]) > 0);
     375    KEEP (strlen (ma0->a7_3[0]) < 2);
     376    KEEP (strlen (ma0->a7_3[1]) < 2);
     377    KEEP (strlen (ma0->a7_3[6]) < 2);
     378    KEEP (strlen (ma0->a7_3[6]) < 2);
     379    KEEP (strlen (ma0->a7_3[i]) > 0);
     380    KEEP (strlen (ma0->a7_3[i]) < 2);
     381    KEEP (strlen (ma0->a7_3[i]) < 2);
     382  
     383    /* Again, verify that the member array isn't assumed to necessarily
     384       be nul-terminated.  */
     385    KEEP (strlen (ma0->a7_3[0]) > sizeof ma0->a7_3);
     386    KEEP (strlen (ma0->a7_3[i]) > sizeof ma0->a7_3);
     387  
     388    KEEP (strlen (ma0->a5_7[0]) < 5);
     389    KEEP (strlen (ma0[0].a5_7[0]) < 5);
     390    KEEP (strlen (ma0[1].a5_7[0]) < 5);
     391    KEEP (strlen (ma0[9].a5_7[0]) < 5);
     392    KEEP (strlen (ma0[9].a5_7[4]) < 5);
     393    KEEP (strlen (ma0[i].a5_7[4]) < 5);
     394    KEEP (strlen (ma0[i].a5_7[i]) < 5);
     395  
     396    /* Same as above.  */
     397    KEEP (strlen (ma0[i].a5_7[i]) > sizeof ma0[i].a5_7);
     398  
     399    KEEP (strlen (ma0->a0) < DIFF_MAX - 2);
     400    KEEP (strlen (ma0->a0) < 999);
     401    KEEP (strlen (ma0->a0) < 1);
     402  
     403    KEEP (strlen (max->ax) < DIFF_MAX - 2);
     404    KEEP (strlen (max->ax) < 999);
     405    KEEP (strlen (max->ax) < 1);
     406  
     407    KEEP (strlen (ma7->a7) < DIFF_MAX - 2);
     408    KEEP (strlen (ma7->a7) < 999);
     409    KEEP (strlen (ma7->a7) < 1);
     410  }
     411  
     412  void keep_pointers (const char *s)
     413  {
     414    KEEP (strlen (ptr) < DIFF_MAX - 2);
     415    KEEP (strlen (ptr) < 999);
     416    KEEP (strlen (ptr) < 1);
     417  
     418    KEEP (strlen (s) < DIFF_MAX - 2);
     419    KEEP (strlen (s) < 999);
     420    KEEP (strlen (s) < 1);
     421  }
     422  
     423  
     424  /* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
     425     { dg-final { scan-tree-dump-times "call_in_false_branch_not_eliminated_" 0 "optimized" } }
     426  
     427     { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } }
     428     { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } } */