Jakie narzędzia lub standardy można zastosować w celu poprawy niezawodności osadzonego kodu C?

9

Zazwyczaj programuję PIC w C, zwykle dla konwerterów przełączanych. Słyszałem o różnych narzędziach i standardach analizy statycznej, takich jak MISRA C , których można użyć do poprawy niezawodności kodu. Chciałbym wiedzieć więcej. Jakie standardy lub narzędzia mogą być odpowiednie dla mojego kontekstu?

Stephen Collings
źródło
1
Jak ustawiony jest język C?
Brian Drummond
1
Mogłoby mnie przekonać do przejścia na coś innego, gdyby było na to bardzo dobre uzasadnienie. Ale musiałby to być bardzo dobry przypadek.
Stephen Collings
„Bardzo dobrego przypadku” na przejście z C nie można zrobić szybko, a dla PIC prawdopodobnie jeszcze nie. W przypadku AVR, ARM lub MSP430 Ada byłaby warta poważnego spojrzenia (pomimo tego, że przyciąga, jak widać!), A dla wysokiej relacji SPARK jest wart spojrzenia.
Brian Drummond
Mogą Cię zainteresować jako podstawowe informacje: SPARK vs MISRA-C spark-2014.org/entries/detail/… oraz niniejsze studium przypadku: spark-2014.org/uploads/Nosegearpaper_1.pdf
Brian Drummond
Być może lepiej zainwestować czas, aby przekonać się do przejścia z PIC na coś nowoczesnego ... Zwłaszcza jeśli projektujesz systemy o kluczowym znaczeniu dla misji, dla których pierwotnie były przeznaczone MISRA i SPARK.
Lundin

Odpowiedzi:

11

Sprawdzanie poprawności kodu osadzonego jest trudne, szczególnie w przypadku części o ograniczonych zasobach, takich jak PIC. Często nie masz luksusu kodowania w przypadkach testowych z powodu ograniczeń pamięciowych części i często programowania w czasie rzeczywistym wykonywanego na tego rodzaju urządzeniach.

Oto niektóre z moich wskazówek:

  1. Napisz specyfikację, jeśli nie istnieje: Jeśli nie kodujesz w oparciu o specyfikację, udokumentuj, do czego powinien służyć Twój kod, jakie są prawidłowe dane wejściowe, jakie są oczekiwane wyniki, jak długo powinna trwać każda procedura, co może, a czego nie może uzyskać clobbered itp. - teoria działania, schematy blokowe, wszystko jest lepsze niż nic.

  2. Skomentuj swój kod: To, że coś jest dla ciebie oczywiste, nie oznacza, że ​​jest oczywiste (lub poprawne) dla kogoś innego. Komentarze w prostym języku są niezbędne zarówno do przeglądu, jak i utrzymania kodu.

  3. Kod defensywnie: Nie dołączaj tylko kodu do normalnych danych wejściowych. Obsługuj brakujące dane wejściowe, dane wejściowe poza zakresem, przepełnienia matematyczne itp. - im więcej zakrętów obejmie Twój projekt kodu, tym mniej stopni swobody będzie miał kod po wdrożeniu.

  4. Użyj narzędzi do analizy statycznej: może być upokarzające, ile narzędzi błędów, takich jak PC-lint, można znaleźć w kodzie. Rozważ czystą analizę statyczną jako dobry punkt wyjścia do poważnych testów.

  5. Niezbędne są wzajemne oceny: Twój kod powinien być czysty i wystarczająco udokumentowany, aby mógł być skutecznie sprawdzony przez niezależną stronę. Sprawdź swoje ego przy drzwiach i poważnie rozważ wszelkie uwagi i sugestie.

  6. Testowanie jest niezbędne: powinieneś przeprowadzić własną weryfikację, a także niezależną weryfikację kodu. Inni mogą złamać kod w sposób, którego nie możesz sobie wyobrazić. Przetestuj każdy prawidłowy warunek i każdy nieprawidłowy warunek, jaki możesz wymyślić. Używaj PRNG i wprowadzaj śmieciowe dane. Rób wszystko, co możesz, aby coś zepsuć, a następnie napraw i spróbuj ponownie. Jeśli masz szczęście, będziesz mógł uruchomić swój kod w trybie debugowania i zerknąć na rejestry i zmienne - jeśli nie, musisz być sprytny i przełączać diody LED / sygnały cyfrowe, aby zorientować się w stanie swojego urządzenie. Zrób wszystko, co konieczne, aby uzyskać potrzebne informacje zwrotne.

  7. Spójrz pod maską: nie bój się spojrzeć na kod maszynowy generowany przez kompilator C. Możesz (będzie?) Znajdować miejsca, w których twój piękny kod C wysadził się w dziesiątki, jeśli nie setki operacji, w których coś, co powinno być bezpieczne (ponieważ jest to tylko jedna linia kodu, prawda?), Zajmuje tyle czasu, że wykonanie wielu przerwań zwolnili i unieważnili warunki. Jeśli coś stanie się okropnie nieefektywne, przerób to i spróbuj ponownie.

Adam Lawrence
źródło
+1 Wszystkie porady dźwiękowe. Oczekiwałbym, że każdy profesjonalny twórca oprogramowania układowego po prostu się uśmiechnie i przytaknie podczas czytania.
Lundin
2
Ważnym aspektem recenzji jest to, że recenzja dotyczy kodu, a nie programisty. Jeśli przeanalizujesz kod za pomocą terminów typu „najpierw to zrobię, a potem to zrobię”, prawdopodobnie masz kłopoty. „Najpierw kod to robi, a potem tak” to właściwy sposób na myślenie o tym. To samo dotyczy recenzentów: nie „dlaczego to zrobiłeś?”, Ale „dlaczego kod to robi?”.
Pete Becker
Możesz również rozważyć dodanie: 1. Korzystanie z cyklicznej kontroli złożoności 2. Oprogramowanie do kontroli wersji
AlphaGoku,
4

Większość tych samych technik tworzenia niezawodnego oprogramowania na PC ma również zastosowanie do programowania wbudowanego. Pomocne jest oddzielenie algorytmów od kodu specyficznego dla sprzętu i przetestowanie ich osobno za pomocą testów jednostkowych, symulacji, analizy statycznej i narzędzi takich jak Valgrind. W ten sposób jest o wiele mniej kodu, który jest testowany tylko na sprzęcie.

Nie zrezygnowałbym z C. Chociaż języki takie jak Ada dają pewne drobne gwarancje, łatwo wpaść w pułapkę myślenia, że ​​język obiecuje więcej niż w rzeczywistości.

Theran
źródło
Valgrid może być jednak nieco bardziej odpowiedni na PC niż dla 8-bitowego MCU :)
Lundin
Niestety niektóre techniki tworzenia dobrego oprogramowania na poziomie komputera są bardzo nieodpowiednie dla małych mikr, a niektóre praktyki uważane za złe i złe na komputerach PC są całkowicie akceptowalne w środowisku osadzonym.
John U
3

MISRA-C jest rzeczywiście bardzo przydatny do poprawy ogólnej jakości kodu i minimalizacji błędów. Upewnij się tylko, że przeczytałeś i zrozumiałeś każdą zasadę, większość z nich jest dobra, ale kilka z nich nie ma żadnego sensu.

Ostrzeżenie tutaj. Dokument MISRA zakłada, że ​​czytelnikiem jest osoba z rozległą znajomością języka C. Jeśli nie masz takiego zahartowanego weterana C w swoim zespole, ale zdecydujesz się wziąć analizator statyczny, a następnie ślepo stosować się do każdego podanego ostrzeżenia, najprawdopodobniej spowoduje to obniżenie jakości kodu, ponieważ możesz zmniejszyć czytelność i wprowadzić błędy przez przypadek. Widziałem to wiele razy, konwersja kodu do zgodności z MISRA nie jest łatwym zadaniem.

Mogą obowiązywać dwie wersje dokumentu MISRA-C. Albo MISRA-C: 2004, która jest nadal aktualnym standardem branżowym. Lub nowy MISRA-C: 2012, który obsługuje standard C99. Jeśli nigdy wcześniej nie korzystałeś z MISRA-C, zaleciłbym wdrożenie tego drugiego.

Należy jednak pamiętać, że dostawcy narzędzi zwykle odnoszą się do MISRA-C: 2004, kiedy twierdzą, że mają sprawdzanie MISRA (czasami nawet odnoszą się do przestarzałej wersji MISRA-C: 1998). O ile mi wiadomo, wsparcie narzędziowe dla MISRA-C: 2012 jest nadal ograniczone. Myślę, że jak dotąd zaimplementowały go tylko niektóre analizatory statyczne: Klocwork, LDRA, PRQA i Polyspace. Może być więcej, ale zdecydowanie musisz sprawdzić, którą wersję MISRA obsługuje.

Przed podjęciem decyzji możesz oczywiście zacząć od przeczytania dokumentu MISRA i zobacz, co się z tym wiąże. Można go kupić za 10 funtów na stronie misra.org , co jest dość przystępne w porównaniu do cen norm ISO.

Lundin
źródło
1

Mathworks (ludzie MATLAB) mają narzędzie do analizy kodu statycznego o nazwie Polyspace .

Oprócz statycznej analizy kodu, kłaczków itp. Sugerowałbym staranne zdefiniowanie i zaprojektowanie interfejsów (z formalnym procesem przeglądu) oraz analizę pokrycia kodu.

Warto również zapoznać się ze wskazówkami dotyczącymi projektowania kodu krytycznego dla bezpieczeństwa, w tym MISRA, ale także normami UL1998 i IEC 61508.

Spehro Pefhany
źródło
Nie polecam zbliżać się do normy IEC 61508, chyba że musisz. Nie wspomina o oprogramowaniu, ale brakuje w nim nowoczesnych, naukowych źródeł. Ten standard pojawił się o 30 lat za późno - gdyby został wydany w latach 70., podobnie jak większość tak zwanych „źródeł”, mógłby być przydatny.
Lundin
1

Aby uzyskać pełną odpowiedź na to pytanie, odrzuciłbym myśl o „niezawodności kodu”, a zamiast tego pomyślałem o „niezawodności projektu”, ponieważ kod jest tylko ostatnim wyrazem projektu.

Zacznij więc od wymagań, napisz je i sprawdź. Jeśli nie masz dokumentu wymagań, wskaż losowy wiersz kodu i zadaj sobie pytanie „dlaczego ten wiersz jest potrzebny?” Potrzeba dowolnego wiersza kodu powinna być ostatecznie zgodna z wymaganiami, nawet jeśli jest to tak proste / oczywiste, jak „zasilacz powinien wytwarzać napięcie 5 V DC, jeśli napięcie wejściowe wynosi 12–36 V DC”. Jednym ze sposobów myślenia na ten temat jest to, że jeśli tego wiersza kodu nie można prześledzić do wymogu, to skąd wiesz, że jest to właściwy kod lub że w ogóle jest potrzebny?

Następnie sprawdź swój projekt. Jest OK, jeśli jest całkowicie w kodzie (np. W komentarzach), ale to sprawia, że ​​trudniej jest wiedzieć, czy kod robi to, co naprawdę ma na myśli. Na przykład w kodzie może znajdować się wiersz o treści output = 3 * setpoint / (4 - (current * 5)); Czy current == 4/5prawidłowe dane wejściowe mogą spowodować awarię? Co należy zrobić w tym przypadku, aby zapobiec podziałowi przez zero? Czy unikasz operacji całkowicie, czy zamiast tego degradujesz wyjście? Dzięki ogólnej notatce w dokumencie projektowym dotyczącym obsługi takich przypadków krawędzi znacznie łatwiej jest zweryfikować projekt na wyższym poziomie. Tak więc teraz kontrola kodu jest łatwiejsza, ponieważ chodzi o sprawdzenie, czy kod poprawnie implementuje ten projekt.

Oprócz tego inspekcja kodu powinna sprawdzić typowe błędy, których nie może wykryć IDE (używasz IDE, prawda?), Takie jak „=”, gdy miałeś na myśli „==”, brak nawiasów klamrowych, które zmieniają znaczenie „jeśli „oświadczenia, średniki tam, gdzie nie powinny być itp.

Kiedy to piszę, przychodzi mi do głowy, że naprawdę trudno jest podsumować lata szkolenia / doświadczenia w zakresie jakości oprogramowania w jednym poście. Piszę kod dla urządzeń medycznych, a powyższe jest niezwykle uproszczonym podsumowaniem tego, jak do tego podchodzimy.

Lyndon
źródło
Rozumiem, że część kodu w urządzeniu medycznym jest testowana prawie tak, jakby była oddzielnym urządzeniem. Czy to jest dokładne?
Scott Seidman
@ScottSeidman Bardziej prawdopodobne jest, że jest testowany na podstawie wymagań, jak wspomniano w tej odpowiedzi. Dla każdego wymagania powinieneś mieć moduł kodu, a dla każdego takiego modułu kodu powinieneś mieć test. Zasadniczo każde wymaganie ma odpowiedni test, a kod jest środkiem do spełnienia tego wymagania. Tego rodzaju śledzenie wymagań jest powszechną praktyką w systemach o znaczeniu krytycznym, na długo przed pojawieniem się hasła „TDD”.
Lundin
Miałem na myśli zwłaszcza wytyczne FDA, takie jak fda.gov/downloads/RegulatoryInformation/Guidances/ucm126955.pdf Oprogramowanie faktycznie wymaga więcej niż mogłoby się wydawać, jeśli jest częścią wyrobu medycznego, poczynając od etapu planowania i kontroli projektu.
Scott Seidman
Scott, nigdy o tym nie myślałem, ale masz rację. Nasi pracownicy ds. Zapewnienia Jakości Oprogramowania weryfikują oprogramowanie osobno od reszty systemu (w miarę możliwości) przed przekazaniem go innej grupie odpowiedzialnej za Weryfikację i Walidację Systemu.
lyndon