next up previous
Next: About this document ... Up: Using C-Breeze Previous: Discussion

Known Bugs

C-Breeze has a few known bugs, and probably at least as many unknown bugs. Many bugs have been removed from C-Breeze (and some added!) recently (as of the writing of this document, summer 1999). The bugs listed here remain because their causes are hard to find, or the cause is known but the solution is sufficiently difficult to implement that it has not yet been worth the effort. These are the known bugs:

1.
static as a storage class for a function definition is ignored by the parser. The static storage class in this context causes the function to explicitly have internal linkage (ISO9899 6.1.2.2) so this bug can cause some programs to have multiply defined symbols at link time. The workaround is to prototype the function in question with the static keyword; the storage class will stick in the context of a declaration. (Note: the same bug affects other storage classes such as auto and extern, but these are superfluous in the context of a function definition.)

2.
The dismantler sometimes emits variable declarations for pointers to anonymous structs or unions (e.g., from a typedef). C-Breeze automatically tags these structs and unions. The types of these pointers don't correspond (as far as C's typing rules know) to the original declarations, so an ``incompatible pointer assignment'' warning may result from trying to compile such dismantled code. The workaround is to ignore these messages.

3.
The dismantler moves all declarations to the beginning of the dismantled function. Variables are renamed to prevent monkey business such as the following

{ int a;
  ...
}
{ double a;
  ...
}

from being a problem, but for some reason global variables aren't handled properly sometimes. Thus, the dismantler will hide certain instances of global variables that result from questionable programming practices, e.g.:

int a;
void foo (void) {
        if (a == 1) {
                int a;
                a = 2; /* changing local a */
        }
        else
                a = 1; /* changing global a */
}

The dismantled code looks like this:

int a;

void foo(void)
{
  int __IES2;
  int __TE0;
  int a1;

  __TE0 = a == 1;
  __IES2 = __TE0;
  if (__IES2)
    goto __IES0;
  a = 1;
  goto __IES1;
  __IES0:
    ;
  a1 = 2;
  __IES1:
    ;
  return ;
}

The last assignment to a1, the renamed local a, should have been to global a. The workaround is not to code this way! Please! I spent a whole day tracking down this silliness in the GCC sources!

4.
Sometimes C-Breeze will choose to see the name of a globally declared function name when it should be seeing a local variable name. For instance, what's wrong with this code?

void foo (void) {
        char    s[100];
        int     index;
        for (index=0; index<100; index++)
                s[index] = 0;
}

It looks perfectly reasonable, but if you have #included "string.h", C-Breeze won't like it because index is the name of a standard C library function. Since any C program in which the programmer uses a reserved identifier (such as index, printf, anything beginning with str, etc.) as a variable name doesn't strictly conform to the ISO9899 standard, C-Breeze's behavior is excusable, if annoying, in cases like this. However, it is wrong when a local variable is mistaken for a user-declared function. The workaround is to rename the local variable.

5.
C-Breeze is not GCC. Although not exactly a bug, this can be annoying when trying to use glibc standard header files. In order to get certain functionality that many programs needs, C-Breeze can define the macro __GNUC__, that tells the header files that they are being read by GCC. Sometimes the header files think that this means it's OK to use GCC extensions not handled by C-Breeze, such as inline assembly language. C-Breeze can handle certain GCC extensions (as long as they are in header files, so that they'll be unparsed back to #include directives), but some others are not handles so easily. The workaround is to use or not use the -gcc flag on the C-Breeze command line. The presence or absence of this flag toggles certain preprocessor directives that try to accommodate weird GCCisms. If C-Breeze fails to compile a program, try using the -gcc flag and see if that helps. In particular, when using the stat(2) system call, the struct stat structure contains a field that is a scalar (a long long) when __GNUC__ is defined, but an array (of two ints) when it isn't defined. When this field is treated as a scalar by user code, you get problems.

6.
Local struct/union/enum tags can be seen globally, contrary to the standard. Quoting ISO9899 section 6.5.2.3, Tags:

A declaration of the form

struct-or-union identifier identifier ;

specifies a structure or union type and declares a tag, both visible only within the scope in which the declaration occurs.

The following test program illustrates the problem:

int a (void) {
        struct foo { int bar; };
}

int b (void) {
        struct foo baz;

        baz.bar = 1;
}

C-Breeze cheerfully accepts this, but struct foo is plainly an incomplete type in function b. It's been this author's experience that when tags are reused like this, the same structure is often also defined, so the bug is usually not much of a problem. One can imagine situations in which this could become troublesome. The workaround is to rename the offending tag when this bug is encountered.

7.
When there is a parse error from C-Breeze, a segmentation fault almost inevitably follows. To avoid this, debug your C code with your favorite ANSI/ISO compliant C compiler before submitting it to C-Breeze.


next up previous
Next: About this document ... Up: Using C-Breeze Previous: Discussion
Calvin Lin
2002-01-31