동일한 비즈니스 코드의 경우, CentOS 7 환경에서 컴파일 및 실행은 정상적으로 이루어졌지만, CentOS 8로 전환하고 최신 버전의 GCC를 사용하여 컴파일했을 때 프로그램이 충돌했습니다. 주목할 점은 문제가 Release 模式에서만 발생하며, Debug 模式에서는 전혀 문제가 없다는 것입니다. 이와 같은 상황은 처음 경험했으며, 사흘간의 조사 끝에 문제의 근본 원인을 찾았습니다.
문제 파악
일련의 점검 결과, 문제의 근본 원인은 函数缺少返回值에 있습니다. Release 모드에서 GCC 최신 버전은 더 많은 최적화를 수행하며, 이로 인해 명시적인 반환 값이 없는 함수의 실행 과정에서 예상치 못한 로직이 발생하여 충돌을 일으킵니다. 결론으로는, 编译器的警告不容忽视,尤其是在老项目中,部分警告可能被无视,但也应当避免屏蔽所有警告입니다.
환경 설명
-
CentOS 7 GCC版本:
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) Copyright © 2015 Free Software Foundation, Inc.
-
CentOS 8 GCC版本:
gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-21) Copyright (C) 2018 Free Software Foundation, Inc.
붕괴 현상
프로그램 충돌 스택을 분석하는 과정에서 다음과 같은 스택 정보를 확인했습니다:
[New LWP 1385902]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pstack_main`.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007ffe894b4420 in ?? ()
(gdb) bt
#0 0x00007ffe894b4420 in ?? ()
#1 0x00000000004008e9 in main ()
이 스택은 직관적이지 않아 보이며, 충돌 함수의 스택 정보가 ??
으로 표시되어 문제 해결을 더욱 어렵게 만들고 있습니다
코드 예시
문제 이해를 돕기 위해, 재현을 위한 최소 코드 예제는 다음과 같습니다:
#include <iostream>
#include <map>
int test() {
std::cout << "1" << std::endl;
}
int main() {
test();
return 0;
}
해당 코드에서 __INLINE_CODE_0__ 函数显然没有显式返回一个值,而它的返回类型是 __INLINE_CODE_1__BOLD_4
int`` 유형의 경우, 반드시 반환 값이 있어야 하며, 그렇지 않으면 정의되지 않은 동작이 발생할 수 있습니다
컴파일 경고
프로젝트에서 CMake 스크립트가 여러 컴파일 경고를 숨겼는데, 그중에는 다음과 같은 경고 메시지도 포함되어 있습니다:
/root/pstack/main.cpp: In function ‘int test()’:
/root/pstack/main.cpp:7:1: warning: no return statement in function returning non-void [-Wreturn-type]
이 경고는 test()
함수가 반환값을 가지지 않는다는 것을 나타내며, 이것이 문제의 근원입니다. GCC의 높은 버전(예: 8.5.0)은 코드를 최적화할 때 이러한 정의되지 않은 동작에 대해 불안정한 최적화를 수행하여 프로그램 충돌을 일으킬 수 있습니다.
어셈블리 코드 차이
GCC 컴파일러 최적화 동작의 차이를 설명하기 위해, 다양한 버전의 GCC가 생성한 어셈블리 코드를 비교했습니다
- GCC 4.8.5 生成的汇编代码:
어셈블리 코드는 다소 장황하며, 표준 출력 스트림(예: std::cout
)的处理逻辑。这表明编译器进行了更保守的优化,未对 INLINE_CODE_1 함수에서 누락된 반환값 문제)에 대한 과도한 최적화를 포함하고 있어, 이로 인해 런타임 오류를 피했을 가능성이 있습니다
- GCC 8.5.0 生成的汇编代码:
새 버전의 GCC는 더 많은 최적화를 수행하여 코드 양을 줄였습니다. 하지만 이러한 최적화로 인해 반환 값이 없는 함수의 실행 동작이 정의되지 않아 프로그램이 충돌할 수 있습니다.
결론
이번 문제 해결 과정을 통해 C++에서 函数返回值必须明确, 특히 함수 선언이 int
BOLD_2__일 때, 모든 경고를 숨기지 않고, 특히 반환 값, 타입 매칭 등 흔히 발생하는 문제에 대해 선택적으로 처리해야 한다는 것을 깊이 인식하게 되었습니다
마침내 INLINE_CODE_0 함수에 반환값을 추가하여 문제를 해결하고 프로그램이 정상적으로 작동하게 되었습니다