C Academy · Lekcja

Nieprawidłowy dostęp

Wyjście poza zakres i niezainicjowane dane

Lekcja 3 z 413 kroki

Nieprawidłowy dostęp 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.

Poza wyciekami

Wycieki marnują pamięć, ale błędy nieprawidłowego dostępu ją uszkadzają. memcheck wykrywa kilka ich rodzajów:

  • Odczyt lub zapis poza końcem bufora
  • Użycie pamięci po wywołaniu free
  • Odczyt niezainicjalizowanych wartości
  • Odczyt lub zapis za pomocą nieprawidłowego wskaźnika

Powodują one najbardziej niebezpieczne i najtrudniejsze do odtworzenia awarie.

Zapis poza zakresem

Ten kod alokuje miejsce na 5 wartości typu int, ale zapisuje pod indeks 5, czyli w szóstym miejscu.

Indeks 5 znajduje się o jeden element za końcem. memcheck zgłasza w tym wierszu Invalid write of size 4.

#include <stdlib.h>

int main(void) {
    int *a = malloc(5 * sizeof(int));
    a[5] = 99; /* valid indices are 0..4 */
    free(a);
    return 0;
}

Odczytywanie komunikatu błędu

Raport określa operację, jej rozmiar oraz relację względem bloku:

Invalid write of size 4
Address 0x... is 0 bytes after a block of size 20 alloc'd

Informacja „0 bytes after a block of size 20” oznacza, że dostęp nastąpił bezpośrednio za blokiem o rozmiarze 20 bajtów (5 wartości typu int).

Odczyt poza zakresem

Odczyty również są wykrywane. W tym przypadku pętla wykonuje się o jeden element za daleko.

memcheck zgłasza Invalid read of size 4 podczas ostatniej iteracji, nawet jeśli program może przez przypadek „działać”.

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int *a = calloc(3, sizeof(int));
    for (int i = 0; i <= 3; i++)   /* should be i < 3 */
        printf("%d\n", a[i]);
    free(a);
    return 0;
}

Niezainicjalizowane wartości

malloc nie zeruje pamięci. Użycie zaalokowanej pamięci przed przypisaniem wartości prowadzi do uzyskania nieprzewidywalnej wartości.

memcheck zgłasza Conditional jump or move depends on uninitialised value(s), gdy taka wartość wpływa na sterowanie przepływem lub dane wyjściowe.

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int *p = malloc(sizeof(int));
    if (*p == 0)              /* *p was never set */
        printf("zero\n");
    free(p);
    return 0;
}

Dlaczego raporty o niezainicjalizowanych wartościach pojawiają się z opóźnieniem

memcheck nie zgłasza problemu natychmiast po odczycie niezainicjalizowanej pamięci. Śledzi „zdefiniowanie” wartości i raportuje problem dopiero wtedy, gdy niezdefiniowana wartość faktycznie ma znaczenie, na przykład w instrukcji warunkowej, danych wyjściowych lub wywołaniu systemowym.

Zapobiega to fałszywym alarmom podczas nieszkodliwego kopiowania niezainicjalizowanych bajtów.

Użycie po zwolnieniu pamięci

Odwołanie do pamięci po jej zwolnieniu jest niezdefiniowanym zachowaniem. memcheck wykrywa je precyzyjnie.

Zgłasza Invalid read of size 4 z informacją Address ... is 0 bytes inside a block of size 4 free'd, a także pokazuje, gdzie nastąpiło wywołanie free.

#include <stdlib.h>
#include <stdio.h>

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 7;
    free(p);
    printf("%d\n", *p);   /* read after free */
    return 0;
}

Podwójne zwolnienie pamięci

Dwukrotne zwolnienie tego samego wskaźnika uszkadza wewnętrzne struktury alokatora.

memcheck zgłasza Invalid free() i pokazuje zarówno bieżące zwolnienie, jak i pierwotną alokację, dzięki czemu błąd staje się oczywisty.

#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    free(p);
    free(p);   /* freed twice */
    return 0;
}

Śledzenie źródeł

W przypadku błędów związanych z niezainicjalizowanymi wartościami należy dodać --track-origins=yes.

memcheck wskaże wtedy miejsce, w którym błędna wartość została utworzona, a nie tylko miejsce jej użycia, zamieniając niejasne ostrzeżenie w precyzyjną wskazówkę dotyczącą naprawy.

valgrind --track-origins=yes ./prog

Stos i zmienne globalne

memcheck doskonale wykrywa błędy na stercie. W przypadku przepełnień na stosie lub w globalnych tablicach jego możliwości są mniejsze.

W takich sytuacjach często lepszym wyborem jest AddressSanitizer (gcc -fsanitize=address). Te dwa narzędzia wzajemnie się uzupełniają.

Błąd o jeden element: terminator null

Częstym przepełnieniem sterty jest pominięcie terminatora łańcucha. strlen zwraca 5 dla 'hello', ale łańcuch potrzebuje 6 bajtów, aby przechować końcowy znak '\0'.

memcheck zgłasza Invalid write, gdy strcpy zapisuje ten ostatni bajt poza końcem obszaru.

#include <stdlib.h>
#include <string.h>

int main(void) {
    char *s = malloc(strlen("hello")); /* needs +1 */
    strcpy(s, "hello");                 /* writes the '\0' past end */
    free(s);
    return 0;
}

Szybkie sprawdzenie

Proszę określić, co memcheck zgłasza dla tego fragmentu kodu.

Podsumowanie

Potrafi już Pan/Pani rozpoznawać błędy nieprawidłowego dostępu:

  • Odczyty/zapisy poza zakresem są zgłaszane jako Invalid read/write wraz z przesunięciem względem bloku
  • Niezainicjalizowane wartości są wykrywane, gdy wpływają na decyzję lub dane wyjściowe
  • Użycie po zwolnieniu i podwójne zwolnienie są wykrywane wraz z obydwoma miejscami wywołania
  • --track-origins=yes wskazuje źródło niezdefiniowanych wartości; w przypadku błędów stosu należy użyć go wraz z ASan

Następnie: odczytywanie pełnego raportu.

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
39
Lekcje
144

Często zadawane pytania

Czy lekcja „Nieprawidłowy dostęp” jest bezpłatna?

Tak — pełny tekst „Nieprawidłowy dostęp” 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 „Nieprawidłowy dostęp”?

Wyjście poza zakres i niezainicjowane dane Ć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 „Nieprawidłowy dostęp”?

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. Dlaczego Valgrind
  2. Wykrywanie wycieków
  3. Nieprawidłowy dostęp
  4. Odczytywanie raportów
← Powrót do C Academy