C++ Academy · Lekcja

UBSan i TSan

Znajduj niezdefiniowane zachowanie i wyścigi

Lekcja 3 z 413 kroki

UBSan i TSan to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C++ Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C++ Academy zawiera 4 lekcji w sumie.

Dwa kolejne sanitizery

Oprócz ASan dwa inne sanitizery wykrywają odmienne klasy błędów.

  • UBSan: niezdefiniowane zachowanie (przepełnienia, nieprawidłowe przesunięcia, dereferencja wskaźnika null)
  • TSan: wyścigi danych w kodzie wielowątkowym

Włączanie UBSan

UndefinedBehaviorSanitizer włącza się za pomocą -fsanitize=undefined. Można go łączyć z ASan.

g++ -fsanitize=undefined -g main.cpp -o app
./app

Przepełnienie liczby całkowitej ze znakiem

Przepełnienie liczby całkowitej ze znakiem jest niezdefiniowanym zachowaniem w C++. UBSan zgłasza je dokładnie w wierszu, w którym wystąpiło.

#include <climits>
#include <iostream>

int main() {
    int x = INT_MAX;
    int y = x + 1; // signed overflow: UB
    std::cout << y << "\n";
    return 0;
}

Inne błędy UB wykrywane przez UBSan

UBSan wykrywa wiele subtelnych błędów.

  • Przesunięcia poza dozwolony zakres (x << 40 dla 32-bitowego typu int)
  • Dereferencja wskaźnika null
  • Nieprawidłowo wyrównany dostęp
  • Nieprawidłowe wartości typu enum lub bool

Zatrzymywanie działania przez UBSan

Domyślnie UBSan wyświetla komunikat i kontynuuje działanie. Dodaj -fno-sanitize-recover=undefined, aby przerwać program po pierwszym błędzie — jest to lepsze rozwiązanie w CI.

g++ -fsanitize=undefined -fno-sanitize-recover=undefined -g main.cpp -o app

Włączanie TSan

ThreadSanitizer włącza się za pomocą -fsanitize=thread. Wykrywa wyścigi danych: sytuacje, w których dwa wątki uzyskują dostęp do tej samej pamięci bez synchronizacji, a co najmniej jeden z nich ją modyfikuje.

g++ -fsanitize=thread -g main.cpp -o app -pthread
./app

Przykład wyścigu danych

Dwa wątki zwiększają współdzielony licznik bez blokady. TSan zgłasza kolidujące dostępy oraz ich stosy wywołań.

#include <thread>
#include <iostream>

int counter = 0;

void work() { for (int i = 0; i < 1000; ++i) ++counter; }

int main() {
    std::thread t1(work), t2(work);
    t1.join();
    t2.join();
    std::cout << counter << "\n";
    return 0;
}

Naprawianie wyścigu

Chroń współdzielone dane za pomocą muteksu lub użyj std::atomic. Po naprawie TSan nie zgłosi żadnych wyścigów.

#include <thread>
#include <atomic>
#include <iostream>

std::atomic<int> counter{0};

void work() { for (int i = 0; i < 1000; ++i) ++counter; }

int main() {
    std::thread t1(work), t2(work);
    t1.join();
    t2.join();
    std::cout << counter << "\n";
    return 0;
}

Zgodność TSan i ASan

TSan nie może być łączony z ASan w tej samej kompilacji (konfliktują ze sobą). Używaj osobnych konfiguracji kompilacji: jednej dla ASan+UBSan, a drugiej dla TSan.

Macierz kompilacji z sanitizerami

Praktyczna konfiguracja CI uruchamia zestaw testów w dwóch kompilacjach z sanitizerami.

  • Kompilacja A: -fsanitize=address,undefined
  • Kompilacja B: -fsanitize=thread

Obejmuje to błędy pamięci, niezdefiniowanego zachowania i współbieżności.

Koszt i ograniczenia

TSan może spowalniać programy od 5 do 15 razy i zużywać znacznie więcej pamięci. Podobnie jak wszystkie sanitizery, wykrywa błędy tylko na wykonywanych ścieżkach kodu, dlatego dobre testy wielowątkowe mają duże znaczenie.

Szybkie sprawdzenie

Przypomnij sobie, co wykrywa TSan.

Podsumowanie

Poznali Państwo UBSan i TSan.

  • UBSan (-fsanitize=undefined) wykrywa przepełnienia, nieprawidłowe przesunięcia i dereferencję wskaźnika null
  • Użyj -fno-sanitize-recover, aby przerwać działanie po pierwszym błędzie UB
  • TSan (-fsanitize=thread) wykrywa wyścigi danych; należy je naprawiać za pomocą muteksu lub atomic
  • TSan i ASan wymagają osobnych kompilacji
Bezpłatny start

Ucz się C++ dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
51
Lekcje
203

Często zadawane pytania

Czy lekcja „UBSan i TSan” jest bezpłatna?

Tak — pełny tekst „UBSan i TSan” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C++ Academy, przejdź na CoddyKit PRO. Kurs C++ Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „UBSan i TSan”?

Znajduj niezdefiniowane zachowanie i wyścigi Ćwiczysz C++ Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C++ Academy?

Nie wymagamy żadnego doświadczenia. C++ Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „UBSan i TSan”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C++ Academy?

Tak. Każda lekcja C++ Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Używanie gdb i lldb
  2. AddressSanitizer
  3. UBSan i TSan
  4. Podstawy Valgrind
← Powrót do C++ Academy