Write better* C++ - @let@token with help from your friend Clang@let

W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
with help from your friend Clang
living knowledge
WWU Münster
René Milk
23rd October 2013
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
2 /31
Contents
What is Clang?
Dynamic analysis (sanitizers)
Tools
living knowledge
WWU Münster
Static analysis
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
3 /31
LLVM1
LLVM (formerly Low Level Virtual Machine) is a compiler infrastructure written in C++; it is
designed for compile-time, link-time, run-time, and "idle-time" optimization of programs
written in arbitrary programming languages.
Clang is a compiler front end for the C, C++, Objective-C and Objective-C++ programming
languages. It uses LLVM as its back end and has been part of its releases since LLVM 2.6.
1
2
https://en.wikipedia.org/wiki/LLVM
https://en.wikipedia.org/wiki/Clang
living knowledge
WWU Münster
Clang2
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
4 /31
I
fast compiles with low memory usage 3
I
detailed “fix-it” notes for warnings and errors
I
build on top of libclang, API allows for extensive tooling
I
fully4 supports c++11 since version 3.3
3
4
http://clang.llvm.org/features.html#performance
http://clang.llvm.org/cxx_status.html
living knowledge
WWU Münster
Clang features
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
5 /31
I
code with fewer bugs
I
shorter compile times
I
consistent formatting
I
not faster execution
I
not code quality in terms of style, complexity, etc.
living knowledge
WWU Münster
for this talk we’ll take “better” as referring to:
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
6 /31
static code (program) analysis5
5
https://en.wikipedia.org/wiki/Static_program_analysis
living knowledge
WWU Münster
Static program analysis is the analysis of computer software that is performed without
actually executing programs (analysis performed on executing programs is known as
dynamic analysis).
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
7 /31
Why you should compile at high warning levels
I
typos
I
unintentional operator usage
I
potential data over/underflows
I
dead code
living knowledge
WWU Münster
Catch code segments that are valid C++, but (probably) not what you meant to write.
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
8 /31
error free build 6= error free code
/// \file warnings_00.cc
#include <cstddef>
#include <string>
int main(int argn, char** argv)
{
auto name = argv[0];
int* i = 0;
10
unsigned long long bigstuff = 8 << 32;
if ( name == "foo" )
char* name = "bar";
else if ( name = NULL )
bigstuff = -1;
15
for ( ; bigstuff < 0; i++);
bigstuff--;
return bigstuff**i;
}
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
9 /31
how many warnings did that generate?
default
“most"
6
13
”most“ warnings settings
clang++ -g -std=c++11 -Wsign-conversion -O0 -g -Wall -Wextra -Wc++0x-compat
-Winline -pedantic -Wredundant-decls -Wloop-analysis -Wstring-compare -Wshadow
-Wunused-variable -Wundef -Wnon-virtual-dtor -Wdocumentation -Wshorten-64-to-32
-Wused-but-marked-unused -Wdisabled-macro-expansion -Wparentheses
-Wsometimes-uninitialized -Wconditional-uninitialized -Wfloat-equal -Wswitch-enum
-Warray-bounds -Wcovered-switch-default -Wunreachable-code
-Wnon-literal-null-conversion -Wtautological-compare
living knowledge
WWU Münster
Table : clang version 3.4-1 exp1
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
10 /31
sign-conversion / tautological-compare
/// \file warnings_01.cc
#include <cstddef>
int main(int, char**)
{
std::size_t bigstuff = -1;
return bigstuff < 0;
}
warnings_01.cc:5:28: warning: implicit conversion changes signedness: ’int’ to
’std::size_t’ (aka ’unsigned long’) [-Wsign-conversion]
std::size_t bigstuff = -1;
~~~~~~~~
^~
warnings_01.cc:6:21: warning: comparison of unsigned expression < 0 is always
false [-Wtautological-compare]
return bigstuff < 0;
~~~~~~~~ ^ ~
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
11 /31
parentheses
warnings_02.cc:4:14: warning: using the result of an assignment as
a condition without parentheses [-Wparentheses]
if (argn = 1)
~~~~~^~~
warnings_02.cc:4:14: note: place parentheses around the assignment to silence this warning
if (argn = 1)
^
(
)
warnings_02.cc:4:14: note: use ’==’ to turn this assignment into an equality comparison
if (argn = 1)
^
==
living knowledge
WWU Münster
5
/// \file warnings_02.cc
int main(int argn, char**)
{
if (argn = 1)
return -1;
}
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
12 /31
loop-analysis / empty-body
/// \file warnings_03.cc
warnings_03.cc:6:10: warning: variable ’argn’ used in loop condition
not modified in loop body [-Wloop-analysis]
for(;argn > 0;);
^~~~
warnings_03.cc:6:20: warning: for loop has empty body [-Wempty-body]
for(;argn > 0;);
^
warnings_03.cc:6:20: note: put the semicolon on a separate line to silence this warning
living knowledge
WWU Münster
5
#include <iostream>
int main(int argn, char** argv)
{
for(;argn > 0;);
std::cout << argv[--argn] << std::endl;
}
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
13 /31
switch / return-type
/// \file warnings_04.cc
enum Things { Dog, Frog };
int foo(Things thing) {
switch (thing) {
case Dog: return 9001;
}
}
10
int main(int, char**) { return 0;}
warnings_04.cc:6:13: warning: enumeration value ’Frog’ not handled in switch [-Wswitch]
switch (thing) {
^
warnings_04.cc:9:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
14 /31
covered-switch-default
/// \file warnings_05.cc
enum Things { Dog, Frog };
int bar(Things thing) {
int ret;
switch (thing) {
case Dog: case Frog: ret = 0;
default: ret = -1;
10
}
return ret;
}
int main(int, char**) { return 0;}
warnings_05.cc:9:9: warning: default label in switch which covers
all enumeration values [-Wcovered-switch-default]
default: ret = -1;
^
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
15 /31
array-bounds
/// \file warnings_06.cc
const int ones[] = {1};
int main() {
const auto bar = ones[1];
return bar;
}
warnings_06.cc:4:22: warning: array index 1 is past the end of the array
(which contains 1 element) [-Warray-bounds]
const auto bar = ones[1];
^
~
warnings_06.cc:1:1: note: array ’ones’ declared here
const int ones[] = {1};
^
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
16 /31
the analyzer plugin
#include <cstddef>
#include <string>
inline int the_meaning_of_life_and_everything() { return 42; }
int main(int, char**)
{
const int* i = nullptr;
auto j = the_meaning_of_life_and_everything();
j = sizeof(int);
10
return j+*i;
}
static_00.cc:8:10: warning: Value stored to ’j’ during its initialization is never read
auto j = the_meaning_of_life_and_everything();
^
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
static_00.cc:10:14: warning: Dereference of null pointer (loaded from variable ’i’)
return j+*i;
^~
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
17 /31
I
Address Sanitizer - out-of-bounds checks, use-after-free,...
I
Thread Sanitizer - finds data races
I
Memory Sanitizer - detects uninitialized reads
I
(soon?) Undefined Behavior Sanitizer - ???
living knowledge
WWU Münster
available sanitizers
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
18 /31
I
inserts instrumentation code into the binary
I
“replays” memory access in shadow memory
I
runs algorithms to find patterns of unwanted behaviour
I
incurs runtime and memory penalty when activated
living knowledge
WWU Münster
What is a sanitizer?
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
19 /31
memory sanitizer - unitialized read
==14624== WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7fdb3ee1b9e6 in main instrumentation_01.cc:6
#1 0x7fdb3d9a3de4 in __libc_start_main /build/buildd/eglibc-2.17/csu/libc-start.c:260
#2 0x7fdb3ee1b89c in _start (01+0x6589c)
SUMMARY: MemorySanitizer: use-of-uninitialized-value instrumentation_01.cc:6 main
Exiting
living knowledge
WWU Münster
5
int main(int argc, char**)
{
int* i = new int[666];
if (i[0])
return -1;
}
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
20 /31
address sanitizer - heap-use-after-free I
10
15
20
25
struct Player {
const YYZ& song_;
Player(const YYZ& song) : song_(song) {}
int length() const { return song_.length(); }
};
int main(int, char**)
{
unique_ptr<Player> player(nullptr);
{
YYZ* yyz = new YYZ;
player = unique_ptr<Player>(new Player(*yyz));
delete yyz;
}
auto le = player->length();
std::cout << le;
return le;
}
living knowledge
WWU Münster
5
#include <memory>
#include <iostream>
using namespace std;
struct YYZ {
int length () const { return (4-int(radio_)*60)+25; }
bool radio_;
YYZ(bool radio = false) : radio_(radio){}
};
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
21 /31
=================================================================
==12704==ERROR: A6ddressSanitizer: heap-use-after-free on address 0x60200000eff0
at pc 0x473841 bp 0x7fff778bdcc0 sp 0x7fff778bdcb8
READ of size 1 at 0x60200000eff0 thread T0
#0 0x473840 in YYZ::length() const instrumentation_02.cc:5
#1 0x472f78 in main instrumentation_02.cc:23
#2 0x7f73aac68de4 in __libc_start_main /build/buildd/eglibc-2.17/csu/libc-start.c:260
#3 0x472dac in _start (02+0x472dac)
0x60200000eff0 is located 0 bytes inside of 1-byte region [0x60200000eff0,0x60200000eff1)
freed by thread T0 here:
#0 0x45eb29 in operator delete(void*) (02+0x45eb29)
#1 0x472f68 in main instrumentation_02.cc:21
#2 0x7f73aac68de4 in __libc_start_main /build/buildd/eglibc-2.17/csu/libc-start.c:260
previously allocated by thread T0 here:
#0 0x45e829 in operator new(unsigned long) (02+0x45e829)
#1 0x472f12 in main instrumentation_02.cc:19
#2 0x7f73aac68de4 in __libc_start_main /build/buildd/eglibc-2.17/csu/libc-start.c:260
SUMMARY: AddressSanitizer: heap-use-after-free instrumentation_02.cc:5 YYZ::length() const
living knowledge
WWU Münster
heap-use-after-free II
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
22 /31
Shadow bytes around the buggy address:
0x0c047fff9da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c047fff9df0: fa fa fa fa fa fa fa fa fa fa 00 fa fa fa[fd]fa
0x0c047fff9e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable:
00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone:
fa
Heap right redzone:
fb
Freed heap region:
fd
Stack left redzone:
f1
Stack mid redzone:
f2
Stack right redzone:
f3
Stack partial redzone: f4
Stack after return:
f5
Stack use after scope: f8
Global redzone:
f9
Global init order:
f6
Poisoned by user:
f7
ASan internal:
fe
==12704==ABORTING
living knowledge
WWU Münster
heap-use-after-free III
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
23 /31
I
clang-format
I
clang-modernize
I
include-what-you-use (iwyu)
I
cldoc
living knowledge
WWU Münster
Tools built with (lib)Clang
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
24 /31
5
/// \file format.cc
#include <cstddef>
#include <string>
int main(int argn,char** argv){auto name=argv[0];int* i=0;unsigned long
long bigstuff=8<<32;if(name=="foo")char* name="bar";else if(name=NULL)bigstuff=
-1;for(;bigstuff<0;i++);bigstuff--;return bigstuff**i;}
living knowledge
WWU Münster
Example clang-format (before)
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
25 /31
Example clang-format (after)
/// \file format.cc
#include <cstddef>
#include <string>
int main(int argn, char **argv) {
5
auto name = argv[0];
int *i = 0;
unsigned long long bigstuff = 8 << 32;
if (name == "foo")
char *name = "bar";
10
else if (name = NULL)
bigstuff = -1;
for (; bigstuff < 0; i++)
;
bigstuff--;
15
return bigstuff * *i;
}
living knowledge
WWU Münster
clang-format-3.4 -style=LLVM format.cc > format_after.cc
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
26 /31
Example clang-modernize (before)
/// \file modernize.cc
#include <vector>
template <class T>
void increment(std::vector<T>& vec) {
for (typename std::vector<T>::iterator it = vec.begin();
it != vec.end(); ++it)
{
++(*it);
10
}
}
int main() {std::vector<int> a(2,4); increment(a);}
living knowledge
WWU Münster
5
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
27 /31
Example clang-modernize (after)
clang-modernize -format-style=LLVM modernize.cc
5
template <class T>
void increment(std::vector<T>& vec) {
for (auto &elem : vec) {
++(elem);
}
}
10
int main() {std::vector<int> a(2,4); increment(a);}
living knowledge
WWU Münster
/// \file modernize.cc
#include <vector>
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
28 /31
Example iwyu (input)
/// \file iwyu.cc
10
<vector>
<assert.h>
<iterator>
<memory>
<sstream>
<iostream>
int main()
{
using namespace std;
cout << abs(long(-1));
}
living knowledge
WWU Münster
5
#include
#include
#include
#include
#include
#include
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
29 /31
Example iwyu (output)
-std=c++11 iwyu.cc
iwyu.cc should add these lines:
#include <cstdlib>
5
// for abs
iwyu.cc should remove these lines:
- #include <assert.h> // lines 2-2
- #include <iterator> // lines 3-3
- #include <memory> // lines 4-4
- #include <sstream> // lines 5-5
- #include <vector> // lines 1-1
10
The full include-list for iwyu.cc:
#include <cstdlib>
#include <iostream>
---
// for abs
// for cout, ostream
living knowledge
WWU Münster
iwyu
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
30 /31
Example cldoc
living knowledge
WWU Münster
http://jessevdk.github.io/cldoc/example/
,
,
[email protected]
W ESTFÄLISCHE
W ILHELMS -U NIVERSITÄT
M ÜNSTER
Write better* C++
31 /31
living knowledge
WWU Münster
Thank you for
your attention.
,
,
[email protected]