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]
© Copyright 2026 Paperzz