2017-03-24 5 views
10

데비안 OS에서 재귀 호출이있는 프로그램을 실행 중입니다. 내 스택의 크기는 지금까지 내가 배운대로, 스택 크기가 고정되어 있어야합니다고정 된 금액 대신 각각의 스택 사용에 따라 스택 오버플로가 발생하는 이유는 무엇입니까?

-s: stack size (kbytes)    8192 

이며, 명시 적으로 ulimit으로 변경하지 않는 한 모든 실행에서 프로그램에 할당해야하는 동일해야합니다.

재귀 함수는 0에 도달 할 때까지 주어진 숫자를 감소시킵니다. 이것은 녹서에 기록되어 있습니다.

fn print_till_zero(x: &mut i32) { 
    *x -= 1; 
    println!("Variable is {}", *x); 
    while *x != 0 { 
     print_till_zero(x); 
    } 
} 

및 값 I가 동일한 값마다의 스택 오버 플로우를 예상하고, 변경 안 이론적

static mut Y: i32 = 999999999; 
unsafe { 
    print_till_zero(&mut Y); 
} 
프로그램에 할당 된 스택이 고정되어 있기 때문에

및로 전달되지만 그것은 스택 할당이 가변적이라는 것을 의미합니다.

경기 1 :

====snip==== 
Variable is 999895412 
Variable is 999895411 

thread 'main' has overflowed its stack 
fatal runtime error: stack overflow 

경기 2 :

====snip==== 
Variable is 999895352 
Variable is 999895351 

thread 'main' has overflowed its stack 
fatal runtime error: stack overflow 

차이는 미묘하지만, 그것은 동일한 변수의 스택 오버 플로우를 일으키는 적이어야한다? 서로 다른 시간에 왜 그런 일이 일어나며, 각 실행마다 다른 스택 크기를 암시합니까? 이것은 녹과 관련이 없습니다. 비슷한 동작은 C에서 관찰된다

#pragma GCC push_options 
#pragma GCC optimize ("O0") 
#include<stdio.h> 
void rec(int i){ 
    printf("%d,",i); 
    rec(i-1); 
    fflush(stdout); 
} 
int main(){ 
setbuf(stdout,NULL); 
rec(1000000); 
} 
#pragma GCC pop_options 

출력 :

실행 1 :

738551,738550,[1] 7052 segmentation fault 

실행 2 :

738438,738437,[1] 7125 segmentation fault 
+6

스택 오버 플로우는 페이지 오류 일 때만 발생합니다. 스택 포인터가 언로드/소유되지 않은 페이지로 실행되는 경우입니다.스택이 시작되는 위치는 정확한 페이지 경계 일 필요는 없지만 오버 플로우 조건 (페이지 폴트) 트리거가 달라 지도록 프로그램이로드되는 위치에 따라 달라질 수 있습니다. –

+1

[this] (http://stackoverflow.com/questions/31180563/why-are-stackoverflow-errors-chaotic)도 비슷합니까? – Art

+0

@RichardCritten 따라서 할당 된 스택 크기 밖에있는 페이지는 소유되지 않은 페이지 권한이어야합니다. 내가 틀렸다면 나를 바로 잡아주세요. – nohup

답변

16

대부분의 아마이 ASLR 때문이다.

특정 유형의 공격을 더 어렵게 만들기 위해 스택의 기본 주소가 각 실행마다 무작위로 지정됩니다. 리눅스에서이 has a granularity of 16 bytes (이것은 x86과 내가 아는 거의 모든 플랫폼에서 가장 큰 정렬 요구 사항이다).

반면에 the page size is (normally) 4 KB on x86과 첫 번째 금지 된 페이지를 터치하면 스택 오버플로가 감지됩니다. 이는 시스템이 스택 오버 플로우를 감지하기 전에 항상 부분 페이지 (ASLR에 따라 오프셋이 있음)와 전체 페이지 두 개를 사용할 수 있음을 의미합니다. 따라서 총 사용 가능한 스택 크기는 적어도 요청한 8192 바이트와 각 실행에서 사용 가능한 크기가 다른 첫 번째 부분 페이지입니다.


  1. 오프셋 "일반"이 모든 경우에서 1

    는 제로이고; 행운이고 무작위 오프셋이 0 인 경우 정확하게 두 페이지를 얻을 수 있습니다.
+0

실제로 16 바이트는 x86 AFAIK에서 가장 제한적인 정렬 요구 사항입니다. –

+0

죄송합니다. 내 덧글을 실수로 삭제 했으므로 다시 여기에 추가하십시오. 나는 스택이 무작위화된 경우, 효율적인 액세스를 위해 페이지에 맞춰서는 안되는가? 업데이트 해주셔서 감사합니다. – nohup

+1

가장 제한적인 데이터 유형의 경우에만 정렬해야합니다. –