Nightly pour [[https://bitbucket.org/ejsvifq_mabmip/mingw-gcc/src/master/|Windows 64]] [[https://gcc.gnu.org/projects/cxx-status.html|C++ status]], [[https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html|libstdc++ status]] ====Ubuntu==== * Installation en parallèle Ubuntu ne fournit pas de méthode 100% automatique. Il faut passer manuellement par ''update-alternatives''. sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 110 --slave /usr/bin/g++ g++ /usr/bin/g++-11 Utiliser pour switcher entre les versions : sudo update-alternatives --config gcc =====Diagnostic===== ====Information et taille des classes et tables virtuelles==== class VirtualBase { public : virtual int tick(int n) = 0; }; class VirtualDerived : public VirtualBase { public : int m_counter; public : VirtualDerived() : m_counter(0) {} int tick(int n) { m_counter += n; return m_counter; } }; * Jusqu'à gcc 7 : ''g++ -fdump-class-hierarchy -c main.cc'' * A partir de gcc 8 : ''g++ -fdump-lang-class -c main.cc'' Vtable for VirtualBase VirtualBase::_ZTV11VirtualBase: 3 entries 0 (int (*)(...))0 8 (int (*)(...))(& _ZTI11VirtualBase) 16 (int (*)(...))__cxa_pure_virtual Class VirtualBase size=8 align=8 base size=8 base align=8 VirtualBase (0x0x6ffffbe0480) 0 nearly-empty vptr=((& VirtualBase::_ZTV11VirtualBase) + 16) Vtable for VirtualDerived VirtualDerived::_ZTV14VirtualDerived: 3 entries 0 (int (*)(...))0 8 (int (*)(...))(& _ZTI14VirtualDerived) 16 (int (*)(...))VirtualDerived::tick Class VirtualDerived size=16 align=8 base size=12 base align=8 VirtualDerived (0x0x6ffffc301a0) 0 vptr=((& VirtualDerived::_ZTV14VirtualDerived) + 16) VirtualBase (0x0x6ffffbe04e0) 0 nearly-empty primary-for VirtualDerived (0x0x6ffffc301a0) * clang : ''clang -cc1 -emit-llvm -fdump-record-layouts main.cc'' Ci-dessous, on affiche que le contenu des ''Dumping AST Record Layout''. *** Dumping AST Record Layout 0 | class VirtualBase 0 | (VirtualBase vtable pointer) | [sizeof=8, dsize=8, align=8, | nvsize=8, nvalign=8] *** Dumping AST Record Layout 0 | class VirtualDerived 0 | class VirtualBase (primary base) 0 | (VirtualBase vtable pointer) 8 | int m_counter | [sizeof=16, dsize=12, align=8, | nvsize=12, nvalign=8] * Table virtuelle uniquement : ''clang -cc1 -emit-llvm -fdump-vtable-layouts main.cc'' Vtable for 'VirtualDerived' (3 entries). 0 | offset_to_top (0) 1 | VirtualDerived RTTI -- (VirtualBase, 0) vtable address -- -- (VirtualDerived, 0) vtable address -- 2 | int VirtualDerived::tick(int) VTable indices for 'VirtualDerived' (1 entries). 0 | int VirtualDerived::tick(int) Vtable for 'VirtualBase' (3 entries). 0 | offset_to_top (0) 1 | VirtualBase RTTI -- (VirtualBase, 0) vtable address -- 2 | int VirtualBase::tick(int) [pure] VTable indices for 'VirtualBase' (1 entries). 0 | int VirtualBase::tick(int) ====gprof==== Génère un graphe de l'utilisation des fonctions d'un programme (nécessite l'option de compilation ''-pg''). [[https://www.thegeekstuff.com/2012/08/gprof-tutorial/|GPROF Tutorial – How to use Linux GNU GCC Profiling Tool]] {{ :prog:gcc:gprof_tutorial_how_to_use_linux_gnu_gcc_profiling_tool_2020-02-24_3_24_57_pm_.html |Archive du 20/08/2012 le 24/02/2020}} ====Couverture de code==== Options à ajouter à la compilation : ''-O0 %%--%%coverage'' Options à ajouter au lieur : ''%%--%%coverage'' Puis exécuter le ou les programmes. Attention, pas d'exécution en parallèle. Les fichiers ''.gcno'' ne le supportent pas. lcov --capture --directory build --gcov-tool /usr/bin/gcov-10 --rc lcov_branch_coverage=1 --output-file build/coverage.info lcov --remove build/coverage.info "/usr/include/*" --rc lcov_branch_coverage=1 -o build/coverage2.info genhtml --output-directory build/coverage --demangle-cpp --num-spaces 2 --sort --function-coverage --branch-coverage --legend build/coverage2.info find build/coverage -name "*.html" -exec sed -i -r "s#headerValue""\>.*-.*-.* .*:.*:.*td#headerValue""> Attention, la version de gcov doit correspondre à celle de gcc. En option, on supprime la date pour qu'un diff simple puisse se faire. =====Commun avec clang===== ====Sanitizer==== Il existe ''-fsanitize=address,thread,undefined'' mais ''address'' et ''thread'' ne sont pas compatible simultanément. ===address=== Il détecte des erreurs de type global-buffer-overflow, heap-use-after-free. [[https://www.youtube.com/watch?v=qTkYDA0En6U|CppCon 2015: Kostya Serebryany “Beyond Sanitizers, Fuzzing and Hardening your C++ apps for Security and Reliability”]] * global-buffer-overflow int global_array[100] = {-1}; int main(int argc, char **argv) { return global_array[argc+100]; } gcc main.c -g -fsanitize=address -o main && ./main ================================================================= ==2500==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000740cf4 at pc 0x00000050d9bf bp 0x7ffeabb89b70 sp 0x7ffeabb89b68 READ of size 4 at 0x000000740cf4 thread T0 #0 0x50d9be in main /tmp/main.c:4:10 #1 0x7f1208faa461 in __libc_start_main .../sys-libs/glibc-2.25-r9/work/glibc-2.25/csu/../csu/libc-start.c:295 #2 0x419709 in _start (/tmp/main+0x419709) 0x000000740cf4 is located 4 bytes to the right of global variable 'global_array' defined in 'main.c:1:5' (0x740b60) of size 400 SUMMARY: AddressSanitizer: global-buffer-overflow /tmp/main.c:4:10 in main Shadow bytes around the buggy address: 0x0000800e0140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e0150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e0160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e0170: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e0180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0000800e0190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00[f9]f9 0x0000800e01a0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 00 00 00 00 0x0000800e01b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e01c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e01d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0000800e01e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 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 Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==2500==ABORTING [[prog:valgrind|valgrind]] ne détecte pas l'erreur. * heap-use-after-free int main(int argc, char **argv) { int *array = new int[100]; delete [] array; return array[argc]; } g++ main2.c -g -fsanitize=address -o main2 && ./main2 ================================================================= ==2765==ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000044 at pc 0x000000512445 bp 0x7ffd51684f60 sp 0x7ffd51684f58 READ of size 4 at 0x614000000044 thread T0 #0 0x512444 in main /tmp/main2.c:4:10 #1 0x7fd8d0086461 in __libc_start_main .../sys-libs/glibc-2.25-r9/work/glibc-2.25/csu/../csu/libc-start.c:295 #2 0x419d29 in _start (/tmp/main2+0x419d29) 0x614000000044 is located 4 bytes inside of 400-byte region [0x614000000040,0x6140000001d0) freed by thread T0 here: #0 0x50ef30 in operator delete[](void*) .../sys-libs/compiler-rt-sanitizers-5.0.0/work/compiler-rt-5.0.0.src/lib/asan/asan_new_delete.cc:141 #1 0x5123f6 in main /tmp/main2.c:3:3 #2 0x7fd8d0086461 in __libc_start_main .../sys-libs/glibc-2.25-r9/work/glibc-2.25/csu/../csu/libc-start.c:295 #3 0x419d29 in _start (/tmp/main2+0x419d29) previously allocated by thread T0 here: #0 0x50e1c8 in operator new[](unsigned long) .../sys-libs/compiler-rt- sanitizers-5.0.0/work/compiler-rt-5.0.0.src/lib/asan/asan_new_delete.cc:95 #1 0x5123d4 in main /tmp/main2.c:2:16 #2 0x7fd8d0086461 in __libc_start_main .../sys-libs/glibc-2.25-r9/work/glibc-2.25/csu/../csu/libc-start.c:295 #3 0x419d29 in _start (/tmp/main2+0x419d29) SUMMARY: AddressSanitizer: heap-use-after-free /tmp/main2.c:4:10 in main Shadow bytes around the buggy address: 0x0c287fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c287fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c287fff8000: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd 0x0c287fff8010: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c287fff8020: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c287fff8030: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa 0x0c287fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa [[prog:valgrind|valgrind]] détecte l'erreur. ==2787== Command: ./main2 ==2787== ==2787== Invalid read of size 4 ==2787== at 0x4005AF: main (main2.c:4) ==2787== Address 0x5b25c84 is 4 bytes inside a block of size 400 free'd ==2787== at 0x4C2CAA5: operator delete[](void*) (vg_replace_malloc.c:621) ==2787== by 0x4005A6: main (main2.c:3) ==2787== Block was alloc'd at ==2787== at 0x4C2BAC8: operator new[](unsigned long) (vg_replace_malloc.c:423) ==2787== by 0x400584: main (main2.c:2) * stack-use-after-return int *g; void LeakLocal() { int local; g = &local; } int main(){ LeakLocal(); return *g; } gcc main3.c -g -o main3 -fsanitize=address ASAN_OPTIONS=detect_stack_use_after_return=1 ./main3 L'utilisation de ''ASAN_OPTIONS=detect_stack_use_after_return=1'' est nécessaire car cette option peut créer des faux positifs. ================================================================= ==2907==ERROR: AddressSanitizer: stack-use-after-return on address 0x7f57b2a00020 at pc 0x00000050db25 bp 0x7ffe8dfc7330 sp 0x7ffe8dfc7328 READ of size 4 at 0x7f57b2a00020 thread T0 #0 0x50db24 in main /tmp/main3.c:10:10 #1 0x7f57b604d461 in __libc_start_main .../sys-libs/glibc-2.25-r9/work/glibc-2.25/csu/../csu/libc-start.c:295 #2 0x419709 in _start (/tmp/main3+0x419709) Address 0x7f57b2a00020 is located in stack of thread T0 at offset 32 in frame #0 0x50d95f in LeakLocal /tmp/main3.c:3 This frame has 1 object(s): [32, 36) 'local' (line 4) <== Memory access at offset 32 is inside this variable HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-use-after-return /tmp/main3.c:10:10 in main Shadow bytes around the buggy address: 0x0feb76537fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76537fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76537fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76537fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76537ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0feb76538000: f5 f5 f5 f5[f5]f5 f5 f5 00 00 00 00 00 00 00 00 0x0feb76538010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76538020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76538030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76538040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0feb76538050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [[prog:valgrind|valgrind]] détecte l'erreur. valgrind --track-origins=yes ./main3 ==2961== Syscall param exit_group(status) contains uninitialised byte(s) ==2961== at 0x4F002B8: _Exit (_exit.c:31) ==2961== by 0x4E70423: __run_exit_handlers (exit.c:98) ==2961== by 0x4E704DC: exit (exit.c:105) ==2961== by 0x4E58468: (below main) (libc-start.c:329) ==2961== Uninitialised value was created by a stack allocation ==2961== at 0x4004A4: main (main3.c:10) ===thread=== #include int main() { int x; std::thread t([&]{x=42;}); x = 43; t.join(); return 0; } g++ -std=c++11 main4.c -g -o main4 -fsanitize=thread Le plantage reste aléatoire et il est nécessaire de lancer l'application plusieurs fois. ================== WARNING: ThreadSanitizer: data race (pid=3226) Write of size 4 at 0x7ffd04d5b144 by thread T1: #0 operator() /tmp/main4.c:5 (main4+0x000000400d0b) #1 __invoke_impl > /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/g++-v7/bits/invoke.h:60 (main4+0x000000401171) #2 __invoke > /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/g++-v7/bits/invoke.h:95 (main4+0x000000400e30) #3 _M_invoke<0> /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/g++-v7/thread:234 (main4+0x0000004014b5) #4 operator() /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/g++-v7/thread:243 (main4+0x000000401448) #5 _M_run /usr/lib/gcc/x86_64-pc-linux-gnu/7.2.0/include/g++-v7/thread:186 (main4+0x0000004013ee) #6 (libstdc++.so.6+0x0000000e251e) Previous write of size 4 at 0x7ffd04d5b144 by main thread: #0 main /tmp/main4.c:6 (main4+0x000000400d75) Location is stack of main thread. Thread T1 (tid=3228, running) created by main thread at: #0 pthread_create (libtsan.so.0+0x00000002917a) #1 std::thread::_M_start_thread(std::unique_ptr >, void (*)()) (libstdc++.so.6+0x0000000e288c) #2 main /tmp/main4.c:5 (main4+0x000000400d69) SUMMARY: ThreadSanitizer: data race /tmp/main4.c:5 in operator() ================== ThreadSanitizer: reported 1 warnings [[prog:valgrind|valgrind]] ne détecte pas l'erreur. ===undefined=== int main(int argc, char **argv) { int t = argc << 16; return t*t; } gcc -fsanitize=undefined main5.c -g -o main5 main6.c:3:11: runtime error: signed integer overflow: 65536 * 65536 cannot be represented in type 'int' [[prog:valgrind|valgrind]] ne détecte pas l'erreur.