[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Tinycc-devel] Bugs found in TCC
From: |
grischka |
Subject: |
Re: [Tinycc-devel] Bugs found in TCC |
Date: |
Mon, 25 Jan 2010 17:08:38 +0100 |
User-agent: |
Thunderbird 2.0.0.23 (Windows/20090812) |
Yann Bourrigault wrote:
> ... Here’s a list of the bugs followed by reproduction
> steps, in the form of source code to compile. Most of them were first
> tested against gcc and worked well with it.
Thanks for that.
Just on a note, there are two that might work correctly with current
master branch (http://repo.or.cz/w/tinycc.git)
That is:
> ->The padding is not generated correctly when initializing unions
> statically.
and:
> -> A memcpy or memset is sometimes introduced for functions returning
> a struct and causes compilation errors is string.h is included afterward.
Also, I'm confused by this one ("unsigned + signed" should be unsigned, no?)
Maybe someone else can comment:
> ->Problem with promotion on bitfields. Some integral promotion are wrong
> with bitfields.
>
> int main()
> {
> struct {
> unsigned int ufield : 7;
> int field : 7;
> int field2 : 7;
> } bit;
> int i1;
> short sh1;
> char ch1;
>
> bit.ufield = 10;
> i1 = -11;
> assert((bit.ufield + i1) < 0);
> sh1 = -11;
> assert((bit.ufield + sh1) < 0);
> bit.field = -11;
> assert((bit.ufield + bit.field) < 0);
> ch1 = -11;
> assert((bit.ufield + ch1) < 0);
> return 0;
> }
For those who like to play with it, I attached the test cases in a more
runnable form. (run "tcc -D T1..17 -run bugs.c")
--- grischka
#include <stdio.h>
#include <stdlib.h>
int my_assert(const char *msg, const char *file, int line)
{
fprintf(stderr, "%s:%d: error: assert (%s)\n", file, line, msg);
exit(-1);
return 0;
}
#define assert(_Expr) ((_Expr) || my_assert(#_Expr,__FILE__,__LINE__))
/*---------------------------------------------------------------------*/
/*
Hello,
My company is looking for a tiny compiler to embed in its product, in order
to build some generated source code. As TCC seems to fit our needs, I have
launched our compiler validation test base on it. I actually found several
bugs, which are not blocking for our purposes, but may interest you. Here'
s a list of the bugs followed by reproduction steps, in the form of source
code to compile. Most of them were first tested against gcc and worked well
with it.
*/
/*---------------------------------------------------------------------*/
#ifdef T1
/*
->Tcc refuses to compile bitfield assignment when a side effect occurs on a
double.
*/
struct
{
int field : 8;
int field2 : 8;
unsigned int ufield : 8;
unsigned int ufield2 : 8;
} bit;
double d1;
int main()
{
bit.field = ++d1;
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T2
/*
->In some cases, Tcc refuses to compile codes defining types with the same names
but in different scopes.
*/
int f(struct xyz { int xyz; } *xyz)
{
return xyz->xyz;
}
int main()
{
struct xyz { int xyz; } buf;
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T3
/*
->In some cases, Tcc refuses to compile codes defining variables with the same
names but in different scopes.
*/
float float_foo = 2.0;
void test()
{
static float foo = 5.0;
{
extern int foo;
foo = 15;
}
float_foo = foo;
}
int foo = 1;
int main()
{
assert(foo == 1);
assert(float_foo == 2.0);
test();
assert(foo == 15);
assert(float_foo == 5.0);
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T4
/*
->Tcc refuses to compile codes with a static initializer containing boolean
operation on doubles.
*/
static int t5 = 1 && 2.1;
int main() { return 0; }
#endif
/*---------------------------------------------------------------------*/
#ifdef T5
/*
->Tcc returns a strange compilation error "missing ;" when the code contains
extern having initializer.
*/
extern int i4 = 10;
int main() { return 0; }
#endif
/*---------------------------------------------------------------------*/
#ifdef T6
/*
->Tcc doesn't support correctly typedefs to incomplete types.
*/
typedef int table[];
table one = { 1 };
table two = { 1, 2 }; // error: index too large
int main() { return 0; }
#endif
/*---------------------------------------------------------------------*/
#ifdef T7
/*
->Tcc doesn't fetch float argument in old style definition as double, causing
wrong values to be passed.
*/
int bug(f, d)
float f;
int d;
{
return d == 42;
}
int main()
{
assert(bug(3.14, 42) == 1);
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T8
/*
->Some complex sizeof are not computed correctly by Tcc, returning wrong
results.
*/
int x = 0;
char a[100];
char b[50];
int main()
{
assert(sizeof(x == 0 ? a : b) == sizeof(char *));
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T9
/*
->Problem with implicit casts on bitfields. Assigning a bitfield to an unsigned
short or unsigned char without an explicit cast leads to a wrong value.
*/
struct bit
{
int dummy;
int f0 : 7;
int f1 : 13;
int f5 : 32 - 2;
int f3 : 32 - 1;
int f4 : 32 ;
};
int main()
{
struct bit bit;
unsigned short ush0, ush1, ush3, ush4;
unsigned char uch0, uch1, uch3, uch4;
unsigned int mask = 0xffffU;
bit.f0 = 63;
bit.f1 = 4095;
bit.f3 = 1023441823;
bit.f4 = 2113483647;
/* Those assignments give wrong results */
ush0 = bit.f0;
ush1 = bit.f1;
ush3 = bit.f3;
ush4 = bit.f4;
assert(ush0 == 63);
assert(ush1 == 4095);
assert(ush3 == (bit.f3 & mask));
assert(ush4 == (bit.f4 & mask));
mask = 0xffU;
/* Those assignments give wrong results */
uch0 = bit.f0;
uch1 = bit.f1;
uch3 = bit.f3;
uch4 = bit.f4;
assert(uch0 == 63);
assert(uch1 == (bit.f1 & mask));
assert(uch3 == (bit.f3 & mask));
assert(uch4 == (bit.f4 & mask));
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T10
/*
->Problem with promotion on bitfields. Some integral promotion are wrong with
bitfields.
*/
int main()
{
struct {
unsigned int ufield : 7;
int field : 7;
int field2 : 7;
} bit;
int i1;
short sh1;
char ch1;
bit.ufield = 10;
i1 = -11;
assert((bit.ufield + i1) < 0);
sh1 = -11;
assert((bit.ufield + sh1) < 0);
bit.field = -11;
assert((bit.ufield + bit.field) < 0);
ch1 = -11;
assert((bit.ufield + ch1) < 0);
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T11
/*
->When declaring local extern variables, the compiler should look for global
variables before looking for local ones.
*/
int v = 3;
int main()
{
int v = 4;
{
extern int v;
assert(v == 3);
}
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T12
/*
->When returning an element with an implicit cast to float, the value is wrong.
*/
float f_dbl(double dbl)
{
return dbl;
}
float f_ui(unsigned int ui)
{
return ui;
}
int main()
{
float f;
double d;
unsigned int ui;
d = -5.9;
f = d;
assert(f == f_dbl(d));
ui = 0;
//ui = ~ui;
f = ui;
assert(f == f_ui(ui));
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T13
/*
->The padding is not generated correctly when initializing unions statically.
*/
union
{
char c;
double d;
} u[2] = { 'a', 'b' };
int main()
{
u[0].d = 3.4;
assert(u[1].c == 'b');
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T14
/*
->Tcc refuses to compile code when an overflow occurs on static initialization.
A warning should only be issued.
*/
int x = 123456789012345678901234567;
int main() { return 0;}
#endif
/*---------------------------------------------------------------------*/
#ifdef T15
/*
-> A memcpy or memset is sometimes introduced for functions returning a struct
and causes compilation errors is string.h is included afterward.
*/
struct s {
int a;
};
struct s test()
{
struct s ms;
ms.a = 1;
return ms;
}
int main()
{
struct s ls;
ls = test();
assert(ls.a == 1);
return 0;
}
#include <string.h>
#endif
/*---------------------------------------------------------------------*/
#ifdef T16
/*
-> Incomplete types lead to an error if not defined, whereas they should be
assumed as having only one element.
*/
char test[];
int main()
{
test[0] = 0;
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T17
/*
-> Computations on very big values stored in long doubles gives wrong results.
*/
#include <float.h>
#define X 5.9486574767861588254287966331400356538172e4931L
int main()
{
long double test;
int exponent = 0;
test = X;
test *= 2.0L;
assert(test > LDBL_MAX);
return 0;
}
#endif
/*---------------------------------------------------------------------*/
#ifdef T18
int main()
{
struct
{
int a:3;
unsigned int b:3;
} s;
int i;
unsigned u = 10;
s.a = 3;
s.b = 3;
assert(s.a - 4 < 0);
assert(s.b - 4 < 0);
return 0;
}
#endif
/*---------------------------------------------------------------------*/
/*
Hope this helps!
Regards,
Yann Bourrigault.
*/