Code Analysis Tools의 활용

Code Analysis Tools 

현재의 소프트위어 산업에서의 가장 큰 화두 중 하나는 소프트웨어의 품질입니다. 빠르게 발전하는 소프트웨어 산업으로의 소프트웨어 다양성 확대, 소프트웨어의 기능 확장, 소프트웨어의 복잡도 증가 등의 이유로 소프트웨어 밸리데이션, 테스팅 등의 품질 관련한 이슈가 많아 지고있습니다.

소프트웨어 개발 중 소프트웨어의 품질 검사 또는 개발자의 다양한 코딩 실수 검사 등을 할 수 있는 IAR Systems의 Code Analysis 툴인 C-RUN, C-STAT을 소개하고 사용예를 이용하여 설명합니다.

 

Static vs Runtime

정적(Static) 방법의 분석과 실행/동작(Runtime) 방법의 분석 모두 코드가 가지고 있는 오류 또는 취약점을 찾아내주는 분석 방법의 종류입니다. 정적 분석은 작성되어있는 소스코드를 대상으로 코드안에 내포되어있는 잠재적인 취약점을 분석하는 방법이며 동작 분석 방법은 실제 코드를 실행 시켜 실행 중 발생하는 오류를 분석하는 방법으로 두 방법에는 차이가 있습니다.

IAR Systems 의 Code Analysis 툴 중 C-STAT은 작성된 코드를 분석하는 정적 분석도구이며, C-RUN은 실제 실행 코드를 타겟에 다운로드 후 실행 중 발생하는 오류를 분석하는 동적 분석도구에 해당합니다.

 

C-STAT Static Analysis

C-STAT은 IAR Embedded Workbenc 에 통합되어있는 추가 제품입니다. IAR Embedded Workbench 외 별도의 설치를 할 필요가 없으나  C-STAT의 기능을 사용하기 위하여  C-STAT 사용을 위한 라이센스 추가가 필요합니다. C-STAT은 정적 분석으로 작성된 코드만으로 코드 내의 잠재적 문제들을 쉽게 파악하여 개발 초기부터 코드 품질, 더 나아가 제품의 품질을 높여 줄 수 있습니다. 

C-STAT주요기능

  • C/C++ 언어의 코드 분석
  • MISRA C:2004, MISRA C++:2008 및 MISRA C:2012에 정의된 규칙 준수 확인
  • CWE 및 CERT C/C++에 따른 많은 문제에 기반한 다양한 검사항목
  • 직관적이고 사용하기 쉬운 설정
  • 개별 규칙 단계 뿐만 아니라 규칙 설정 단계의 유연한 규칙 선택
  • IAR Embedded Workbench IDE와 완벽하게 통합
  • 다양하고 상세한 오류 정보 표시
  • 빠른 분석 실행 속도

C-STAT의 정적 분석으로 사용할 수있는 기능 중 하나로 코딩룰을 MISRA-C 코딩 룰을 검사하는 기능이 있습니다. MISRA-C 코딩 룰은 MISRA(Motor Industry Software Reliability Association)에서 개발된 자동차 산업 제품의 소프트웨어 개발에 사용되는 C 프로그래밍에 대한 코딩 룰 이며 소프트웨어의 코드 안전성, 호환성, 신뢰성 향상을 목표로하고있습니다.  

C-STAT에서는 MISRA-C 의 MISRA-C:1998, MISRA-C:2004, MISRA-C++:2008, MISRA-C:2012 버전의 코딩룰 검사를 지원하고 있어 MISRA-C 코딩 룰을 준수하여 진행되는 프로젝트의 개발자가 코드 작성 후 바로 코딩 룰 검사를 실행 해 볼 수 있는 장점이 있습니다. 또한, CERT C/C++ 의 일부 코딩 룰 체크가 가능하며 CWE 리스트 기반의 개발자가 범할 수 있는 실수를 검사할 수 있는 다양한 스텐다드 검사항목을 제공합니다.

 

C-RUN Runtime Analysis

C-RUN은 C-STAT과 마찬가지로 IAR Embedded Workbenc 에 통합되어있는 추가 제품입니다. IAR Embedded Workbench 외 별도의 설치를 할 필요가 없으나 기능 사용을 위하여 라이센스를 추가해야합니다. 다만 C-RUN의 경우 추가 라이센스를 구매하지 않더라도 코드사이즈 제한(테스트 코드 12K 제한)으로 평가 가능합니다. C-RUN은 실행 분석으로 작성된 소스 코드를 실제 동작의 타겟에 다운로드하여 동작 시킨 후 발생하는 문제점에 대하여 분석합니다.

C-RUN주요기능

  • C/C++ 언어의 코드 분석
  • 직관적이고 사용하기 쉬운 설정
  • 최적화된 테스트 코드 삽입으로 코드 사이즈와 성능 저하를 최적화
  • 다양하고 상세한 런타임 오류 정보 표시
  • 콜 스택 정보를 포함한 오류 정보 표시
  • 오류 사항과 코드와의 상관관계 확인 및 에디터 창에 오류 표시
  • 유연한 필터 관리
  • 배열 또는 범위를 가지고있는 객체들의 경계범위를 벗어난 접근 검사
  • 버퍼 오버플로우 검사
  • 서로 다른 타입의 변수를 캐스팅 할 경우 발생하는 값의 변화 검사
  • 산술연산에서의 오버플로우 검사
  • 쉬프트 연산에서의 오버플로우 검사
  • 힙 메모리의 잘못된 사용과 메모리 누수 검사

일반적인 동적/실행 분석 도구들은 코드 실행 중 검사를하기에 소스 코드 중 테스트 되어야할 위치에 테스트 코드를 사용자가 직접 입력해야 합니다. 따라서 전체의 소스 코드의 크기가 커지고 테스트 코드와 같이 실행되기에 코드 실행 성능이 떨어지게됩니다. 하지만 C-RUN의 경우 테스트 코드의 입력을 컴파일러가 코드를 분석하여 최적화된 코드를 자동 삽입하기에 고드 사이즈 증가와 실행 성능 저하를 최소화 하고있습니다.

  

Code Analysis 활용하여코드품질향상 

다음의 예제 코드를 이용하여 코드 품질 향상을 위한 C-RUN과 C-STAT을 활용 방법을 설명드립니다. 우선, 다음의 예제는 strcpy(),strcat() 의 라이브러리 함수를 이용하여 “Hello World!”라는 문구를 만들고 이를 출력하는 두 방법에 대하여 작성되어있습니다. 

 

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

 

const char str1[] = "Hello ";

const char str2[] = "world! ";

 

int main()

{

  char buf1[12];

  char *buf2;

  int length;

 

  strcpy(buf1, "Hello ");

  strcat(buf1, "world!");

  printf("%s\n", buf1);

        

  length = strlen(str1) + strlen(str2);

  buf2 = (char *)malloc(sizeof(char) * length);

  

  strcpy(buf2, str1);

  strcat(buf2, str2);

  printf("%s\n", buf2);

 

  return 0;

}

 

위의 작성된 예졔의 빌드과정에 오류, 경고가 없이 정상 빌드가 진행됩니다. 이 후 C-SPY 디버거에서 코드를 실행 시키면 Teminal I/O 창 (View > Terminal I/O)에서 정상적으로 “Hello World!”문구가 2개 출력됨을 확인 할 수있습니다.

C-STAT Static Analysis_KR_201706

< 그림 1. C-STAT Static Analysis >

동일한 예제를 C-STAT으로 정적 분석을 진행하면 다음과 같은 결과가 나오게됩니다.

Project Option > C-STAT Static Analysis > Analyze Project 에서 검사항목을 설정합니다.

C-STAT Setting_KR_201706

 < 그림 2. C-STAT 설정 >

C-STAT Running_KR_201706

< 그림 3. C-STAT 실행 >

C-

< 그림 4. C-STAT 분석 결과 >

C-STAT의 정적 분석으로 C-STAT Messages 창에 결과를 표시합니다. 분석된 결과의 내용을 보면 2개의 코드상 내포되어있는 문제점을 찾아냅니다. 내용을 보면 첫번째 메시지는 스트링의 경우 마지막에 스트링의 마지막을 표시하는 Null 값을 표시해야 하지만 스트링 값이 저장되는 배열 변수의 길이가 스트링의 마지막 Null 값을 포함 할 수 없는 길이이기에 나오는 메시지 이며, 두 번째 메지시는 malloc() 함수를 이용하여 힙 메모리 시작 주소를 return을 받을 경우 malloc() 함수 처리 중 정상적으로 힙메모리 할당이 되지 않으면 Null 값을 return 하지만 이에대한 예외 처리가 없어 나오는 메시지입니다.

따라서 코드 품질의 향상을 위하여 다음과 같이 코드를 수정합니다. 

 

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

 

const char str1[] = "Hello ";

const char str2[] = "world! ";

 

int main()

{

  char buf1[13];       // 배열길이를 스트링의 마지막 Null 을 포함하도록 수정

  char *buf2;

  int length;

 

  strcpy(buf1, "Hello ");

  strcat(buf1, "world!");

  printf("%s\n", buf1);

        

  length = strlen(str1) + strlen(str2);

  buf2 = (char *)malloc(sizeof(char) * length);

 

  if(buf2 == NULL)  return 1;    // buf2에 Null 값이 return 될 경우의 예외 처리 추가

 

  strcpy(buf2, str1);

  strcat(buf2, str2);

  printf("%s\n", buf2);

 

  return 0;

}

 

 

이번엔 위의 수정된 C-RUN을 사용하여 실행 분석을 진행해 보겠습니다. Project Options > Runtime Checking 에서 C-RUN 검사항목 설정 후 코드를 빌드합니다. 이 후 C-SPY 디버거에서 코드를 실행시켜 코드 실행 분석을 진행합니다.

C-RUN Setting_KR_201706

< 그림 5. C-RUN 설정 >

C-RUN Runtime_KR_201706

< 그림 6. C-RUN 에서의 Runtime 오류 검출 >

C-RUN의 동적 분석으로 실제 실행 중 발생하는 문제점을 분석하여 C-RUN Messages 창에 결과를 출력합니다. 예제 코드를 실행 한 결과 하나의 실행 분석 메시지가 출력었습니다. 오류가 발생한 위치와 오류 내용을 자세히보면 strcat()함수를 이용 힙 메모리에 위치한 buf2에 문자열 추가하는 과정에서 마지막의 Null 까지입력하게되어 buf2의 범위를 벗어나게됩니다. 윈인은 힙 메모리할당 받은 크기가 스트링의 마지막 구분을 위한 Null을 포함하지 못하고 있어 문제가 나타납니다. 따라서 코드 품질의 향상을 위하여 다음과 같이 코드를 수정합니다. 

 

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

 

const char str1[] = "Hello ";

const char str2[] = "world! ";

 

int main()

{

  char buf1[13];       // 배열길이를 스트링의 마지막 Null 을 포함하도록 수정 (C-STAT)

  char *buf2;

  int length;

 

  strcpy(buf1, "Hello ");

  strcat(buf1, "world!");

  printf("%s\n", buf1);

        

  length = strlen(str1) + strlen(str2);

  buf2 = (char *)malloc(sizeof(char) * length + 1);  // Null을 포함하도록 힙 메모리 사이즈 추가 (C_RUN)

 

  if(buf2 == NULL)  return 1;    // buf2에 Null 값이 return 될 경우의 예외 처리 추가(C-STAT)

 

  strcpy(buf2, str1);

  strcat(buf2, str2);

  printf("%s\n", buf2);

 

  return 0;

}

 

 

 

위의 예제에서도 동작에 문제가 없어 보였으나 코드 분석을 통하여 내포되어있는 잠재적 문제를 확인 할 수 있었습니다. 이러한 내포된 문제들로 인하여 큰 문제가 개발 후반기 또는 출시 이 후 발생된다면 문제 해결 비용이 큰 부담이 될 수 있습니다.

소프트웨어 품질에 대한 중요성은 누구나 인식하고 있습니다. 제품에 내재된 문제를 개발 초기에 발견하고 문제를 해결한다면 문제 해결에 발생하는 비용을 최소화 할 수 있습니다. 초기 문제 발견이 되지 않고 추 후 개발 후반기 또는 출시 이 후 발견이 된다면 초기에 문제를 해결 할 때보다 문제 해결 비용은 기하급수적으로 늘어나게 됩니다. 따라서, C-RUN, C-STAT과 같은 코드 분석 툴들을 개발 초기에 잘 활용하여 문제를 개발 초기에 발견과 해결을 하신다면 소프트웨어의 품질 향상과 문제해결 비용 최소화에 도움이 많이 될 것입니다.

© IAR Systems 1995-2017 - All rights reserved.