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.


->Tcc refuses to compile bitfield assignment when a side effect occurs on a 
double.

Reproduction steps:
struct {
int field : 8;
int field2 : 8;
unsigned int ufield : 8;
unsigned int ufield2 : 8;
} bit;

double d1;

void main() {
bit.field = ++d1;
}

->In some cases, Tcc refuses to compile codes defining types with the same 
names but in different scopes.
Reproduction steps:
int f(struct xyz { int xyz; } *xyz)
{
                return xyz->xyz;
}

void main() {
  struct xyz { int xyz; } buf;
}

->In some cases, Tcc refuses to compile codes defining variables with the same 
names but in different scopes.

Reproduction steps:
#include <assert.h>

float float_foo = 2.0;

void test() {
  static float foo = 5.0;

  {
    extern int foo;
    foo = 15;
  }
  float_foo = foo;
}

int foo = 1;

void main() {
  assert(foo == 1);
  assert(float_foo == 2.0);
  test();
  assert(foo == 15);
  assert(float_foo == 5.0);
}

->Tcc refuses to compile codes with a static initializer containing boolean 
operation on doubles.

Reproduction steps:
static int t5 = 1 && 2.1;

->Tcc returns a strange compilation error "missing ;" when the code contains 
extern having initializer.

Reproduction steps:
extern int i4 = 10;

->Tcc doesn't support correctly typedefs to incomplete types.

Reproduction steps:
typedef int table[];

table one = { 1 };
table two = { 1, 2 }; // error: index too large

->Tcc doesn't fetch float argument in old style definition as double, causing 
wrong values to be passed.

Reproduction steps:

int bug(f, d)
float f;
int d;
{
return d == 42;
}

void main()
{
assert(bug(3.14, 42) == 1);
}

->Some complex sizeof are not computed correctly by Tcc, returning wrong 
results.

Reproduction steps:
int x = 0;
char a[100];
char b[50];
void main()
{
assert(sizeof(x == 0 ? a : b) == sizeof(char *));
}

->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.
Reproduction steps:
#include <assert.h>
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;
}

->Problem with promotion on bitfields. Some integral promotion are wrong with 
bitfields.
Reproduction steps:
#include <assert.h>
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;
}

->When declaring local extern variables, the compiler should look for global 
variables before looking for local ones.

Reproduction steps:
int v = 3;

void main()
{
int v = 4;
{
extern int v;
assert(v == 3);
}
}

->When returning an element with an implicit cast to float, the value is wrong.

Reproduction steps:
float f_dbl(double dbl)
{
   return dbl;
}

float f_ui(unsigned int ui)
{
   return ui;
}

void 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));
}

->The padding is not generated correctly when initializing unions statically.

Reproduction steps:
union {
char c;
double d;
} u[2] = { 'a', 'b' };

void main()
{
   u[0].d = 3.4;
   assert(u[1].c == 'b');
}

->Tcc refuses to compile code when an overflow occurs on static initialization. 
A warning should only be issued.

Reproduction steps:
int x = 123456789012345678901234567;


-> A memcpy or memset is sometimes introduced for functions returning a struct 
and causes compilation errors is string.h is included afterward.

Reproduction steps:
#include <assert.h>

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>


-> Incomplete types lead to an error if not defined, whereas they should be 
assumed as having only one element.

Reproduction steps:
char test[];

int main() {
  test[0] = 0;
}


-> Computations on very big values stored in long doubles gives wrong results.

#include <float.h>
#include <assert.h>

#define X  5.9486574767861588254287966331400356538172e4931L

int main() {
  long double test;
  int exponent = 0;

  test = X;

  test *= 2.0L;

  assert(test > LDBL_MAX);

  return 0;
}


Hope this helps!

Regards,

Yann Bourrigault.
_______________________________________________
Tinycc-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to