c/c++ 프로그램에서 가능한/잠재적인 스택 오버플로 문제를 감지하는 방법은 무엇입니까?
앱에 스택 공간이 얼마나 있는지, 실행 중 스택 사용량의 최고 워터마크가 얼마인지를 확인할 수 있는 표준 방법이 있습니까?
또한 실제 오버플로의 무서운 경우에는 어떻게 됩니까?
충돌, 예외 또는 신호를 트리거합니까?모든 시스템과 컴파일러에 표준이 있습니까?
특히 Windows, Linux 및 Macintosh를 찾고 있습니다.
Windows에서는 스택 오버플로 예외가 생성됩니다.
이를 보여주는 윈도우 코드는 다음과 같습니다.
#include <stdio.h>
#include <windows.h>
void StackOverFlow()
{
CONTEXT context;
// we are interested control registers
context.ContextFlags = CONTEXT_CONTROL;
// get the details
GetThreadContext(GetCurrentThread(), &context);
// print the stack pointer
printf("Esp: %X\n", context.Esp);
// this will eventually overflow the stack
StackOverFlow();
}
DWORD ExceptionFilter(EXCEPTION_POINTERS *pointers, DWORD dwException)
{
return EXCEPTION_EXECUTE_HANDLER;
}
void main()
{
CONTEXT context;
// we are interested control registers
context.ContextFlags = CONTEXT_CONTROL;
// get the details
GetThreadContext(GetCurrentThread(), &context);
// print the stack pointer
printf("Esp: %X\n", context.Esp);
__try
{
// cause a stack overflow
StackOverFlow();
}
__except(ExceptionFilter(GetExceptionInformation(), GetExceptionCode()))
{
printf("\n****** ExceptionFilter fired ******\n");
}
}
이 exe를 실행하면 다음과 같은 출력이 생성됩니다.
Esp: 12FC4C
Esp: 12F96C
Esp: 12F68C
.....
Esp: 33D8C
Esp: 33AAC
Esp: 337CC
****** ExceptionFilter fired ******
Linux에서 코드가 스택을 통과하여 쓰기를 시도하면 분할 오류가 발생합니다.
스택 크기는 프로세스 간에 상속되는 속성입니다.에서 다과같명령을사용은하여셸에경수와 같은 할 수 있는 ulimit -s
단위:)()sh
,ksh
,zsh
) 또는limit stacksize
(tcsh
,zsh
).
프로그램에서 스택의 크기는 다음을 사용하여 읽을 수 있습니다.
#include <sys/resource.h>
#include <stdio.h>
int main() {
struct rlimit l;
getrlimit(RLIMIT_STACK, &l);
printf("stack_size = %ld\n", l.rlim_cur);
return 0;
}
저는 사용 가능한 스택의 크기를 구하는 표준 방법을 모릅니다.
은 스은다로시니로 합니다.argc
에 다에의내있습다니이용의 .argv
그리고 환경의 복사본, 그리고 당신의 변수.그러나 커널은 스택의 시작 위치를 랜덤화할 수 있고 위에 더미 값이 있을 수 있기 때문입니다.argc
당신이 가지고 있다고 가정하는 것은 잘못된 것입니다.l.rlim_cur
아래에서 사용 가능한 바이트&argc
.
하는 한 입니다./proc/1234/maps
서)1234
는 프로그램의 프로세스 ID입니다.이러한 경계를 알고 나면 최신 로컬 변수의 주소를 확인하여 스택 사용량을 계산할 수 있습니다.
gcc는 반환 주소와 일반 변수 사이에 추가 메모리 블록을 "void" 함수 호출에 배치합니다(이 예에서 함수는 void test() {chara[10]; b[20]:
call stack:
-----------
return address
dummy
char b[10]
char a[20]
함수가 포인터 'a'에 36바이트를 쓰면 오버플로가 반환 주소를 '손상'합니다(보안 위반 가능성 있음).그러나 포인터와 반환 주소 사이에 있는 '더미'의 값도 변경하여 프로그램이 충돌하고 경고가 표시됩니다(-fno-stack-protector를 사용하여 이를 비활성화할 수 있음).
Linux에서 Gnu libsigsegv 라이브러리는 다음 기능을 포함합니다.stackoverflow_install_handler
스택 오버플로를 탐지하고 경우에 따라 복구할 수 있습니다.
창에서 스택(특정 스레드의 경우)은 생성 전에 이 스레드에 대해 지정된 스택 크기에 도달할 때까지 주문형으로 증가합니다.
온디맨드 확장은 처음에는 스택의 일부만 사용할 수 있다는 점에서 가드 페이지를 사용하여 구현됩니다. 그 다음에 가드 페이지가 표시되면 예외가 트리거됩니다. 이 예외는 특별하며 시스템에서 처리됩니다. 처리를 수행하면 사용 가능한 스택 공간이 증가합니다(제한에 도달한 경우에도 확인됩니다!).)가 표시되고 읽기 작업이 다시 시도됩니다.
제한에 도달하면 스택 오버플로 예외가 발생하는 증가가 더 이상 없습니다.는 스레드 블록에 되며, 이은 현재스베저환블스다장니됩록경에레드라는 로 되어 ._NT_TIB
(신호 정보 블록).디버거를 사용할 수 있는 경우 다음과 같이 표시됩니다.
0:000> dt ntdll!_teb @$teb nttib.
+0x000 NtTib :
+0x000 ExceptionList : 0x0012e030 _EXCEPTION_REGISTRATION_RECORD
+0x004 StackBase : 0x00130000
+0x008 StackLimit : 0x0011e000
+0x00c SubSystemTib : (null)
+0x010 FiberData : 0x00001e00
+0x010 Version : 0x1e00
+0x014 ArbitraryUserPointer : (null)
+0x018 Self : 0x7ffdf000 _NT_TIB
StackLimit 특성은 필요에 따라 업데이트됩니다.이 메모리 블록의 특성을 확인하면 다음과 유사한 내용이 표시됩니다.
0:000> !address 0x0011e000
00030000 : 0011e000 - 00012000
Type 00020000 MEM_PRIVATE
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageStack
Pid.Tid abc.560
그리고 그 옆에 있는 페이지를 확인하면 가드 속성이 나타납니다.
0:000> !address 0x0011e000-1000
00030000 : 0011d000 - 00001000
Type 00020000 MEM_PRIVATE
Protect 00000104 PAGE_READWRITE | PAGE_GUARD
State 00001000 MEM_COMMIT
Usage RegionUsageStack
Pid.Tid abc.560
도움이 되길 바랍니다.
예외 처리기는 최소한의 스택을 처리해야 하므로(일반적으로 단일 페이지만 이 용도로 예약됨) 스택 오버플로는 처리하기에 가장 유해한 예외 유형일 수 있습니다.
이러한 유형의 예외 처리 문제에 대한 흥미로운 토론은 Chris Brumme의 블로그 게시물 1과 2를 참조하십시오. 이 블로그 게시물은 .NET 관점에서 문제, 특히 CLR 호스팅에 초점을 맞춥니다.
일부 컴파일러는 스택의 남은 여유 공간을 반환하는 stackavail() 함수를 지원합니다.프로그램에서 스택 공간이 많이 필요한 함수를 호출하기 전에 이 기능을 사용하여 호출해도 안전한지 확인할 수 있습니다.
Linux를 사용하는 경우 대체 신호 스택을 사용하는 것이 좋습니다.
- 이 경우 모든 신호는 대체 스택을 통해 처리됩니다.
- 스택 오버플로가 발생하면 시스템에서 SEGV 신호를 생성하며, 이 신호는 대체 스택을 통해 처리할 수 있습니다.
- 사용하지 않을 경우...그러면 신호를 처리할 수 없을 수 있으며 프로그램이 처리/오류 없이 충돌할 수 있습니다.
Visual Studio에서 editbin을 사용하여 스택 크기를 변경할 수 있습니다.이 정보는 msdn.microsoft.com/en-us/library/35yc2tc3.aspx 에서 찾을 수 있습니다.
언급URL : https://stackoverflow.com/questions/199747/how-to-detect-possible-potential-stack-overflow-problems-in-a-c-c-program
'programing' 카테고리의 다른 글
오류 TS1243: 'async' 수정자를 'abstract' 수정자와 함께 사용할 수 없습니다. (0) | 2023.06.11 |
---|---|
문자열의 첫 글자를 루비로 대문자화하는 방법 (0) | 2023.06.11 |
npm에서 Firebase를 사용하여 배포하는 중 오류 발생 -- 접두사 $RESOURCE_DIR 런 린트 (0) | 2023.06.11 |
빈 셀이 포함된 Excel 스프레드시트를 읽기 위해 NPOI를 사용하는 방법은 무엇입니까? (0) | 2023.06.11 |
중복되지 않은 난수 목록을 만들려면 어떻게 해야 합니까? (0) | 2023.06.11 |