Proven by Intelligence
보이지 않는 안전을 인텔리전스로 증명하다.
기술 인사이트를 만나보세요.
임베디드 시스템이나 시스템 소프트웨어 개발 분야에서는 오랫동안 C와 C++가 핵심 언어로 사용되어 왔습니다.
두 언어는 하드웨어에 가까운 수준에서 동작하며 높은 성능과 제어 능력을 제공하기 때문에 임베디드 환경에서 널리 활용되고 있습니다.
하지만 C/C++에서는 메모리를 개발자가 직접 관리해야 하기 때문에 메모리 누수, 댕글링 포인터, 버퍼 오버플로우와 같은 문제가 발생하기 쉽습니다. 실제로 많은 시스템 취약점이 이러한 메모리 안전성 문제에서 비롯되는 경우가 많습니다.
이러한 문제를 해결하기 위한 대안으로 등장한 언어가 바로 Rust입니다.
Rust는 언어적 특징을 통해 메모리 안전성과 성능을 동시에 확보할 수 있도록 설계된 언어입니다. 이러한 특성 덕분에 C와 C++에서 자주 발생하는 메모리 관련 오류를 컴파일 단계에서 사전에 방지할 수 있습니다.
이번 글에서는 C/C++ 대비 Rust가 가지는 주요 강점에 대해 살펴보고, CodeSonar에서 지원하는 Rust의 대표적인 결함에 대해 살펴보겠습니다.
Rust의 주요 특징
01. 소유권(Ownership)을 통한 메모리 안전성
Rust는 각 데이터의 소유자를 명확히 하고, 소유권이 이전되거나 범위를 벗어나면 자동으로 메모리를 해제합니다. 덕분에 메모리 누수나 댕글링 포인터 같은 오류를 컴파일 단계에서 방지할 수 있습니다.
02. 대여(Borrowing)를 활용한 동시성 안전성
Rust는 데이터에 대한 불변 참조(읽기 전용)와 가변 참조(수정 가능)를 엄격히 구분합니다. 동시에 여러 스레드에서 데이터를 수정하는 상황을 컴파일 단계에서 제한하여, 데이터 경쟁(Race Condition)을 원천적으로 막을 수 있습니다.
03. 제로 비용 추상화 (Zero-cost Abstractions)를 통한 고성능 추상화
제로 비용 추상화란 고수준 추상화 기능을 사용하더라도 실행 성능은 직접 작성한 저수준 코드와 거의 동일하게 유지되는 구조를 의미합니다. Rust에서는 iterator, generics 같은 고수준 추상화 기능을 통해 코드 가독성은 물론 성능은 저하 없이 효율적으로 실행할 수 있다는 장점이 있습니다.
04. Null 안전성
Rust에는 null 포인터가 존재하지 않으며, 값이 없을 수 있는 경우에는 Option<T>를 사용합니다. 컴파일러가 반드시 처리하도록 강제하므로 Null Pointer Dereference를 방지할 수 있습니다.
그러나 Rust가 제공하는 안전 장치가 있음에도 불구하고 코드 내 취약점 발생 가능성을 완전히 배제할 수 없습니다.
예를 들어, 로직 오류, 코딩 표준 위반, 비효율적인 패턴, 잠재적인 오류 등은 여전히 발생할 수 있으며, 이러한 결함은 코드 수준에서의 추가적인 검증을 통해 발견하는 것이 중요합니다.
"
이러한 이유로 Rust 코드에서도 정적 분석을 통한 코드 검증 과정이 필요합니다.
CodeSonar는 Rust 코드 품질 검증을 위해 검출 가능한 다양한 결함들을 지원하고 있습니다.
"
예를 들어 다음과 같은 케이스에 대해 결함을 식별할 수 있습니다.
CodeSonar에서 지원하고 있는 Rust 결함
01. 버퍼 사이즈 관련 결함
버퍼 사이즈 관련 결함은 배열이나 슬라이스의 유효 범위를 초과하여 접근할 때 발생합니다.
이러한 경우 Rust에서는 런타임 시 panic이 발생하며, 프로그램이 비정상적으로 종료될 수 있습니다.
CodeSonar는 아래와 같이 배열의 마지막 인덱스(길이가 5일 때 최대 인덱스는 4)를 벗어난 접근으로 판단하여 아래와 같이 결함을 검출합니다.

<Out of Bounds Indexing 결함>
이 외에도 버퍼 관련된 결함으로 Iter Out of Bounds, Large Stack Arrays, Large Stack Frames 등을 지원합니다.
02. 민감정보 노출 관련 결함
민감정보 노출 관련 결함은 로그 출력, 디버깅 코드, 또는 외부 인터페이스를 통해 비밀번호, 토큰, 개인 정보와 같은 중요한 데이터가 의도치 않게 노출될 때 발생합니다.
이러한 정보는 외부에 노출될 경우 보안 위협으로 이어질 수 있으며, 인증 우회, 권한 탈취 등의 심각한 문제를 유발할 수 있습니다.
아래 예제와 같이 디버깅 매크로를 사용해 데이터를 출력할 경우, 민감한 정보가 외부로 노출될 수 있습니다.
CodeSonar는 이러한 위험 패턴을 식별하여 관련 결함을 검출합니다.

<Dbg Macro 결함>
이 외에도 Print Stdout, Print Stderr 등의 관련 결함들을 지원합니다.
03. Recursion 관련 결함
Recursion 관련 결함은 함수가 자기 자신을 반복적으로 호출하는 과정에서, 종료 조건이 올바르게 설정되지 않거나 누락될 경우 발생합니다.
이로 인해 함수 호출 스택이 계속해서 누적되며, 결국 스택 메모리를 초과하여 프로그램이 비정상적으로 종료될 수 있습니다.
아래와 같이 검출된 Unconditional Recursion 결함은 종료 조건이 없는 상태에서 함수가 자기 자신을 지속적으로 호출하면서 정상적인 반환 경로 없이 실행이 계속되는 경우 탐지됩니다.

<Unconditional Recursion 결함>
이 외에도 Recursion과 관련해서 Main Recursion, Recursive Format Impl 등의 결함들을 지원합니다.
04. Dead Code 관련 결함
Dead Code 관련 결함은 특정 조건문의 결과나 함수 호출 시, 해당 함수가 정상적으로 종료되지 않거나 조건이 항상 동일한 결과를 반환함에 따라 하위 구문이 실행되지 않는 경우 발생합니다.
이로 인해 일부 코드 구문이 실제로는 수행되지 않는 문제가 발생합니다.
예제 코드의 경우 전체 조건식의 결과가 항상 false로 평가되어 해당 조건문이 의미를 가지지 않으며, true일 때 실행되는 구문 역시 도달할 수 없는 코드로 판단하여 아래와 같은 결함이 검출됩니다.

<Impossible Comparisons 결함>
이 외에도 Dead Code 결함과 관련해서 Absurd Extreme Comparisons, If Same Then Else, Ifs Same Cond, Never Loop 등을 지원합니다.
05. 형 변환 관련 결함
형 변환 관련 결함은 특정 변수의 타입을 묵시적 또는 명시적으로 변환하는 과정에서 발생합니다.
이 과정에서 데이터의 값 손실이 발생할 수 있으며, 이는 예상치 못한 결과를 초래할 수 있습니다.
아래 예제 코드를 보면 x는 부호가 있는 int 타입으로 선언되어 있으나, 부호가 없는 unsigned int 타입으로 선언된 y에 x의 값을 할당하면서 형 변환이 발생한 케이스입니다.

<Cast Sign Loss 결함>
이 외에도 형 변환 관련 결함들은 Cast Possible Truncation, Unnecessary Cast, Cast Precision Loss, Cast Nan to Int등으로 구성되어 있습니다.
결론
Rust는 메모리 안전성과 성능을 동시에 제공하는 프로그래밍 언어로, 임베디드 및 시스템 소프트웨어 개발 환경에서 점차 주목받고 있습니다.
하지만 언어의 특성만으로 모든 결함을 방지할 수는 없으며, 코드 수준의 검증 과정은 여전히 필수적입니다.
따라서 Rust의 안전성에 정적 분석 도구인 CodeSonar를 결합함으로써, 소스 코드 내 취약점을 사전에 식별하고 보다 높은 수준의 안전성과 신뢰성을 확보할 수 있습니다.
이번 포스팅 관련하여 궁금하신 사항 있으시다면! 아래 이메일 주소로 언제든지 연락 주시기 바랍니다. :)
출처 :
https://rust-lang.github.io/rust-clippy/stable/index.html#redundant_field_names
https://www.elancer.co.kr/blog/detail/808
📧 codesonar@mdsit.co.kr ✍️ 문의남기기
