C++ Analysis & Lint Tools
서론
C++을 사용하다 보면 다양한 실수와 수많은 오류를 만들게 된다.
코드를 작성하는 내 자신을 믿을 수 없기 때문에 다양한 도구들의 도움이 필수적이다.
내가 C++로 개발할 때 사용하는 도구들을 정리해 보았다.
주 개발 환경은
Linux
+Visual Studio Code
+CMake
이다.
C++ Lint Tools
프로젝트마다 코딩 컨벤션은 천차만별이지만, 한번 정해지면 이는 모두가 지켜야 하는 당연한 규칙이다.
코드 리뷰 과정에서 들여쓰기 크기가 다르거나 불필요한 공백이 있는지 확인하는 것은 비효율적인 작업이다. 따라서 코딩 컨벤션을 강제할 수 있는 린트 도구를 사용하는 것이 좋다.
Clang-Format
LLVM/Clang 프로젝트에서 개발한 Clang-Format은 C, C++, Objective-C 등의 코드를 정해진 규칙에 따라 포맷하는 린트 도구이다.
Clang-Format은 Style Option을 통해 다양한 규칙을 적용할 수 있다. Style Option은 CLI 옵션에 추가하거나 .clang-format
파일에 추가하여 사용한다.
테스트 페이지에서 Style Option을 적용하고 결과를 확인할 수 있다.
아래는 내가 자주 사용하는 .clang-format
파일의 Style Option이다.
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignTrailingComments: false
AlignOperands: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: false
AllowAllParametersOfDeclarationOnNextLine: false
BinPackArguments: true
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BraceWrapping:
AfterControlStatement: true
AfterEnum: true
AfterStruct: true
AfterFunction: true
AfterClass: true
AfterNamespace: false
AfterObjCDeclaration: false
BeforeCatch: true
BeforeElse: true
SplitEmptyFunction: true
Cpp11BracedListStyle: true
ColumnLimit: 120
FixNamespaceComments: true
IncludeBlocks: Regroup
IndentWidth: 4
PointerAlignment: Left
TabWidth: 4
UseTab: Never
Visual Studio Code에 Clang-Format을 적용하려면 먼저 확장 프로그램을 설치하고 .clang-format
파일을 추가해야 한다.
그 다음, .vscode/settings.json
파일에 아래 필드를 추가하면 소스 코드 파일을 저장할 때마다 자동으로 포맷팅된다.
{
"editor.formatOnSave": true,
}
C++ Static Analysis Tools
정적 분석 도구는 소스 코드를 분석하여 다양한 문제 및 취약점을 파악한다.
성능 문제, 동시성 문제, 메모리 누수, 사용하지 않는 코드 등 많은 광범위한 내용을 분석하기 때문에 최소한의 코드 품질을 보장할 수 있도록 도와준다.
Compiler Warning
C++은 기본적으로 컴파일러 경고를 통해 소스 코드를 검사할 수 있다.
컴파일러의 종류(GNU
, Clang
, MSVC
)와 버전마다 사용 가능한 경고 플래그에 차이가 있는데 자세한 내용은 C++ Best Practices에서 확인할 수 있다.
Clang-Tidy
LLVM/Clang 프로젝트에서 개발한 Clang-Tidy는 C, C++, Objective-C 등의 소스 코드를 분석하는 정적 분석 도구이다.
Clang-Tidy는 Check Option을 통해 다양한 검사 규칙을 적용할 수 있다. Check Option은 CLI 옵션에 추가하거나 .clang-tidy
파일에 추가하여 사용한다.
아래는 내가 자주 사용하는 .clang-tidy
파일의 Check Option이다.
prefix에 붙는
-
는 해당 Check Option을 검사에서 제외한다는 의미이고,*
은 wildcard를 의미한다.
# 먼저 모든 Check Options을 제외한 뒤, 하나씩 추가
Checks: >
-*,
cppcoreguidelines-*
bugprone-*,
google-*,
misc-*,
modernize-*,
performance-*,
portability-*,
readability-*,
clang-analyzer-*,
clang-diagnostic-*,
concurrency-*,
-bugprone-assignment-in-if-condition,
-bugprone-easily-swappable-parameters,
-cppcoreguidelines-avoid-non-const-global-variables,
-cppcoreguidelines-avoid-const-or-ref-data-members,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-special-member-functions,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-pro-type-reinterpret-cast,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-vararg,
-google-runtime-int,
-google-readability-braces-around-statements,
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
-misc-unused-parameters,
-modernize-redundant-void-arg,
-modernize-use-trailing-return-type,
-readability-convert-member-functions-to-static,
-readability-function-cognitive-complexity,
-readability-identifier-length,
-readability-isolate-declaration,
-readability-magic-numbers,
-readability-named-parameter,
-readability-simplify-boolean-expr,
-readability-uppercase-literal-suffix,
-readability-braces-around-statements
WarningsAsErrors: true
HeaderFilterRegex: ''
Visual Studio Code에 Clang-Tidy를 적용하려면 먼저 확장 프로그램을 설치하고 .clang-tidy
파일을 추가해야 한다.
그 다음, .vscode/settings.json
파일에 아래 필드를 추가하면 자동으로 정적 분석 도구를 사용할 수 있다.
{
"C_Cpp.codeAnalysis.runAutomatically": true,
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
"C_Cpp.codeAnalysis.exclude": {
"**/build": true,
},
}
SonarLint
SonarSource에서 개발한 SonarLint는 다양한 언어를 정적 분석하는 IDE 플러그인이다.
SonarLint에 적용된 C++ 규칙은 SonarLint C++ static code analysis에서 확인할 수 있다.
Visual Studio Code에 SonarLint를 적용하려면 확장 프로그램을 설치해야 한다.
그 다음, .vscode/settings.json
파일에 아래 필드를 추가하면 자동으로 정적 분석을 수행한다.
{
"sonarlint.pathToCompileCommands": "/home/yourname/repos/proj/compile_commands.json"
}
json 파일 생성 방법은 SonarLint 가이드를 참고하자.
Cppcheck
구글에서 개발한 CppCheck는 C/C++ 소스 코드를 분석하는 정적 분석 도구이다.
Visual Studio Code에 적용이 까다로워 잘 사용하지는 않지만 가끔 다음 CLI 명령어을 사용한다.
# –enable : 검색 범위를 지정하는 옵션
# –suppress : 탐지하지 말아야 하는 기능을 명시하는 옵션
# –std : 언어 버전을 지정하는 옵션
$ cppcheck --enable=warning --suppress=missingIncludeSystem --std=c++14 ${file_or_folder_name}
자세한 설명은 Netmarble 기술 블로그에 잘 나와있다.
C++ Dynamic Analysis Tools
동적 분석 도구는 런타임에 소스 코드를 분석하여 정적 분석 도구가 찾지 못한 문제를 발견할 수 있다.
Valgrind
Valgrind는 리눅스 환경에서 사용하는 동적 분석 도구이다. Valgrind는 목적에 따라 다양한 도구를 사용할 수 있다.
Memcheck
: 메모리 누수 탐지 도구Helgrind
: 스레드 오류 탐지 도구Cachegrind
: 캐시 프로파일 도구Massif
: 힙 프로파일 도구- 그 외의 도구들
이 중에서 메모리 누수를 탐지하기 위한 목적으로 자주 사용하는 CLI 명령어는 다음과 같다.
# --tool : valgrind 도구를 지정하는 옵션
# --show-error-list : 프로그램을 실행하지 않아도 탐지할 수 있는 오류 표시 유무를 지정하는 옵션
# --leak-check : 메모리 누수에 대한 세부 정보 범위를 지정하는 옵션
# --show-leak-kinds : 메모리 누수 보고 종류를 지정하는 옵션
$ valgrind --tool=memcheck --show-error-list=yes --leak-check=full --show-leak-kinds=all ${binary_name}
자세한 옵션은 Valgrind 문서에서 확인할 수 있다.
Sanitizer
Sanitizer는 구글에서 개발한 동적 분석 도구이다. Sanitizer는 목적에 따라 다양한 도구를 사용할 수 있다.
AddressSanitizer
: 메모리 오류 탐지 도구LeakSanitizer
: 메모리 누수 탐지 도구ThreadSanitizer
: 스레드 오류 탐지 도구MemorySanitizer
: 초기화 되지 않은 메모리 읽기 탐지 도구HWASAN
: 하드웨어 지원을 받는 메모리 오류 탐지 도구UBSan
: UB(Undefined Behavior) 탐지 도구
Sanitizer는 컴파일러에 옵션을 추가하여 사용한다.
CMake에 Santizier를 적용하려면 CMakeLists.txt
파일 내에 다음과 같은 설정을 추가하면 된다.
target_compile_options(${target_name} PRIVATE -fsanitize=address -O1 -fno-omit-frame-pointer)
target_link_libraries(${target_name} PRIVATE -fsanitize=address -O1 -fno-omit-frame-pointer)
자세한 옵션과 정보는 Sanitizer 위키에서 확인할 수 있다.