Towards Beautiful Test Cases for Compiler Bugs John Regehr University of Utah.

Slides:



Advertisements
Similar presentations
Lecture Computer Science I - Martin Hardwick The Programming Process rUse an editor to create a program file (source file). l contains the text of.
Advertisements

A C++ Crash Course Part II UW Association for Computing Machinery Questions & Feedback.
CS 11 C track: lecture 7 Last week: structs, typedef, linked lists This week: hash tables more on the C preprocessor extern const.
The C ++ Language BY Shery khan. The C++ Language Bjarne Stroupstrup, the language’s creator C++ was designed to provide Simula’s facilities for program.
C++ Basics Variables, Identifiers, Assignments, Input/Output.
C Programming - Lecture 5
Optimization Compiler Baojian Hua
Dale/Weems/Headington
Random Testing of Interrupt-Driven Software John Regehr University of Utah.
Computer Science 1620 Programming & Problem Solving.
Finding Bugs with PC-lint A Static Analysis Tool for C/C++
CSE 332: C++ program structure and development environment C++ Program Structure (and tools) Today we’ll talk generally about C++ development (plus a few.
Programming Introduction to C++.
C++ Functions. 2 Agenda What is a function? What is a function? Types of C++ functions: Types of C++ functions: Standard functions Standard functions.
CSE 332: C++ Algorithms II From Last Time: Search with Generic Iterators Third generalization: separate iterator type parameter We arrive at the find algorithm.
CS 192 Lecture 3 Winter 2003 December 5, 2003 Dr. Shafay Shamail.
COMPUTER PROGRAMMING. Data Types “Hello world” program Does it do a useful work? Writing several lines of code. Compiling the program. Executing the program.
Introduction to C++ Programming Introduction to C++ l C is a programming language developed in the 1970's alongside the UNIX operating system. l C provides.
CS 11 C track: lecture 5 Last week: pointers This week: Pointer arithmetic Arrays and pointers Dynamic memory allocation The stack and the heap.
Department of Computer Science and Engineering, HKUST 1 HKUST Summer Programming Course 2008 Templates ~ their instantiation and specialization.
CSE 332: C++ Type Programming: Associated Types, Typedefs and Traits A General Look at Type Programming in C++ Associated types (the idea) –Let you associate.
Chapter 13 Recursion. Learning Objectives Recursive void Functions – Tracing recursive calls – Infinite recursion, overflows Recursive Functions that.
Introduction to C++ // Program description #include directives int main() { constant declarations variable declarations executable statements return.
Volatiles Are Miscompiled, and What to Do about It Eric Eide and John Regehr University of Utah EMSOFT 2008 / October 22, 2008.
CIS-165 C++ Programming I CIS-165 C++ Programming I Bergen Community College Prof. Faisal Aljamal.
Introduction to C++ Programming COMP102 Prog. Fundamentals I:Introduction to C++ / Slide 2 Introduction to C++ l C is a programming language developed.
Data Structures and Debugging Dr. Nancy Warter-Perez June 18, 2003.
C++ Memory Overview 4 major memory segments Key differences from Java
Automatic program generation for detecting vulnerabilities and errors in compilers and interpretersAutomatic program generation for detecting vulnerabilities.
Introduction to Programming
CSE 332: C++ template examples Concepts and Models Templates impose requirements on type parameters –Types that are plugged in must meet those requirements.
Variables and Data Types.  Variable: Portion of memory for storing a determined value.  Could be numerical, could be character or sequence of characters.
1 Chapter 2 C++ Syntax and Semantics, and the Program Development Process.
Provably Correct Peephole Optimizations with Alive.
1 Debugging and Syntax Errors in C++. 2 Debugging – a process of finding and fixing bugs (errors or mistakes) in a computer program.
Optimization of C Code The C for Speed
LECTURE LECTURE 11 Constructors and destructors Copy constructor Textbook: p , 183.
Lecture 01a: C++ review Topics: Setting up projects, main program Memory Diagrams Variables / Types (some of) the many-types-of-const's Input / Output.
CSE 332: C++ template examples Today: Using Class and Function Templates Two examples –Function template for printing different types –Class template for.
Week 7 Part I Kyle Dewey. Overview Code from last time Array initialization Pointers vs. arrays Structs typedef Bubble sort (if time)
Announcements Assignment 1 due Wednesday at 11:59PM Quiz 1 on Thursday 1.
C++ Basics Programming. COMP104 Lecture 5 / Slide 2 Introduction to C++ l C is a programming language developed in the 1970s with the UNIX operating system.
1 CSC 1111 Introduction to Computing using C++ C++ Basics (Part 1)
2. C FUNDAMENTALS. Example: Printing a Message /* Illustrates comments, strings, and the printf function */ #include int main(void) { printf("To C, or.
Chapter 2 Creating a C++ Program. Elements of a C++ Program Four basic ways of structuring a program Four basic ways of structuring a program 1.Sequencing.
Announcements Assignment 2 Out Today Quiz today - so I need to shut up at 4:25 1.
CSE 332: C++ templates and generic programming II Review: Concepts and Models Templates impose requirements on type parameters –Types that are plugged.
Finding and Understanding Bugs in C Compilers Xuejun Yang Yang Chen Eric Eide John Regehr University of Utah.
Test-Case Reduction for C Compiler Bugs
Motivation for Generic Programming in C++
C++ Lesson 1.
Programming with ANSI C ++
Data types Data types Basic types
Programming Introduction to C++.
Programs – Dynamic Linking and Loading
Volatiles Are Miscompiled, and What to Do about It
Reserved Words.
פרטים נוספים בסילבוס של הקורס
Object-Oriented Programming (OOP) Lecture No. 39
Govt. Polytechnic,Dhangar
Variables, Identifiers, Assignments, Input/Output
Prof. Bhushan Trivedi Director GLS Institute of Computer Technology
2. Second Step for Learning C++ Programming • Data Type • Char • Float
Programming Introduction to C++.
Statements and flow control
C. M. Overstreet Old Dominion University Spring 2006
C Programming - Lecture 5
CS31 Discussion 1D Winter19: week 4
C. M. Overstreet Old Dominion University Fall 2007
Data Structures & Programming
Presentation transcript:

Towards Beautiful Test Cases for Compiler Bugs John Regehr University of Utah

template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shift_right ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shr ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } } # 5 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" 1 # 14 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" namespace boost { namespace simd { namespace ext { } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { typedef typename dispatch::meta::as_integer ::type itype; return bitwise_cast (shift_right(bitwise_cast (a0),a1)); } }; } } } namespace boost { namespace simd { namespace ext{ } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { return a0 >> a1; } }; } } } # 6 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" 1 # 20 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" namespace boost { namespace simd { namespace ext { 2

template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shift_right ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shr ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } } # 5 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" 1 # 14 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" namespace boost { namespace simd { namespace ext { } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { typedef typename dispatch::meta::as_integer ::type itype; return bitwise_cast (shift_right(bitwise_cast (a0),a1)); } }; } } } namespace boost { namespace simd { namespace ext{ } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { return a0 >> a1; } }; } } } # 6 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" 1 # 20 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" namespace boost { namespace simd { namespace ext { 3 From GCC PR 50800: “Testcase is [here] (couldn't attach it due to bugzilla size restrictions)”

template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shift_right ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shr ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } } # 5 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" 1 # 14 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" namespace boost { namespace simd { namespace ext { } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { typedef typename dispatch::meta::as_integer ::type itype; return bitwise_cast (shift_right(bitwise_cast (a0),a1)); } }; } } } namespace boost { namespace simd { namespace ext{ } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { return a0 >> a1; } }; } } } # 6 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" 1 # 20 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" namespace boost { namespace simd { namespace ext { 4 From GCC PR 50800: “Testcase is [here] (couldn't attach it due to bugzilla size restrictions)” Next comment: “That you couldn't attach it should tell you something…”

template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shift_right ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } template __attribute__((always_inline)) typename boost::dispatch::meta::call ::type shr ( A0 const& a0, A1 const& a1 ) { typename boost::dispatch::make_functor ::type callee; return callee( a0, a1);; } } # 5 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" 1 # 14 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/scalar/shift_right.hpp" namespace boost { namespace simd { namespace ext { } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { typedef typename dispatch::meta::as_integer ::type itype; return bitwise_cast (shift_right(bitwise_cast (a0),a1)); } }; } } } namespace boost { namespace simd { namespace ext{ } } } namespace boost { namespace dispatch { namespace meta { template __attribute__((always_inline)) boost :: simd :: ext :: implement >, scalar_ >), tag::cpu_ > dispatching( boost::simd::tag::shift_right_, tag::cpu_, scalar_ > const, scalar_ > const, adl_helper = adl_helper() ) { boost :: simd :: ext :: implement >, scalar_ > ), tag::cpu_ > that; return that; } } } } namespace boost { namespace simd { namespace ext { template struct implement >, scalar_ > ), tag::cpu_, Dummy > { typedef A0 result_type; inline result_type operator()( A0 const& a0, A1 const& a1 ) const { return a0 >> a1; } }; } } } # 6 "/home/gaunard/build/may_alias/include/boost/simd/toolbox/operator/include/functions/shift_right.hpp" 2 # 1 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" 1 # 20 "/home/gaunard/dev/may_alias/modules/boost/simd/operator/include/boost/simd/toolbox/operator/functions/simd/common/shift_ri ght.hpp" namespace boost { namespace simd { namespace ext { 5 From GCC PR 50800: “Testcase is [here] (couldn't attach it due to bugzilla size restrictions)” Next comment: “That you couldn't attach it should tell you something…” Next comment: 203 KB reduced test case attached

(safe_47 (((g_1161 ^ 0x2893L), (((safe_9 ((!l_1747), ((l_1749 = func_37 (func_58 ((l_1748, UL), g_110, l_1168, p_7, l_1747), g_381, p_9)), g_894))) != l_1747) <= p_10)), p_8))), g_11) 4UL), 0x93L)) ^ g_1161))) <= l_1750), p_8), g_458); g_1122 = (l_1749 && func_37 (l_1750, (g_1161 = ((safe_17 (((safe_60 (l_1755, 4)) | (g_703, (safe_55 ((p_10, 3UL), p_7)))), ((safe_51 ((safe_42 (0UL, ((l_1747 != 0x3AL) < g_28))))) | 0xF862D3BEL))) != 0xC7L)), g_1487)); g_146 = 0xBC806FC8L; l_1788 = func_24 (((safe_13 ((~ (((g_458 != (safe_54 (((~ (l_1749 = (safe_43 ((safe_14 ((((safe_62 ((safe_4 ((safe_63 (((l_1750 = 1L), (safe_59 (l_1168, 1))), (((p_10 = func_46 (func_46 (l_1749, g_894, (safe_23 (l_1749, (l_1167 = g_1161))), ((l_1469 = 6

(safe_47 (((g_1161 ^ 0x2893L), (((safe_9 ((!l_1747), ((l_1749 = func_37 (func_58 ((l_1748, UL), g_110, l_1168, p_7, l_1747), g_381, p_9)), g_894))) != l_1747) <= p_10)), p_8))), g_11) 4UL), 0x93L)) ^ g_1161))) <= l_1750), p_8), g_458); g_1122 = (l_1749 && func_37 (l_1750, (g_1161 = ((safe_17 (((safe_60 (l_1755, 4)) | (g_703, (safe_55 ((p_10, 3UL), p_7)))), ((safe_51 ((safe_42 (0UL, ((l_1747 != 0x3AL) < g_28))))) | 0xF862D3BEL))) != 0xC7L)), g_1487)); g_146 = 0xBC806FC8L; l_1788 = func_24 (((safe_13 ((~ (((g_458 != (safe_54 (((~ (l_1749 = (safe_43 ((safe_14 ((((safe_62 ((safe_4 ((safe_63 (((l_1750 = 1L), (safe_59 (l_1168, 1))), (((p_10 = func_46 (func_46 (l_1749, g_894, (safe_23 (l_1749, (l_1167 = g_1161))), ((l_1469 = 7 Exposes an LLVM miscompilation bug Part of an 89 KB program randomly generated by Csmith

(safe_47 (((g_1161 ^ 0x2893L), (((safe_9 ((!l_1747), ((l_1749 = func_37 (func_58 ((l_1748, UL), g_110, l_1168, p_7, l_1747), g_381, p_9)), g_894))) != l_1747) <= p_10)), p_8))), g_11) 4UL), 0x93L)) ^ g_1161))) <= l_1750), p_8), g_458); g_1122 = (l_1749 && func_37 (l_1750, (g_1161 = ((safe_17 (((safe_60 (l_1755, 4)) | (g_703, (safe_55 ((p_10, 3UL), p_7)))), ((safe_51 ((safe_42 (0UL, ((l_1747 != 0x3AL) < g_28))))) | 0xF862D3BEL))) != 0xC7L)), g_1487)); g_146 = 0xBC806FC8L; l_1788 = func_24 (((safe_13 ((~ (((g_458 != (safe_54 (((~ (l_1749 = (safe_43 ((safe_14 ((((safe_62 ((safe_4 ((safe_63 (((l_1750 = 1L), (safe_59 (l_1168, 1))), (((p_10 = func_46 (func_46 (l_1749, g_894, (safe_23 (l_1749, (l_1167 = g_1161))), ((l_1469 = 8 Part of an 89 KB program randomly generated by Csmith Exposes an LLVM miscompilation bug Csmith is our C compiler fuzzer ~425 compiler bugs discovered and reported so far

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 9 $ clang -O1 foo.c ;./a.out 0 $ clang -O2 foo.c ;./a.out 1

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 10 $ clang -O1 foo.c ;./a.out 0 $ clang -O2 foo.c ;./a.out 1 Reported as LLVM PR on 3/5/2012, fixed same day

int printf (const char *, …); char f[] = { -9L }; int main (void) { printf ("%d\n", 255 | f[0]); } 11 Intel CC for x86-64 is wrong at “-Ofast -ipo”

int printf (const char *,...); const union { short f1; int f2 : 13; } a = { }; int main (void) { printf ("%d\n", a.f1); printf ("%d\n", a.f2); return 0; } 12 GCC from Ubuntu LTS for x86-64 is wrong at -O1

int printf (const char *,...); int b; static struct S0 { int f2 : 1; } c; int main (void) { b = -1 ^ c.f2; printf ("%d\n", b); } 13 GCC from mid-Feb 2012 for x86-64 is wrong at -O0 (PR 52209)

Beautiful test case == 1.Small (but not obfuscated) 2.Well-defined 3.Unambiguously elicits bad behavior 4.Makes the compiler bug obvious Not all bugs have beautiful test cases 14

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 15 Delta Debugging algorithm “ddmin” == Greedy search Delete chunks Test results for “interestingness” Keep reducing granularity

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 16 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity Is this still interesting?

#!/bin/bash clang -O1 test.c&&\./a.out > out1.txt&&\ clang -O2 test.c&&\./a.out > out2.txt&&\ ! diff out1.txt out2.txt 17

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 18 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity Assume not interesting, so we backtrack

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 19 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 20 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 21 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 22 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 23 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity

short a; int b, d, k, l, m; int fn1 (short p1, int p2) { return p1 - p2; } int fn2 (short p1) { return p1 == 0 || a == 0 ? a : a % p1; } int fn3 (int p1, unsigned short p2) { return p2 == 0 ? 0 : p1 % p2; } void fn4 (unsigned char p1) { if (p1) b = 1; } void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 24 ddmin == Greedy search Delete chunks Test for “interestingness” Keep reducing granularity

Problem: ddmin gets stuck – Output is often not beautiful Our premise: – The Delta Debugging concept is sound – But ddmin is too hard-coded, inflexible 25

Generalized Delta Debugging 1.One or more transformations – E.g. “remove chunks of text” 2.Interestingness test 3.Fitness function – E.g. “prefer smaller test cases” 4.Search algorithm – E.g. “greedy” 26

Generalized Delta Debugging 1.One or more transformations – E.g. “remove chunks of text” 2.Interestingness test 3.Fitness function – E.g. “prefer smaller test cases” 4.Search algorithm – E.g. “greedy” 27

C-Reduce: A Generalized Delta Debugger Fixpoint computation Parameterized by – Interestingness test – Plugins that perform transformations Plugins are iterators implementing: reset() advance() transform(file) 28

void fn5 (p1) { short n = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 29

void fn5 (p1) { short 0 = 60018; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 30

void fn5 (p1) { short n = 0; k = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 31

void fn5 (p1) { short n = 60018; 0 = fn2 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 32

void fn5 (p1) { short n = 60018; k = 0 (p1); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 33

void fn5 (p1) { short n = 60018; k = fn2 (0); d = k != 0; l = fn1 (d, n); m = fn3 (l, p1); fn4 (m); } int main () { fn5 (2); printf ("%d\n", b); return 0; } 34

Example transformations: Remove chunks of text (like ddmin) C-specific peephole transformations – 0xfeedbeefULL  1 – x ^= y  x = y – (x + 1)  x + 1 – while (…)  if (…) – x ? y : z  y C-Reduce has 49 plugins so far 35

Some transformations make coordinated changes across different parts of the program – Inline a function call – Scalar replacement of aggregates – Un-nest nested function calls – Remove dead arguments – Make function return void – Reduce array dimension or pointer level – Shorten identifier name These use Clang as a rewriter 36

37 transformation current test case interesting? yes no

Beautiful test case == 1.Small (but not obfuscated) 2.Well-defined 3.Unambiguously elicits bad behavior 4.Makes the compiler bug obvious 38

#include using namespace std; int r[3], x[3], y[3]; int main() { int xa=2,ya=5,xb=4,yb=2,n=3; x[0] = 3; x[1] = 5; x[2] = 1; y[0] = 1; y[1] = 3; y[2] = 3; r[0] = 2; r[1] = 1; r[2] = 2; int tcount = 0; for (int k=min(xa,xb); k<=max(xa,xb); k++) { bool found1,found2 = false; for (int j=0; j<n; j++) { if (((k-x[j])*(k-x[j])+(y[j]-ya)*(y[j]-ya))<=r[j]*r[j]) { found1 = true; } if (((k-x[j])*(k-x[j])+(y[j]-yb)*(y[j]-yb))<=r[j]*r[j]) { found2 = true; } if (found1 && found2) break; } if (!found1) tcount++; if (!found2) tcount++; } cout << tcount << endl; return 0; } 39 GCC PR 51962

#include using namespace std; int r[3], x[3], y[3]; int main() { int xa=2,ya=5,xb=4,yb=2,n=3; x[0] = 3; x[1] = 5; x[2] = 1; y[0] = 1; y[1] = 3; y[2] = 3; r[0] = 2; r[1] = 1; r[2] = 2; int tcount = 0; for (int k=min(xa,xb); k<=max(xa,xb); k++) { bool found1,found2 = false; for (int j=0; j<n; j++) { if (((k-x[j])*(k-x[j])+(y[j]-ya)*(y[j]-ya))<=r[j]*r[j]) { found1 = true; } if (((k-x[j])*(k-x[j])+(y[j]-yb)*(y[j]-yb))<=r[j]*r[j]) { found2 = true; } if (found1 && found2) break; } if (!found1) tcount++; if (!found2) tcount++; } cout << tcount << endl; return 0; } 40 GCC PR Bug report says: “Compile the following simple code without -O3, and run. Now compile it with -O3 option (for optimization), run again. Surprisingly 2 different outputs appear.”

#include using namespace std; int r[3], x[3], y[3]; int main() { int xa=2,ya=5,xb=4,yb=2,n=3; x[0] = 3; x[1] = 5; x[2] = 1; y[0] = 1; y[1] = 3; y[2] = 3; r[0] = 2; r[1] = 1; r[2] = 2; int tcount = 0; for (int k=min(xa,xb); k<=max(xa,xb); k++) { bool found1,found2 = false; for (int j=0; j<n; j++) { if (((k-x[j])*(k-x[j])+(y[j]-ya)*(y[j]-ya))<=r[j]*r[j]) { found1 = true; } if (((k-x[j])*(k-x[j])+(y[j]-yb)*(y[j]-yb))<=r[j]*r[j]) { found2 = true; } if (found1 && found2) break; } if (!found1) tcount++; if (!found2) tcount++; } cout << tcount << endl; return 0; } 41 GCC PR Bug report says: “Compile the following simple code without -O3, and run. Now compile it with -O3 option (for optimization), run again. Surprisingly 2 different outputs appear.” GCC developer responds: “You do not initialise found1.” PR is RESOLVED INVALID And this person may have a hard time getting someone to read his next bug report

#include using namespace std; int r[3], x[3], y[3]; int main() { int xa=2,ya=5,xb=4,yb=2,n=3; x[0] = 3; x[1] = 5; x[2] = 1; y[0] = 1; y[1] = 3; y[2] = 3; r[0] = 2; r[1] = 1; r[2] = 2; int tcount = 0; for (int k=min(xa,xb); k<=max(xa,xb); k++) { bool found1,found2 = false; for (int j=0; j<n; j++) { if (((k-x[j])*(k-x[j])+(y[j]-ya)*(y[j]-ya))<=r[j]*r[j]) { found1 = true; } if (((k-x[j])*(k-x[j])+(y[j]-yb)*(y[j]-yb))<=r[j]*r[j]) { found2 = true; } if (found1 && found2) break; } if (!found1) tcount++; if (!found2) tcount++; } cout << tcount << endl; return 0; } 42 GCC PR 51962

C99 has – 191 kinds of undefined behavior – 52 kinds of unspecified behavior Code in a bug report must not execute these behaviors ddmin and C-Reduce tend to introduce these behaviors 43

#!/bin/bash is_valid_c99 test.c &&\ clang -O1 test.c&&\./a.out > out1.txt&&\ clang -O2 test.c&&\./a.out > out2.txt&&\ ! diff out1.txt out2.txt 44

Validity checkers: KCC: executable semantics for C99 Frama-C: static analyzer that supports an interpreter mode 45

Median size output from reducers For 57 compiler-crash bugs – ddmin*:8.6 KB – C-Reduce: 0.33 KB For 43 wrong-code bugs – ddmin*: 6.5 KB – C-Reduce: 0.51 KB * 46

Reduction fails when compiler is non-deterministic – Usually due to memory unsafety + ASLR Reduction works poorly when compiler bug stems from a resource overflow – Infinite loop, memory leak, register spill 47

Can C-Reduce create reportable test cases from proprietary codes? We hope so Clearly “declassification” has to be done on a case-by-case basis We would love to get feedback about successes and failures 48

Does C-Reduce work for C++ code? – Yes, but not (yet) very well C++-specific transformations are needed – Template instantiation – Namespace and class hierarchy flattening Problem: No validity checker for C++ 49

Factoring the transformations out of a delta debugger is a good idea C-Reduce can (sometimes) produce beautiful test cases Ensuring validity of test cases is hard 50

C-Reduce is here: 51