정적코드분석/코딩표준

MISRA-C : 안전한 C 프로그래밍의 코딩 표준

도요타 프리우스 이미지

이번 포스팅은 안전한 C프로그래밍을 위한 코딩 표준 MISRA-C 에 대한 글입니다.

프로그래밍 언어의 철학

프로그래밍 언어는 기본적으로 그 언어 자체가 추구하는 철학을 실체로 구현한 것입니다. 동적 객체지향 언어인 루비를 예로 들면 “스트레스가 없는 쉬운 프로그래밍이고, 루비는 우리의 삶을 반영해야 하며, 프로그래밍 언어는 (컴퓨터가 아닌) 인간 중심으로 설계되어야 한다” 라는 철학을 가지고 설계되었고 실제 루비의 문법은 컴퓨터 원초적인 향이 배인 C나 Java와 비교하면 광장히 인간적입니다. 그렇다면 C의 철학은 어떨까요?

C프로그래머는 곧 신이다

C의 창시자 켄 톰슨(좌)과 데니스 리치(우)
수염과 헤어스타일로 구루(Guru)의 덕력을 말해주는 C의 창시자 켄 톰슨(좌)과 데니스 리치(우)

C 프로그래밍 언어의 철학은 “High level Assembly” 혹은 “Portable Assembly” 입니다. 태생 자체가 이(異)기종간의 Unix 개발이 목적이었으니까요. 여기에 한 가지 덧붙이지면, 철학까지는 아니지만 C언어를 만든 켄 톰슨과 데이비드 리치가 프로그래밍 구루(Guru)라 그런지 “프로그래머는 C언어와 해당 기기에 대해서 모든 것을 알고있다” 라는 기본적인 전제를 깔고 있습니다. 이런 전제를 단적으로 보여주는 예가 최초의 인터넷 웜으로 불린 ‘모리스 웜’ 사건입니다. 모리스 웜을 퍼트린 로버트 모리스는 C언어 표준 라이브러리의 strcpy, scanf, gets 의 취약성을 이용하여 그 당시 금액으로 1천만~1억 달러나 되는 큰 피해를 입혔습니다. 한동안 해당 함수를 라이브러리에서 제외시켜야한다는 말이 많았지만, 아직도 이 함수들은 C의 표준 라이브러리에 남아있습니다. 그렇습니다. 이 함수 자체가 나쁜 것이 아니죠. 다만, 프로그래머가 이 함수를 제대로 쓰지 않아서 문제가 되었을 뿐입니다.

근본이 위험한 언어 – C 언어

리치와 톰슨이 C언어를 만들때만 해도 전 세계적으로 선풍적인 인기를 끌며 수 많은 프로그램과 기기에 쓰이리라곤 그 자신들도 상상하지 못했을 것입니다. C는 언어의 이식성과 유연성 덕분에 각종 산업에서 폭넓게 사용되면서 C는 프로그래밍 구루들의 전유물에서 수 많은 일반 프로그래머의 도구가 되었습니다. 그런데 모든 C 프로그래머들이 데니스 리치와 켄 톰슨의 의도처럼 C에 대해서 완벽하게 이해하고 C로 만든 프로그램이 동작하는 HW에 대해서 완벽하게 이해하고 있을까요? 저는 아니라고 봅니다.

C프로그래머 중 Integral Promotion 개념에 대해 이해하는 사람이 얼마나 많을까요? Padding 개념은 알고 계신가요?? Underlying Type이나 컴파일러 다르게 정의하는 Implement-define behavior에 대해서 숙지하고 계신 분이 있으신가요?? atoi, strcpy, gets, scanf 등의 표준 라이브러리가 얼마나 위험한지 알시나요? 개발하고 있는 기기가 Big-endian 인가 Little-endian 인가 알고 오동작을 방지하기 위해 프로그래밍 하고있습니까? Floating Point 연산이 시스템마다 구현이 다른다는 사실은 알고 프로그래밍 하시는지요? 모르는 프로그래머들이 많을 것입니다.

코드 1000줄당 버그의 숫자
코드 1000줄당 버그의 숫자

C언어는 예리한 칼과 같아서 잘 쓰면 훌륭한 과도나 식칼이 될 수 있지만 잘못쓰면 곧바로 사람잡는 흉기로 돌변하는 위험한 언어입니다. 이러한 현실은 C 언어의 위험성에 대한 조사 결과가 충실히 반영하고 있습니다. 컨설턴트인 Jack Ganssle은 C 로 작성된 프로그램의 경우 코드 1,000 줄마다 최대 500개의 에러를 생성할 수 있으며, 평균 167개의 에러 혹은 자동 생성 되는 코드의 경우 12.5개의 버그가 발생할 수 있다고 합니다. (출처 : http://www.eetkorea.com/ART_8800418233_839585_NT_80021f66.HTM)

C언어가 위험한 이유는 하나 더 있습니다. 기존 글 JSF Air Vehicle C++ Coding Standards 에서도 언급한 내용인데, 바로 ‘Undefined Behavior‘ 개념입니다. C언어(C++도 마찬가지) 자체가 언어 문법을 확실하게 정하지 않고 많은 부분을 컴파일러 개발사가 알아서 구현하도록 만들었기 때문에 각 플랫폼별로 그 결과가 다를 수 있습니다. 혹자는 C는 이식성이 좋아서 표준 C로만 작성하면 어느 플랫폼이든지 다 동작한다고 말합니다. 반은 맞고 반은 틀립니다. 동작할 수는 있지만 제대로 동작하지 않을 수 있습니다.

폭탄의 확산 : PC에서 당신의 자동차 안으로

이제 소프트웨어는 PC나 핸드폰에서 벗어나 자동차 분야에서도 그 비중과 중요성은 나날이 높아지고 있습니다. 1975년 미국에서 모든 자동차에 임베디드 컨트롤 시스템을 장착하기 시작한 이후로, 자동차의 임베디드SW는 계속 성장해서 2010년엔 자동차 부품의 72%가 임베디드SW일 것으로 전망됩니다. 또한 독일자동차협회에서 2004년에 발표한 보고서에 따르면 자동차의 고장원인 중 36%가 소프트웨어로 인해 발생한다고 합니다.(출처 : http://www.ittoday.co.kr/news/articleView.html?idxno=4741)

도요타 프리우스 이미지
위 자동차의 이미지는 본문의 내용과 전혀 상관없음. 있을수도 있고

그렇습니다. 버그 폭탄은 이제 PC에서 벗어나 여러분이 매일 타는 자동차까지 들어왔습니다. 과거 아날로그 위주로 운전에 필요한 부품들이 운전석을 메우고 있던 것과는 달리 요즘 출시되는 자동차는 운전자의 편의를 위해 각종 소프트웨어로 중무장하고 있죠. C언어로 개발한 프로그램이 PC에서 돌거나 고작 MP3 플레이어에서 작동한다면 대수롭지 않을 것입니다. 그저 종료시키거나, 리셋하거나, 다시 실행하면 됩니다. 하지만 (자동차 소프트웨어가 C언어로 개발되었다는 가정하에) 에러 발생 즉시 천국의 문턱을 밟을 수 있을 자동차의 경우는 이야기가 다릅니다. 실제로 미국에서 발생한 도요타 자동차 급가속 사고의 주요 원인으로 소프트웨어 결함이 의심받고 있습니다.

문제를 미연에 막자 : MISRA-C 의 탄생

이에 안전에 민감한 영역인 자동차, 우주항공, 철도, 국방 부분에서 사용하는 소프트웨어의 결함을 줄이고자 영국 자동차 산업 신뢰형 협회(MISRA : Motor Industry Software Reliability Association)에서 C 프로그래밍 언어에 대해서 코딩 가이드라인을 발표했습니다. 이를 MISRA-C 라고 합니다. 이 코딩 가이드라인의 목적은 명확합니다. 임베디드 장비에서 안전하고, 이식성이 좋고, 신뢰성있는 코드를 만들기 위해서 입니다.

MISRA-C 표준의 초판은 “Guidelines for the use of the C language in vehicle based software” 라는 이름으로 1998년도에 발표되었습니다. 이를 보통 MISRA-C:1998 이라 부릅니다. MISRA-C:1998 버전은 이름에서도 알 수 있듯이 자동차 소프트웨어의 안전성을 위해서 만들어졌으나 2004년에 나온 MISRA-C의 개정판에서는 자동차를 넘어서 안전에 민감한 시스템(Critical System) 모두에 사용할 수 있도록 만들어졌습니다. 그래서 표제도 “Guidelines for the use of the C language in critical systems”입니다. 이를 보통 MISRA-C:2004 라고 부릅니다. 2013년 3월에는 MISRA-C:2012가 나왔죠. 표제는 MISRA-C:2004와 같지만 C99의 문법을 지원하고 사용자의 피드백을 받아서 규칙 자체도 발전하고 설명도 많이 붙었습니다.

MISRA-C는 높은 소프트웨어 신뢰성이 필요한 자동차, 항공, 우주, 원전 산업 등에서 많이 사용되고 있습니다. MISRA-C:2012가 최신 버전이지만 2013년 초에 발표되었기 때문에 현재 산업계에서는 MISRA-C:2004가 제일 널리 사용되고 있습니다. 또한 JSF Air Vehicle C++ Coding Standards, GJB(Chineses Military Standards), HIS(Herstellerinitiative Software) 등 많은 코딩 표준이 MISRA-C의 규칙을 차용하고 있습니다.

MISRA-C 살펴보기

MISRA-C 는 반드시 지켜야 하거나(Required) 지키면 좋은(Advisory) 코딩 규칙(Rule)으로 이루어져 있습니다. MISRA-C:1998은 총 127개 코딩 규칙(93 Required, 34 Advisory)이 있으며 MISRA-C:2004는 총 141개 코딩 규칙(121 Required, 20 advisory)으로 이루어져 있습니다. MISRA-C는 유료로 판매되기 때문에 샘플을 올리기는 그렇고…. 대신 웹에서 떠돌아 다니는 MISRA-C:1998 샘플 중 MISRA-C:2004 에서 사용된 것과 유사한 규칙을 하나 소개하겠습니다.

Rule 33 (required): The right hand side of a “&&” or “||” operator shall not contain side effects. There is nothing in the C language that prevents you from writing code that looks like the following:

if ((x == y) || (*p++ == z))
{
/* do something */
}

논리적 AND 연산(&&)이나 논리적 OR연산(||) 의 우항 피연산자는 Side Effect를 가져서는 안된다는 내용이지요. 이 경우 컴파일러마다 실행 순서가 달라져서 개발자가 의도하지 않은 결과가 나올 수 있습니다.

내용이 궁금하신 분은 Preview 문서를 보시길 바랍니다. 정식 문서는 MISRA 홈페이지에서 PDF 파일로 구매하실 수 있습니다. 가격도 싸니까 꼭 사서 보시기 바랍니다. 가격도 10~15파운드 (원화로 약 1.7 ~ 2.5만원)밖에 안하고, 주문하면 PDF 문서 내부에 주문자의 이름이 박힌 한정판 스페셜 에디션 PDF를 받으실 수 있습니다. 유출되면 망신..

MISRA-C 를 지원하는 정적 코드 분석 도구

시중에 판매되는 몇몇 정적 분석 도구에서 MISRA-C 규칙을 체크할 수 있습니다. 코드를 손으로 훑어가며 하는건 거의 불가능에 가깝거나 ROI 가 안나오는 일이기 때문에 해당 도구를 사용하는 것을 추천드립니다. 대표적인 도구는 LDRA , PRQA, Parasoft 에서 판매하는 제품이 있습니다.

Leave a Reply

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *