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.