summaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg/builtin-stringop-chk-2.c
blob: adccd0f444d553f08d8995c003928f4f02d2248a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* This file was miscompiled by an earlier version of the object size
   checking patch.  Object size in one of the memcpy calls was
   incorrectly determined to be 0 while it should be (size_t) -1
   (== unknown).  */
/* { dg-do compile } */
/* { dg-options "-O2" } */

#include "../gcc.c-torture/execute/builtins/chk.h"
   
void *bar (int);
extern void *malloc (__SIZE_TYPE__);

struct A
{
  int i, j, k;
};

/* Here all object sizes are not known at compile time.  There
   should be no warning, nor any checker functions called.  */

void
foo (const struct A *x, int y, const unsigned char *z)
{
  unsigned int b;
  unsigned char *c = 0;

  b = (x->i & 0xff) == 1 ? 3 : 4;
  if (y)
    c = bar (x->j * x->k);

  const unsigned char *d = z;
  unsigned char *e = c;
  unsigned char *f = c + x->j * x->k;
  int g = 0;

  while (e < f)
    {
      unsigned int h = *d++;

      if (h & 128)
	{
	  h = h - 128;
	  g = e + h * b > f;
	  if (g)
	    h = (f - e) / b;
	  if (b < 4)
	    do
	      {
		memcpy (e, d, 3);
		e += 3;
	      }
	    while (--h);
	  else
	    do
	      {
		memcpy (e, d, 4);
		e += 4;
	      }
	    while (--h);
	  d += b;
	}
      else
	{
	  h *= b;
	  g = e + h > f;
	  if (g)
	    h = f - e;
	  memcpy (e, d, h);
	  e += h;
	  d += h;
	}
    }
}

/* The same routine, slightly modified:
   1) c has known size at compile time
   2) e += h was changed into e += 16.
      GCC could actually through VRP determine that
      in e += h is (h >= 0 && h <= 127), thus know
      it is pointer addition and not subtraction and
      know e's __builtin_object_size (e, 0) is at 512,
      but we are not there yet.  */

unsigned char *
baz (const struct A *x, const unsigned char *z)
{
  unsigned int b;
  unsigned char *c = 0;

  b = (x->i & 0xff) == 1 ? 3 : 4;
  c = malloc (512);

  const unsigned char *d = z;
  unsigned char *e = c;
  unsigned char *f = c + x->j * x->k;
  int g = 0;

  while (e < f)
    {
      unsigned int h = *d++;

      if (h & 128)
	{
	  h = h - 128;
	  g = e + h * b > f;
	  if (g)
	    h = (f - e) / b;
	  if (b < 4)
	    do
	      {
		memcpy (e, d, 3);
		e += 3;
	      }
	    while (--h);
	  else
	    do
	      {
		memcpy (e, d, 513); /* { dg-warning "will always overflow" "memcpy" } */
		e += 4;
	      }
	    while (--h);
	  d += b;
	}
      else
	{
	  h *= b;
	  g = e + h > f;
	  if (g)
	    h = f - e;
	  memcpy (e, d, h);
	  /* e += h; */
	  e += 16;
	  d += h;
	}
    }
  return c;
}