Volatiles Are Miscompiled, andWhat to Do about It
Eric Eide and John Regehr
University of Utah
EMSOFT 2008 / October 22, 2008
int get_time() { // …}
void set_led() { // …}
int get_time() { // …}
void set_led() { // …}
Code Meets World
2
volatile int TIME; volatile int LED;volatile int TIME; volatile int LED;
int get_time() { return TIME;}
void set_led() { LED = 1;}
int get_time() { return TIME;}
void set_led() { LED = 1;}
70F170F1
00010001
Volatile Semantics
• compiled program must “do” what the source program says
• i.e., volatile side-effects must occur
3
volatile int WATCHDOG;
void reset_watchdog() { WATCHDOG = WATCHDOG;}
volatile int WATCHDOG;
void reset_watchdog() { WATCHDOG = WATCHDOG;}
reset_watchdog: movl WATCHDOG, %eax movl %eax, WATCHDOG ret
reset_watchdog: movl WATCHDOG, %eax movl %eax, WATCHDOG ret
reset_watchdog: retreset_watchdog: ret
GCC / IA32 GCC / MSP430
Our Contributions
• performed study of volatile bugs
• developed automated testing framework– “careful” random program generator– access summary testing
• found defects in all compilers we tested
• evaluated a workaround for volatile errors
• helped to make one compiler “10,000× better”4
Talk Outline
• examine error rates• evaluate workaround• investigate compiler defects• help make compiler better
5
random program gen.
.c.c.c.c.c.c.c.c.c.c.c.c
randprog compiler
access summary testing
exeexeexeexeexeexeexeexeexeexeexeexe
checker
Generating Good Test Cases
• our test cases are C programs• a good test case has a “right answer”
• an “answer” for us is an executable• we judge “rightness” by inspecting its output
– the computed result and the trail of side-effects
we must generate C programs that have predictable behaviors– independent of compiler, compiler options, …
6
Our Test Programs
• randprog creates programs that compute over integer variables
– signed/unsigned; 8/16/32 bits
– some globals declared volatile– functions take and return integer values– assignments, for-loops, arithmetic & logical
operators– no pointers, arrays, structs, or unions
7
.c.c.c.c.c.c.c.c.c.c.c.c
randprog
Test Program I/O
• no input (“closed”)
• two outputs– a checksum over global variables– a sequence of accesses to volatile variables
• now we must…– …ensure that every test has a “right answer”
• not just the checksum, but also the volatile invariant
– …figure out what that answer is8
Strictly Conforming
• avoid creating programs whose output depends on
– unspecified behavior — e.g., evaluation order– impl.-defined behavior — e.g., range of int– undefined behavior — e.g., division by zero
…according to the C standard
• enforce statically & dynamically9
Evaluation Order
• ensure that expression value is independent of evaluation order
• track read/write effect of expressions as they are built– may-read set– may-write set– volatile-access flag
• clear @ sequence point10
volatile int vol_1;int glo_2;
int func_3(void) { vol_1 = glo_2; return 7;}
void func_4() { int loc_5 = …; int loc_6 = func_3() + ???;}
volatile int vol_1;int glo_2;
int func_3(void) { vol_1 = glo_2; return 7;}
void func_4() { int loc_5 = …; int loc_6 = func_3() + ???;}
Dealing with Integers
• avoid most problematic behaviors, e.g.– integer range issues — avoid statically– signed shifts, div-by-zero — avoid dynamically
• but still there are issues…– signed integer overflow & underflow– arithmetic & logical operators in combination– integer promotions
• these do not matter in practice for us
• so, “nearly strictly conforming” programs11
Evaluating Test Cases
12
random program gen. access summary testing
.c.c.c.c.c.c.c.c.c.c.c.c
exeexeexeexeexeexeexeexeexeexeexeexe
randprog compiler checker
Access Summary Testing
• compile the test case
• run executable in instrumented environment
• map memory accesses to volatile variables
• create an access summary
• compare to the correct access summary
13
.c.c exeexe
compiler checker
✔/✖✔/✖
Access Summary Implementation
• two instrumented environments– volcheck — binary rewriting for IA32 (Valgrind)– Avrora — an AVR platform simulator– each outputs a log of memory accesses
• creating the summary– scan source & object code volatile variables– count total # of loads & stores to each volatile– effective: compact & sufficiently precise
14
Is It Right?
15
.c.c exeexe
compiler checker
✔/✖✔/✖
exeexe
exeexe
exeexe
✔?
identical checksum
& summaries
?
identical checksum
& summaries
?
yes ✔no ✖
✖
From Errors to Defects
• volatile error– volatile-access summary differs across the
executables
• functional error– output checksum differs across the executables
• a single test case can be both
16
Experimental Results
…and what to do about them
17
Methodology
• examined 13 production-quality C compilers– IA32 GCC (×5), LLVM-GCC, Intel, Sun– AVR GCC (×3)– Coldfire CodeWarrior– MSP430 GCC
• all: handwritten tests + manual inspection
• 9: random tests + access summary testing– 250,000 test programs
18
Access Summary Results
19
Work Around Volatile Errors
• idea: “protect” volatile accesses from overeager compilers via helper functions
20
int vol_read_int(volatile int *vp){ return *vp; }
volatile int *vol_id_int(volatile int *vp){ return vp; }
int vol_read_int(volatile int *vp){ return *vp; }
volatile int *vol_id_int(volatile int *vp){ return vp; }
x = vol_read_int(vol_1);*vol_id_int(&vol_1) = 0;x = vol_read_int(vol_1);*vol_id_int(&vol_1) = 0;
x = vol_1;vol_1 = 0;x = vol_1;vol_1 = 0;
opaqueopaque
Volatile Helper Results
21
Sample GCC Bug (#1)
22
const volatile int x;volatile int y;
void foo(void) { for (y=0; y>10; y++) { int z = x; }}
const volatile int x;volatile int y;
void foo(void) { for (y=0; y>10; y++) { int z = x; }}
foo: movl $0, y movl x, %eax jmp .L3.L2: movl y, %eax incl %eax movl %eax, y.L3: movl y, %eax cmpl $10, %eax jg .L3 ret
foo: movl $0, y movl x, %eax jmp .L3.L2: movl y, %eax incl %eax movl %eax, y.L3: movl y, %eax cmpl $10, %eax jg .L3 ret
GCC 4.3.0 / IA32 / -Os
Sample LLVM-GCC Bug
23
volatile int a;
void baz(void) { int i; for (i=0; i<3; i++) { a += 7; }}
volatile int a;
void baz(void) { int i; for (i=0; i<3; i++) { a += 7; }}
baz: movl a, %eax leal 7(%eax), %ecx movl %ecx, a leal 14(%eax), %ecx movl %ecx, a addl $21, %eax movl %eax, a ret
baz: movl a, %eax leal 7(%eax), %ecx movl %ecx, a leal 14(%eax), %ecx movl %ecx, a addl $21, %eax movl %eax, a ret
LLVM-GCC 2.2 / IA32 / -O2
Toward Zero Volatile Bugs
• we distilled random-program errors into bug reports against LLVM-GCC– Mar–Jul 2008: 5 volatile + 8 functional bugs fixed
• over our 250,000 test programs:
24
10,000× improvement
10,000× improvement
Summary• we developed an automated and effective framework
for discovering volatile-related defects in C compilers– “careful” random program generation– access summary testing– first published study of volatile bugs that we know of
• the miscompilation of volatiles is disturbingly common– serious consequences for critical & embedded software
• what to do about it?– a simple workaround can avoid 96% of volatile errors– report bugs to compiler writers– give advice to developers & compiler writers (in paper)
25
Thank you!
questions?
26
Top Related