piątek, 25 listopada 2022

LPC1769 - Cppcheck

W tym poście chciałbym opisać takie narzędzie jak CppCheck. 



CppCheck jest to narzędzie służące do statycznej analizy kodu. 

Lista elementów jakie są sprawdzane podczas analizy kodu można zobaczyć pod tym linkiem

Poniżej przedstawię proces instalacji narzędzia w środowisku MCUXpresso. Ponieważ bazuje ono na eclipsie, to w większości przypadków proces instalacyjny będzie bardzo podobny.

Instalacja przebiega całkiem intuicyjnie. Niestety z powodu zamknięcie serwera dla eclipsa, pliki instalacyjne należy pobrać z githuba [link], zamiast bezpośrednio z Eclipse Marketplace.

Bezpośrednio w eclipsie należy podać ścieżkę do plików CPP. Należy otworzyć okno Window->Preferences. 


Gdzie zostanie dodana ścieżka do lokalizacji pliku cppcheck.exe.

Po wykonaniu operacji i zatwierdzeniu listy sprawdzanych potencjalnych błędów w kodzie (cppchecklipse->problem). Należy ponownie uruchomić program.

Aby uruchomienić sprawdzania należy prawym klawiszy myszy kliknąć na projekt, wybrać cppcheck i run cppcheck. Druga dostępna opcja czyści wygenerowane błędy z wyświetlania.

Przyjrzyjmy się teraz kilku przykładowym błędom w kodzie, jakie mogą zostać wykryte przez to narzędzie.

Dla przykładowego projektu CppCheck znalazł następujące błędy:


Error:


1. Buffer is accesed out of bounds:

  1. char array[28] = {0x00};
  2. memset(array, 0x20, 32);

Dla powyższego przypadku tablica array składa się z 28 elementów natomiast poleceniem memset wprowadzamy dane do 32 elementów, przez co wychodzimy poza zakres tablicy. Poprawiamy błąd przez zmianę wartości 32 na 28. 

2. Common realloc mistake: 'postData' nulled but not freed upon failure

W tym błędzie chodzi o to, że gdy realloc się nie powiedzie to zwróci wartość NULL. W takim przypadku należy sprawdzać czy operacja jest poprawna i wykonać jakieś działanie. 

  1. postData = (uint8_t *) realloc((uint8_t *) postData, POST_DATA_LENGTH);

  1. uint8_t * tmp = (uint8_t *) realloc((uint8_t *) postData, POST_DATA_LENGTH);
  2.  
  3. if (NULL == tmp)
  4. {
  5.     free(postData);
  6. }
  7. else
  8. {
  9.     postData = tmp;
  10. }

3. Uninitialized variable: val

Błędy tym razem dotyczą funkcji udostępnionych przez producenta:

  1. USB_INT32U  ReadLE32U (volatile  USB_INT08U  *pmem)
  2. {
  3.     USB_INT32U   val;
  4.  
  5.     ((USB_INT08U *)&val)[0] = pmem[0];
  6.     ((USB_INT08U *)&val)[1] = pmem[1];
  7.     ((USB_INT08U *)&val)[2] = pmem[2];
  8.     ((USB_INT08U *)&val)[3] = pmem[3];
  9.  
  10.     return (val);
  11. }

Funkcja składa tablicę 8 bitową na zmienną 32 bitową. Tutaj rozwiązanie błędu można uzyskać przez ustawienie wartości początkowej dla zmiennej.

Warning:


Uninitialized variable: uart_rx_arr.

Tutaj w instrukcji warunkowej sprawdzam wartość wpisaną do tablicy, która nie została na początku zainicjalizowana wartościami, tylko są one do niej wprowadzone później

  1. uint8_t uart_rx_arr[ARR_LEN];
  2.  
  3. //Rozwiązanie uint8_t uart_rx_arr[ARR_LEN] = {0x00};
  4.  
  5. //...
  6. //...
  7.  
  8. if(uart_rx_arr[3] == 0x04) {
  9. //...
  10. //...

Info:


Too many #ifdef configurations - cppcheck only checks 12 configurations. Use --force to check all configurations. For more details, use --enable=information.

W testowanym projekcie znajduje się dużo zależności, zależny od ustawienia dyrektyw. CppCheck informuje, że jest w stanie sprawdzić 12 konfiguracji. 

Można to rozwiązać przez dołożenie flagi --force i ponowne wywołanie sprawdzania. 


Flagę wywołuję we właściwościach projektu. Tak samo jak na screenie powyżej.

Linki: