1AC_ARG_ENABLE([gcc-vcheck],
2[AS_HELP_STRING([--disable-gcc-vcheck], [do not check for buggy gcc version])],
3gcc_check=$enableval, gcc_check="yes")
4
5msg_gcc_check="use --disable-gcc-vcheck to disable this check. Before reporting any bugs check with a supported version of gcc"
6VERSION_SUFFIX=
7dnl Check for gcc-4.1.0
8if test "$gcc_check" = "yes"; then
9	if test "x$ac_compiler_gnu" = "xyes"; then
10		AC_MSG_CHECKING([for a supported version of gcc])
11		gcc_version=`${CC} -dumpversion`
12		case "${gcc_version}" in
13			4.1.0*)
14				AC_MSG_RESULT([no (${gcc_version})])
15				AC_MSG_ERROR([gcc 4.1.0 is known to incorrectly compile upx.c. Upgrade your compiler to at least 4.1.1/4.1.2)])
16				;;
17			*)
18				AC_MSG_RESULT([ok (${gcc_version})])
19				;;
20		esac
21		case "${gcc_version}" in
22		    [[56789]].* | 4.[[3456789]].*)
23			# bb #1581 - temporarily add -fno-strict-aliasing so gcc 4.4.0
24			# works correctly
25			CFLAGS="$CFLAGS -fno-strict-aliasing"
26			;;
27		    *)
28			;;
29		esac
30	fi
31else
32	CFLAGS="$CFLAGS -O0"
33	VERSION_SUFFIX="$VERSION_SUFFIX-broken-compiler"
34fi
35
36# add distcheck warning flags
37distcheck_enable_flags=0
38if test "x$ac_compiler_gnu" = "xyes"; then
39	gcc_version=`${CC} -dumpversion`
40	case "${gcc_version}" in
41		4.[[3456789]]*)
42			distcheck_enable_flags=1
43			;;
44		[[56789]].*)
45			distcheck_enable_flags=1
46			;;
47	esac
48fi
49
50dnl Checks if compiler produces valid code, regardless of compiler
51dnl we do these checks here to avoid receiving endless bugreports about
52dnl breakages due to compiler bugs.
53
54dnl Check if compiler produces invalid code on gcc PR27603 (affects upx.c)
55dnl testcase from gcc testsuite
56AC_MSG_CHECKING([for gcc bug PR27603])
57AC_TRY_RUN(
58	   [
59/* (C) Richard Guenther */
60void exit (int);
61void abort (void);
62int a;
63int main(void)
64{
65  int j;
66  for (j = 0; j < 6; j++)
67  {
68    if ((unsigned)j - 3 <= 1)
69      exit (0);
70    a = 1000 * (6 - j);
71  }
72  abort ();
73}
74], [AC_MSG_RESULT([ok, bug not present])],
75[AC_MSG_ERROR([your compiler has gcc PR27603 bug, use a different compiler, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27603])], [AC_MSG_RESULT([cross-compiling, assumed ok])])
76
77dnl Check if compiler produces invalid code on gcc PR26763-2 (affects upx.c)
78dnl testcase from gcc testsuite
79AC_MSG_CHECKING([for gcc bug PR26763-2])
80AC_TRY_RUN(
81	   [
82/* (C) Richard Guenther */
83extern void abort(void);
84
85static int try (char *a, int d)
86{
87  return a + d > a;
88}
89
90int main(void)
91{
92  char bla[100];
93
94  if (try (bla + 50, -1))
95    abort ();
96
97  return 0;
98}
99], [AC_MSG_RESULT([ok, bug not present])],
100[AC_MSG_ERROR([your compiler has gcc PR26763-2 bug, use a different compiler, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26763])],[AC_MSG_RESULT([cross-compiling, assumed ok])])
101
102dnl Check if compiler produces invalid code on own testcase based on upx.c
103AC_MSG_CHECKING([for valid code generation of CLI_ISCONTAINED])
104AC_TRY_RUN(
105	   [
106#include <stdio.h>
107static struct v{
108	char* dst;
109	unsigned int dsize;
110	unsigned int dcur;
111	unsigned int backsize;
112	signed int unp_offset;
113} values[] = {
114	{(char*)0xf78ab008, 0x2e000, 1, 4, -1594},
115	{(char*)0xb7af1008, 0x2e000, 1, 4, -1594}
116
117};
118extern void abort(void);
119
120#define CLI_ISCONTAINED(bb, bb_size, sb, sb_size)	\
121  ((bb_size) > 0 && (sb_size) > 0 && (size_t)(sb_size) <= (size_t)(bb_size) \
122   && (sb) >= (bb) && ((sb) + (sb_size)) <= ((bb) + (bb_size)) && ((sb) + (sb_size)) > (bb) && (sb) < ((bb) + (bb_size)))
123
124int crashtest()
125{
126	unsigned int backsize, dcur;
127	int dval=0x12000, unp_offset;
128	int* dsize = &dval;
129	char* dst = (char*)0x12000;
130	while(1) {
131		backsize=4;
132		dcur=0;
133		unp_offset=0x800002c7;
134
135		if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0)
136			return -1;
137		abort();
138	}
139	return 0;
140}
141
142int main(void)
143{
144	size_t i;
145	for(i=0;i<sizeof(values)/sizeof(values[0]);i++) {
146		struct v* v= &values[i];
147		char* dst = v->dst;
148		unsigned int* dsize = &v->dsize;
149		unsigned int dcur = v->dcur;
150		unsigned int backsize = v->backsize-1;
151		signed int  unp_offset = v->unp_offset;
152
153		if(!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) ||
154				!CLI_ISCONTAINED(dst, *dsize,dst+dcur,backsize) || unp_offset >= 0)  {
155			continue;
156		}
157		abort();
158	}
159	crashtest();
160	return 0;
161}
162], [AC_MSG_RESULT([ok, bug not present])],
163[AC_MSG_ERROR([your compiler has a bug that causes clamav bug no. 670, use a different compiler, see https://bugzilla.clamav.net/show_bug.cgi?id=670])], [AC_MSG_RESULT([cross-compiling, assumed ok])])
164
165dnl Check if compiler produces invalid code on gcc PR28045 (affects upx.c)
166dnl testcase from gcc testsuite
167AC_MSG_CHECKING([for gcc bug PR28045])
168AC_TRY_RUN(
169	   [
170/* (C) Andrew Pinski */
171extern void abort(void);
172struct a
173{
174   unsigned int bits : 1;
175   signed long val : ((sizeof(long) * 8) - 1);
176};
177static int Fnegate (struct a b)
178{
179  if ((-((long)b.val)) <= ((long) ((1UL << ((sizeof(long) * 8) - 2)) -1UL))
180      && (-((long)b.val)) >= (-(((long) ((1UL << ((sizeof(long) * 8) - 2)) -1UL))) - 1))
181     return 0 ;
182  abort ();
183}
184int main (void)
185{
186  struct a b = {1, 1};
187  Fnegate (b);
188  return 0;
189}
190], [AC_MSG_RESULT([ok, bug not present])],
191[AC_MSG_ERROR([your compiler has gcc PR28045 bug, use a different compiler, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=28045])], [AC_MSG_RESULT([cross-compiling, assumed ok])])
192
193dnl Check if compiler produces invalid code on gcc PR37573 (affects autoit.c)
194dnl this is a bug in gcc 4.4.0, but for some reason it affects gcc 4.1.2 too
195dnl gcc 4.1.3 is OK. This bug occurs only at -O3.
196AC_MSG_CHECKING([for gcc bug PR37573])
197AC_TRY_RUN(
198	   [
199#include <stdlib.h>
200#include <string.h>
201struct S
202{
203  unsigned int *a;
204  unsigned int b;
205  unsigned int c[624];
206};
207static unsigned char
208foo (struct S *s)
209{
210  unsigned int r;
211  if (!--s->b)
212    {
213      unsigned int *c = s->c;
214      unsigned int i;
215      s->a = c;
216      for (i = 0; i < 227; i++)
217	c[i] =
218	  ((((c[i] ^ c[i + 1]) & 0x7ffffffe) ^ c[i]) >> 1) ^
219	  ((0 - (c[i + 1] & 1)) & 0x9908b0df) ^ c[i + 397];
220      for (; i < 623; i++)
221	c[i] =
222	  ((((c[i] ^ c[i + 1]) & 0x7ffffffe) ^ c[i]) >> 1) ^
223	  ((0 - (c[i + 1] & 1)) & 0x9908b0df) ^ c[i - 227];
224      c[623] =
225	((((c[623] ^ c[0]) & 0x7ffffffe) ^ c[623]) >> 1) ^ ((0 - (c[0] & 1)) &
226							    0x9908b0df) ^ c[i
227									    -
228									    227];
229    }
230  r = *(s->a++);
231  r ^= (r >> 11);
232  r ^= ((r & 0xff3a58ad) << 7);
233  r ^= ((r & 0xffffdf8c) << 15);
234  r ^= (r >> 18);
235  return (unsigned char) (r >> 1);
236}
237
238void
239bar (unsigned char *p, unsigned int q, unsigned int r)
240{
241  struct S s;
242  unsigned int i;
243  unsigned int *c = s.c;
244  *c = r;
245  for (i = 1; i < 624; i++)
246    c[i] = i + 0x6c078965 * ((c[i - 1] >> 30) ^ c[i - 1]);
247  s.b = 1;
248  while (q--)
249    *p++ ^= foo (&s);
250};
251
252static unsigned char p[23] = {
253  0xc0, 0x49, 0x17, 0x32, 0x62, 0x1e, 0x2e, 0xd5, 0x4c, 0x19, 0x28, 0x49,
254    0x91, 0xe4, 0x72, 0x83, 0x91, 0x3d, 0x93, 0x83, 0xb3, 0x61, 0x38
255};
256
257static unsigned char q[23] = {
258  0x3e, 0x41, 0x55, 0x54, 0x4f, 0x49, 0x54, 0x20, 0x55, 0x4e, 0x49, 0x43,
259    0x4f, 0x44, 0x45, 0x20, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x3c
260};
261
262int
263main (void)
264{
265  unsigned int s;
266  s = 23;
267  bar (p, s, s + 0xa25e);
268  if (memcmp (p, q, s) != 0)
269	abort ();
270  return 0;
271}
272
273], [AC_MSG_RESULT([ok, bug not present])],
274[AC_MSG_ERROR([your compiler has gcc PR37573 bug, use a lower optimization level (-O1 or -O2), see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37573])], [AC_MSG_RESULT([cross-compiling, assumed ok])])
275
276# It's not fatal if gperf is missing
277AM_MISSING_PROG(GPERF, gperf)
278AC_SUBST(GPERF)
279
280AC_TYPE_OFF_T
281AC_COMPILE_CHECK_SIZEOF([short])
282AC_COMPILE_CHECK_SIZEOF([int])
283AC_COMPILE_CHECK_SIZEOF([long])
284AC_COMPILE_CHECK_SIZEOF([long long])
285AC_COMPILE_CHECK_SIZEOF([void *])
286