It’s not clear how many people enjoy looking at programs that make compilers crash — but this post is for them (and me). Our paper on producing reduced test cases for compiler bugs contained a large table of results for crash bugs. Below are all of C-Reduce’s reduced programs for those bugs.
Can we conclude anything just by looking at these? It’s hard to say… many of these C fragments are not obviously hard to compile — to see the problem we would need to know the details of the translation to a particular compiler’s intermediate representation.
In general, we don’t know of any way to make these programs much smaller. In other words, C-Reduce already implements most of the tricks we can think of. It will always be the case that an experienced compiler developer who understand a particular bug will be able to produce considerably better reduced test cases than C-Reduce can. Our goal, rather, is to create tests that a naive user cannot improve very much. So if you see interesting opportunities to improve these test cases, we’d love to hear about it. The current version of C-Reduce fails to implement optimizations such as constant folding, constant propagation, and loop peeling. We haven’t seen much need for these, though.
These are the verbatim tool output; there are definitely some formatting warts.
C1 : Crashes Clang 2.6 at -O0:
#pragma pack(1) struct S1 { int f0; char f2 }; struct { struct S1 f0 } a[] = { 0 } ;
C2 : Crashes Clang 2.6 at -O2:
struct S0 { int f0:1; int f4 } a; void fn1 () { struct S0 b[][1][1] = { 0 }; b[0][0][0] = a; }
C3 : Crashes Clang 2.6 at -O2:
unsigned short a; int b; char c; short fn1 () { return 1 / a; } void fn2 () { b = fn1 (); char d = b; c = d % 3; }
C4 : Crashes Clang 2.6 at -O3:
int a, b, c, d, e; #pragma pack(1) struct S0 { int f0:14; int f1:13; int f2:28; int f3:23; int f4:12 }; void fn1 (struct S0); void fn2 () { int f; lbl_2311: ; struct S0 g = { 0, 0, 1 }; fn1 (g); b && e; for (; c;) { if (d) goto lbl_2311; f = a && 1 ? 0 : 1; g.f4 = f; } }
C5 : Crashes Clang 2.6 at -O2:
int crc32_context, g_2 = 0, g_5; int g_8; int *g_39, *g_371; int g_81; int func_1_l_15 ; static short safe_add_func_int16_t_s_s ( short si1, int si2 ) { return si1 > 67 ? si1 : si1 + si2; } static int func_1 ( ) { int l_462 = 0; g_2 = 0; for ( ; g_2 < 12; g_2 = safe_add_func_int16_t_s_s ( g_2, 5 ) ) { g_5 = 1; for ( ; g_5; ++g_5 ) { g_8 = 1; for ( ; g_8 >= 0; g_8 = g_8 - 1 ) { func_1_l_15 = 1; for ( ; func_1_l_15; func_1_l_15 = func_1_l_15 - 1 ) if ( g_8 ) break; } g_371 = &l_462; int *l_128 = &g_81; *l_128 = *g_39; } *g_371 = 0 != 0 ; } return 0; } int main ( ) { func_1 ( ); crc32_context = g_2; crc32_context += g_5; }
C6 : Crashes Clang 2.6 at -O0:
#pragma pack(1) struct S2 { int f1; short f4 }; struct S3 { struct S2 f1; int f3:14 }; struct { struct S3 f3 } a = { 0, 0, 0 };
C7 : Crashes Clang 2.6 at -O1:
int *a; static int **b; int c, d, e; void fn1 () { d = &b == c; for (;;) { int **f = &a; if (e) { } else b = f; if (**b) continue; **f; } }
C8 : Crashes Clang 2.6 at -O1:
#pragma pack(1) struct S0 { int f3; char f4 }; struct { struct S0 f6; int f8 } a = { 0, 0, 0 };
C9 : Crashes Clang 2.6 at -O2:
struct S0 { int f0; int f1; short f3; int f7; int f8 } b; int a, c, d, e, f; void fn1 (struct S0 p1) { d++; c = p1.f8; e = 0; a = p1.f7; } void fn2 () { e = 0; for (; e; e++) { if (d) for (;;) { } --f; } fn1 (b); }
C10 : Crashes Clang 2.6 at -O1:
union U2 { int f0; unsigned short f2 } b; static int a = 1; void fn1 (int p1, unsigned short p2) { } int fn2 (union U2); union U2 fn3 (); static unsigned long long fn5 () { fn1 (b.f2, b.f0); return 0; } static char fn4 () { fn5 (); return 0; } int main () { a || fn2 (fn3 (fn4 () ) ); }
C11 : Crashes Clang 2.7 at -O1:
int *a; static int **b; int c, d, e; void fn1 () { d = &b == c; for (;;) { int **f = &a; if (e) { } else b = f; if (**b) continue; **f; } }
C12 : Crashes Clang 2.7 at -O0:
char a; unsigned char b; int c; void fn1 () { (b ^= c) != a; }
C13 : Crashes Clang 2.7 at -O2:
int a, b; void fn1 (); void fn2 (short p1) { short c; c = (65532 | 3) + p1; fn1 (c && 1); b = (0 == p1) * a; }
C14 : Crashes GCC 3.2.0 at -O1:
void fn1 () { struct S0 *a; struct S0 *b, *c = &a; struct S0 **d = &c; if (&b == &a) { } }
C15 : Crashes GCC 3.2.0 at -O3:
volatile int a, b, c, i; char d; void fn1 () { int e; { for (;; c++) { int f[50] = { }; if (b) { { 0; { { int g = a, h = d; e = h ? g : g / 0; } } a = e; } } } } } void main () { i = 0 / 0; a; }
C16 : Crashes GCC 3.2.0 at -O3:
int a, c; volatile int b; void fn1 () { b; for (;;) break; int d = b, e = a; c = a ? d : d % 0; } void fn2 () { if (0 % 0) b; }
C17 : Crashes GCC 3.2.0 at -O2:
union U1 { int f0; char f1 }; void fn1 (union U1 p1) { p1.f1 = 0; for (; p1.f1;) { } }
C18 : Crashes GCC 3.2.0 at -O1:
int a, b; void fn1 () { b = 4294967290UL <= a | b; }
C19 : Crashes GCC 3.2.0 at -O3:
int a, b, c; int fn1 (int p1, int p2) { return p1 - p2; } void fn2 () { int d; int **e; int ***f = &e; d = a && b ? a : a % 0; if (fn1 (f == 0, 2) ) c = ***f; }
C20 : Crashes GCC 3.3.0 at -O3:
int a, b, d; struct S0 { int f3 }; int *volatile c; void fn1 (struct S0); void fn2 () { int e; struct S0 **f; struct S0 ***g = &f; (a && b && b ? 0 : b) > (&c && 0); e = 0 == g; d = e >> 1; for (;;) fn1 (***g); }
C21 : Crashes GCC 3.4.0 at -O3:
int a, b; struct U0 { char f0; int f2 }; void fn1 () { struct U0 c; for (; c.f0 != 1; c.f0 = c.f0 + a) b -= 1; }
C22 : Crashes GCC 3.4.0 at -O3:
int a, b, d, e; struct S0 { int f3 }; int *c; void fn1 (struct S0); void fn2 () { struct S0 **f; struct S0 ***g = &f; (a && b && b ? 0 : b) > (&c == d); e = 1 < (0 == g); for (;;) fn1 (***g); }
C23 : Crashes GCC 4.0.0 at -O2:
int ***a; int b; int *c; void main () { if (&c == a) b = 0 == *a; }
C24 : Crashes GCC 4.0.0 at -O2:
int a[][0]; int *const b = &a[0][1]; int fn1 () { return *b; }
C25 : Crashes GCC 4.0.0 at -O0:
int a, b; unsigned char c; void fn1 () { (0 >= a & (0 || b) ) > c; }
C26 : Crashes GCC 4.0.0 at -O1:
struct { int f9:1 } a; const int b[] = { 0 }; void fn1 (); void main () { for (;;) { a.f9 = b[0]; fn1 (); } }
C27 : Crashes GCC 4.0.0 at -O0:
int a, c; unsigned char b; void fn1 () { b > (c > 0 & 0 < a); }
C28 : Crashes GCC 4.0.0 at -O2:
int **a[][0]; static int ***const b = &a[0][1]; void fn1 (); int fn2 () { return ***b; fn1 (); } void fn1 () { **b; }
C29 : Crashes GCC 4.1.0 at -O1:
volatile int ***a; int b; int **c; void fn1 () { if (&c == a) b = 0 == *a; }
C30 : Crashes GCC 4.1.0 at -O1:
struct { int f0; int f2 } a; int b; void fn1 () { a.f2 = 0; int *c[] = { 0, 0, 0, 0, &a.f0, 0, 0, 0, &a.f0 }; b = *c[4]; }
C31 : Crashes GCC 4.1.0 at -O2:
int a, b; unsigned c; void fn1 () { for (; c <= 0;) if (b < c) a = 1 && c; }
C32 : Crashes GCC 4.1.0 at -O1:
unsigned a; int b; void main () { unsigned c = 4294967295; int d = c; b = a <= d || a; }
C33 : Crashes GCC 4.1.0 at -O1:
const volatile long a; void main () { printf ("%d\n", (int) a); }
C34 : Crashes GCC 4.1.0 at -O3:
int a, b; union U1 { int f0; int f1 }; void fn1 () { union U1 c = { 1 }; int d = 1; if ( (c.f1 & a ? c.f1 : 1 - a) ^ d) { } else b = 0; }
C35 : Crashes GCC 4.2.0 at -O1:
volatile int ***a; int b; int **c; void fn1 () { if (&c == a) b = 0 == *a; }
C36 : Crashes GCC 4.2.0 at -O1:
struct S2 { volatile int f5:1; int f6 }; static struct S2 a; void main () { printf ("%d\n", a.f5); }
C37 : Crashes GCC 4.3.0 at -O1:
long long *a; int b; void fn1 () { long long **c = &a; int d = 7; lbl_2890: { long long **e = &a; b = (e == c) < d; d = 0; goto lbl_2890; } }
C38 : Crashes GCC 4.3.0 at -O2:
struct S2 { volatile int f5:1; int f6 }; static struct S2 a; void main () { printf ("%d\n", a.f5); }
C39 : Crashes GCC 4.3.0 at -O3:
int a; short b; void fn1 () { int c[0]; for (;;) { a = c[0]; b = 0; for (; b < 7; b += 1) c[b] = 0; } }
C40 : Crashes GCC 4.3.0 at -O1:
volatile int **a; int *b; void fn1 () { if (a == &b) **a; }
C41 : Crashes GCC 4.3.0 at -O3:
int a, b, c, d, e, f; void fn1 () { char g; lbl_120: if (b || e >= 0 & d >= 0 || a) return; g = f < 0 ? 1 : f; d = g == 0 || (char) f == 0 && g == 1 ? 0 : 0 % 0; if (c) goto lbl_120; }
C42 : Crashes Intel CC 12.0.5 at -O1:
struct U0 { int f0 } a; struct U0 fn1 () { return a; } void main () { 0 > a.f0; fn1 (); }
C43 : Crashes Open64 4.2.4 at -O3:
int a; int *b; unsigned c; void fn1 () { for (; a; a--) if (*b) { c = 0; for (; c >= 5; c++) { } } }
C44 : Crashes Open64 4.2.4 at -O3:
short a; void fn1 () { long b; b = 44067713550; a |= b; }
C45 : Crashes Open64 4.2.4 at -O3:
volatile int a; void fn1 () { int b = 1; a || b--; }
C46 : Crashes Open64 4.2.4 at -O2:
int a, b; void fn1 (); void fn2 (); void fn3 () { fn2 (); fn1 (); } void fn2 () { if (1) { } else for (;; b++) { int c = 0; int *d = &a; int **e = &d; *e = &c; *d = 0; *d |= 0; } }
C47 : Crashes Open64 4.2.4 at -O3:
struct S0 { int f1:1 }; int a, b; void fn1 () { for (; b;) { struct S0 c = { }; if (1) { c = c; a = c.f1; } } }
C48 : Crashes Open64 4.2.4 at -O3:
int a, b; int fn1 () { int *c = &b; a = 0; for (; a >= -26; --a) { unsigned d = 18446744073709551615; int *e = &b; *e &= d; } return *c; }
C49 : Crashes Open64 4.2.4 at -O3:
static int a, c, d; int b; int *e; void fn1 () { for (; a; a += 1) { b = 0; for (; b > -16; --b) for (; c;) { int *f = &d; *f = 0; } *e = 0; } }
C50 : Crashes Sun CC 5.11 at -xO4:
unsigned char a, d; struct { int f2 } b; int c, e; void fn1 (p1) { } void fn2 () { c = 0; for (; c <= 0;) e = b.f2; fn1 (0); b = b; d = -a; }
C51 : Crashes Sun CC 5.11 at -fast:
int a, c; int b[1]; void fn1 () { short d; for (; a; a -= 1) { d = b[c + 2] = b[c + 2]; b[0] = 0; } }
C52 : Crashes Sun CC 5.11 at -xO4:
int a, b, d; short c; int fn1 (p1) { return a ? 0 : p1; } void fn2 () { int e = 0; for (;;) { c = 0; d = fn1 (e ^ ~~c); d && b; } }
C53 : Crashes Sun CC 5.11 at -fast:
long a; int b, d; int *c; void fn1 () { int *e; for (;; b--) for (; d;) { *c = 0; *c &= (&e != 1) / a; } }
C54 : Crashes Sun CC 5.11 at -xO0:
#pragma pack(1) struct { int f3:1; int f4:16 } a = { 1, 0 };
C55 : Crashes Sun CC 5.11 at -xO3:
int a, c; static int b = 1; void fn1 (); void fn2 () { for (; a; a--) { c = 0; for (; c != 1;) { if (b) break; fn1 (); } } }
C56 : Crashes Sun CC 5.11 at -xO4:
#pragma pack(1) struct S0 { int f1; int f3:1 } a; void fn1 (struct S0 p1) { p1.f3 = 0; } void fn2 () { fn1 (a); }
C57 : Crashes Sun CC 5.11 at -fast:
int a, c, d, e, f, g, h, i, j, k; volatile int b; int fn1 () { for (; d; d = a) { int *l = &c; c = -3; for (; c > -23; --c) if (k) { if (*l) continue; return b; } for (; i; ++i) { j = 0; g = h; for (; f <= 1; f += 1) { } } } return e; }
23 responses to “57 Small Programs that Crash Compilers”
I noticed there are no MSVC examples in there — was it not a targeted compiler? If so, I’m curious as to why.
Hi Aaron, we didn’t test MSVC here. No good reason except that our lives are easier if Windows isn’t in the critical path for getting work done.
Microsoft will not fix them anyway, for most of the examples are not ‘real world’ enough. It is a waste of time.
In general a company wants to know that a significant number of customers (or one big one) are affected by a bug before putting resources into fixing it.
The exception is when a particular engineer at a company gets ahold of Csmith (or a similar tool), runs it internally, and uses peer pressure or other mechanisms to get people to fix bugs. I’ve heard that this has happened at a couple of places, but not at Microsoft as far as I know.
Do any of those have formatting dependencies? I.e. does running any of them through a formatting tool make the crashes go away?
This isn’t timely, but it is cute.
10 GOTO 30
20 RETURN
30 GOSUB 20
This crashed the BASIC interpreter of the Wang 3300 computer (circa 1972), as the RETURN would pop the “next token” address off of a stack and not check to see if it was valid (it was 1 past the end of line 30). It was then try to interpret garbage and get lost in the weeds.
Wang Labs later created the Wang 2200 computer, which was popular for its time and purpose. The interpreter was a complete rewrite, as the 3300 was a general purpose computer and the 2200 was a microcoded machine dedicated for running BASIC. The 2200 interpreter suffered the exact same error. I always wondered if the same people wrote the two interpreters, or if it is just an obvious pothole to fall into.
Minor suggestion: put a link to the paper post at the top of the page.
Hi bcs, C5 looks like the only one where running a code formatting tool didn’t work (C-Reduce runs both GNU indent and astyle at various places).
Looking at C5, you can also see that the function renaming pass failed. My guess is that it’s a buffer overrun bug — these tend to be the ones that are sensitive to things like string length and whitespace.
I’m not sure why indent/astyle fail to produce nicely formatted test cases sometimes. I’m guessing they fail to do a full parse/unparse and rather try to remember some of the original formatting, which is a bad idea in this case.
Thanks Chris, silly oversight, done.
Cool stuff. We’ve been doing some of this using ad-hoc Python scripts to generate and reduce cases to crash gccgo. Some bug reports produced so far:
http://code.google.com/p/go/issues/detail?id=1320
http://code.google.com/p/go/issues/detail?id=1329
http://code.google.com/p/go/issues/detail?id=1330
http://code.google.com/p/go/issues/detail?id=1331
http://code.google.com/p/go/issues/detail?id=1346
http://code.google.com/p/go/issues/detail?id=1347
http://code.google.com/p/go/issues/detail?id=1385
http://code.google.com/p/go/issues/detail?id=1437
http://code.google.com/p/go/issues/detail?id=1532
http://code.google.com/p/go/issues/detail?id=1557
http://code.google.com/p/go/issues/detail?id=1575
http://code.google.com/p/go/issues/detail?id=1841
http://code.google.com/p/go/issues/detail?id=1844
http://code.google.com/p/go/issues/detail?id=2661
http://code.google.com/p/go/issues/detail?id=3006
http://code.google.com/p/go/issues/detail?id=3186
We have also taken to running the compiler under Valgrind to catch errors that don’t crash it but are probably doing something wrong anyway.
Most recent work is here:
http://code.google.com/p/gofrontend/issues/detail?id=7
It might be cool to turn your techniques on Go in the future. 🙂
Crash I encountered a long time ago with MSVC 5.0 because of a lowercase/uppercase mistake:
int a;::a::b();
[…] pues aquà tienes 57 programas escritos en C y compilados con varias versiones de Clang, Open64, Sun CC y GCC para que intentes averiguar el […]
Would be nice such a thing for JAVA.
[…] 英文原文:John Regehr   编译:伯ä¹åœ¨çº¿ – 黄利民 […]
void main crashes a compiler? It shouldn’t even compile!
Hi vanklomp, you’d be surprised what will pass through a C compiler.
Since we’re just trying to crash compilers here, there’s no attempt to create valid test cases (the original Csmith programs were valid, but the reducer breaks this).
Of course we could have created reduced test cases that are valid C code, but they’d be larger. The assumption is that we want to absolute smallest test case that we can generate.
When I was in college in the 80s I asked one of my profs who was talking about proving correctness in a program, “What if the compiler has a bug?” With a completely straight face he said, “Compilers don’t have bugs.” I think he believed it, too.
CSX321: You are correct in your assumption. My Former Bitch Supervisor From Hell(tm) used to claim that program bugs were like roaches. If you found one, there were at least nine others. All programs had bugs, she stated.
We encountered a situation where the Microsoft C compiler had generated the wrong machine code. Since she couldn’t read assembler, she thought we were BSing her and that the problem was with us. We tried to remind her of her dictum at all programs had bugs and this was one of them. She countered with “It’s a compiler, not a program.”
She did not buy it when we tried to tell her that a compiler was a program.
In the end we just found a different way to code the routine to avoid the bug.
I’ve heard the same thing, that compilers don’t have bugs. I even tell students this sometimes so that they’ll find the bug in their own code (99.9% of the time) instead of blaming the compiler :).
Hey Brainiac, that was funny. I had a good laugh. Unfortunately, I had the same experience.
[…] å‰›å¥½çœ‹åˆ°ä¸€ç¯‡æ–‡ç« : 57 Small Programs that Crash Compilers(出處)。 […]
Can we conclude anything just by looking at these?
YES: that in C the semicolon is a TERMINATOR not a separator.
Humberto, the question of what (if anything) we can conclude from these is a good one.
I think the answer is that we can learn a few simple things, but not a lot beyond that. We can conclude that usually, not a lot of code is needed to trigger a crash. We can conclude that loops, structs, and math are almost always present in crash-bug triggers, but non-loop control flow is rarely needed.