스택 오버플로우가 발생하는 이유는 '프로세스 스택의 범위를 벗어나 스택을 사용'하기 때문입니다. 스택 오버플로우를 유발하는 직접적인 원인은 다음과 같이 분류할 수 있습니다.
너무 많은 함수를 호출
조건없이 재귀함수를 호출
큰 사이즈의 배열을 지역 변수로 잡음
첫 번째로, 너무 많은 함수가 호출되면 스택 오버플로우가 일어날 수 있습니다. 함수를 호출하면 함수를 호출하기 직전의 스택 주소와 링크 레지스터의 값을 스택에 푸시하는데, 이 과정에서 프로세스의 스택을 사용합니다. 그런데 함수를 더 많이 호출할수록 이예 비례해 프로세스의 스택을 사용하는데, 너무 많은 함수가 호출되면 스택 오버플로우가 유발될 수 있습니다.
두 번째로, 스택 오버플로우가 일어나는 가장 흔한 패턴은 종료 조건 없이 재귀함수(Recursive Function)을 호출하면 스택 오버플로우가 유발될 수 있습니다. 재귀 함수를 호출하면서 자연히 프로세스의 스택을 사용하는데, 재귀 함수가 종료되는 조건없이 호출되면 프로세스의 스택을 무한대로 사용하게 됩니다. 그 결과 100% 스택 오버플로우가 유발됩니다.
세 번째로, 큰 사이즈의 배열이나 구조체를 지역 변수로 선언해 사용하면 프로세스의 스택을 사용합니다. 지역 변수로 배열을 1024와 같이 크게 잡거나 1024바이트가 넘는 사이즈로 구조체를 지역 변수로 선언하게 되면 스택 오버플로우를 유발할 수 있습니다.
정리하면, 보통 함수를 호출하거나 함수 내에 지역 변수를 선언하면 프로세스의 스택을 사용하는데, 위와 같은 3가지 조건에서 프로세스에게 지정된 스택 범위를 넘어서는 스택 오버플로우를 유발하게 됩니다.
그런데 위에서 스택 오버플로우를 유발하는 요인에 대해 언급했는데, '너무 많은', '큰 사이즈'와 같은 정성적인 표현을 읽으면 그 기준이 무엇인지 구체적으로 떠오르지 않습니다.
그 기준이 무엇인지 이해하려면 다음과 같은 사실을 알아야 합니다.
프로세스에게 고정된 사이즈의 스택 공간이 할당된다.
운영체제나 RTOS마다 프로세스에게 할당하는 스택 사이즈가 다르다.
위와 같은 내용을 읽으면 여러분이 개발하는 시스템에서 프로세스에게 얼마나 많은 스택이 할당되는지 알아야 한다는 결론을 내릴 수 있습니다. 스택 사이즈를 알아야 '너무 많은', '큰 사이즈'의 기준을 설정할 수 있습니다.
코드를 리뷰할 때, 함수를 호출할 때 프로세스의 스택을 얼마나 사용하는지 검토하면, 스택 오버플로우를 방지할 수 있습니다.
[중요]
C 프로그래밍으로 어떤 코드를 입력하면 해당 코드를 실행하는 주인공은 프로세스 혹은 태스크입니다. 운영체제나 RTOS (Real-Time Operating System)마다 구현 방식에 약간 차이는 있지만 프로세스들은 자신만의 스택 공간을 갖게 됩니다. 프로세스는 생성될 때 자신만의 스택 공간을 커널로부터 할당받는데, 여기서 중요하게 기억해야 할 사실은 "프로세스의 스택 공간은 일정하다"라는 점입니다.
그런데 메모리를 할당 받고 싶을 때 동적 메모리 할당을 요청하듯이, 함수를 호출할 때 사용되는 프로세스의 스택 공간을 동적으로 할당 받을 수 없습니다. 잠실 야구장에서 야외 펜스의 길이가 125m로 정해져 있듯이, 프로세스의 스택 공간도 정해져 있습니다.
프로세스가 생성되면 운영체제는 프로세스에게 일정 크기의 스택 공간을 할당합니다. 예를 들어 32비트 기반의 리눅스 커널은 프로세스의 스택 사이즈는 0x2000, 64비트 기반에서는 0x4000입니다.
'시스템 소프트웨어 개발을 위한 Arm 아키텍처의 구조와 원리 > 11장: AAPCS(함수 호출 규약)' 카테고리의 다른 글
[Arm][AAPCS] 스택 오버플로우란 (0) | 2025.01.09 |
---|---|
[Arm][AAPCS] 프로세스의 스택 사이즈를 점검하는게 중요 (0) | 2025.01.09 |
[Arm][AAPCS] 스택 오염 문제는 어떻게 디버깅할까 (0) | 2025.01.08 |
[Arm][AAPCS] 스택 오염이 발생한 후에는 시스템은 어떻게 동작할까 (0) | 2025.01.07 |
[Arm][AAPCS] 스택 오염(Stack Corruption)이란 (0) | 2025.01.06 |