문제

x86 Linux 시스템에서 스택 오버플로를 일으킬 수 있는 특정 조건이 있습니다.

  • struct my_big_object[HUGE_NUMBER] 스택에.그것을 통해 걷는 것은 결국 SIGSEGV.
  • 그만큼 alloca() 루틴(예: malloc(), 그러나 스택을 사용하고 자동으로 해제되며 다음과 같이 폭발합니다. SIGSEGV 너무 큰 경우). 업데이트:alloca()는 내가 원래 언급한 것처럼 공식적으로 더 이상 사용되지 않습니다.단지 낙담했을 뿐이야.

로컬 스택이 주어진 객체에 비해 충분히 큰지 프로그래밍 방식으로 감지하는 방법이 있습니까?나는 스택 크기가 다음을 통해 조정 가능하다는 것을 알고 있습니다. ulimit, 그래서 방법이 있기를 바랍니다(그러나 이식성이 없을 수도 있음).이상적으로는 다음과 같은 작업을 수행하고 싶습니다.

int min_stack_space_available = /* ??? */;
if (object_size < min_stack_space_available)
{
    char *foo = alloca(object_size);
    do_stuff(foo);
}
else
{
    char *foo = malloc(object_size);
    do_stuff(foo);
    free(foo);
}
도움이 되었습니까?

해결책

프로세스 '스택 공간의 크기를 찾은 다음 사용 된 양을 빼서 프로세스가 사용할 수있는 스택 공간을 결정할 수 있습니다.

ulimit -s

Linux 시스템의 스택 크기를 보여줍니다. 프로그래밍 방식의 접근 방식은 확인하십시오 getrlimit (). 그런 다음 현재 스택 깊이를 결정하려면 스택 상단에 포인터를 한쪽에서 하단으로 빼냅니다. 예를 들어 (코드 테스트되지 않은) :

unsigned char *bottom_of_stack_ptr;

void call_function(int argc, char *argv) {
    unsigned char top_of_stack;
    unsigned int depth = (&top_of_stack > bottom_of_stack_ptr) ? 
        &top_of_stack-bottom_of_stack_ptr : 
        bottom_of_stack_ptr-&top_of_stack;

    if( depth+100 < PROGRAMMATICALLY_DETERMINED_STACK_SIZE ) {
        ...
    }
}

int main(int argc, char *argv) {
    unsigned char bottom_of_stack;
    bottom_of_stack_ptr = &bottom_of_stack;
    my_function();
    return 0;
}

다른 팁

더 이상 사용되지 않은 Alloca () 루틴 (Malloc ()와 같은 스택을 사용하고 자동으로 해방되며 Sigsegv가 너무 큰 경우 SIGSEGV로 날려 버립니다).

Alloca가 더 이상 사용되지 않는 이유는 무엇입니까?

어쨌든, 당신의 경우에 Alloca vs Malloc은 얼마나 빠릅니까? (그만한 가치가 있습니까?)

공간이 충분하지 않으면 Alloca에서 널 되돌아 가지 않습니까? (Malloc과 마찬가지로?)

그리고 코드가 충돌하면 어디에서 충돌합니까? Alloca에 있습니까 아니면 Dostuff ()에 있습니까?

/요한

이것이 Linux에서 적용되는지 확실하지 않지만 Windows에서는 대규모 스택 할당으로 액세스 위반에 들어갈 수 있습니다. 그들이 성공하더라도!

기본적으로 Windows의 VMM은 실제로 스택 액세스가 일반적으로 아래쪽으로 행진한다고 믿기 때문에 실제로 상위 몇 대 (정확히 얼마나 많은지 확실하지 않음) 4096 바이트의 스택 램 페이지를 pagable으로 표시하기 때문입니다. 상단; 액세스가 현재 "경계"에 가까워지면서 하위 및 하위 페이지는 Pagable으로 표시됩니다. 그러나 이것은 메모리가 아직 할당되지 않았기 때문에 스택 상단보다 훨씬 아래에있는 초기 메모리 읽기/쓰기가 액세스 위반을 트리거한다는 것을 의미합니다!

Alloca ()는 실패시 Null을 반환 할 것입니다. Alloca (0)의 동작은 정의되지 않은 플랫폼 변형이라고 생각합니다. do_something () 전에 그것을 확인하면 segv에 맞지 않아야합니다.

몇 가지 질문이 있습니다.

  1. 왜, 왜, 당신은 스택에 큰 무언가가 필요합니까? 대부분의 시스템의 기본 크기는 8m이므로 여전히 너무 작습니까?
  2. Alloca () 블록을 호출하는 함수가 Mlock () / mlockall ()을 통해 동일한 양의 힙을 보호하는 경우 시간이 지남에 따라 동일한 액세스 성능 (예 : "Do n't Swap Me, Bro!")에 가깝게 보장합니까? 보다 공격적인 'RT'스케줄러를 사용하는 경우 어쨌든 전화하는 것이 좋습니다.

문제는 흥미롭지 만 눈썹을 높입니다. 그것은 내 정사각형 끈 끈-O- 미터의 바늘을 올립니다.

스택에 할당하는 이유에 대해별로 말하지는 않지만 매력적인 스택 메모리 모델이라면 힙에 스택 할당도 구현 될 수 있습니다. 프로그램의 시작 부분에 큰 메모리 덩어리를 할당하고 일반 스택의 프레임에 해당하는 포인터 스택을 유지하십시오. 함수가 반환 될 때 개인 스택 포인터를 팝업하는 것을 기억하면됩니다.

예를 들어 여러 컴파일러 Watcom C/C ++를 열었습니다, 정확히 할 수있는 stackavail () 함수를 지원합니다.

당신이 사용할 수있는 GNU libsigsegv 에게 핸들 스택 오버플로가 발생하는 경우를 포함한 페이지 오류(웹 사이트에서):

일부 응용 프로그램에서는 스택 오버플로 처리기가 일부 정리를 수행하거나 사용자에게 알린 다음 즉시 응용 프로그램을 종료합니다.다른 애플리케이션에서는 스택 오버플로 처리기 longjmp가 애플리케이션의 중앙 지점으로 돌아갑니다.이 라이브러리는 두 가지 용도를 모두 지원합니다.두 번째 경우, 핸들러는 일반 신호 마스크를 복원해야 하며(핸들러가 실행되는 동안 많은 신호가 차단되기 때문에) 제어권을 전달하려면 sigsegv_leave_handler()도 호출해야 합니다.그런 다음에만 longjmp할 수 있습니다.

Alloca 기능은입니다 ~ 아니다 감가 상각 된. 그러나 POSIX에 있지 않으며 기계 및 컴파일러에 따라 다릅니다. Alloca의 Linux Man-Page는 "특정 응용 프로그램의 경우 Malloc 사용에 비해 효율성을 향상시킬 수 있으며 특정 경우 Longjmp () 또는 Siglongjmp ()를 사용하는 응용 프로그램에서 메모리 거래를 단순화 할 수 있다고 지적합니다. 그것의 사용은 낙담합니다. "

인력은 또한 "스택 프레임을 확장 할 수없는 경우 오류 표시가 없다고 말합니다. 그러나 할당 실패 후 프로그램은 SIGSEGV를받을 가능성이 높습니다."

Malloc의 성능은 실제로 언급되었습니다 stackoverflow 팟 캐스트 #36.

(나는 이것이 당신의 질문에 대한 적절한 답이 아니라는 것을 알고 있지만 어쨌든 그것이 유용 할 것이라고 생각했습니다.)

이것이 당신의 질문에 대한 직접적인 답이 아니더라도, 나는 당신이 존재한다는 것을 알고 있기를 바랍니다. Valgrind - Linux에서 런타임에서 이러한 문제를 감지하기위한 훌륭한 도구.

스택 문제와 관련하여 이러한 오버플로를 감지하는 고정 풀에서 동적으로 객체를 할당 할 수 있습니다. 간단한 거대-와이즈 드라이를 사용하면 릴리스 시간에 실제 코드가 실행되면서 디버그 시간 에이 실행을 할 수 있으므로 (적어도 실행중인 시나리오에 대해) 너무 많이 복용하지 않는다는 것을 알 수 있습니다. 다음은 더 많은 정보와 링크입니다 샘플 구현에.

내가 생각할 수있는 좋은 방법은 없습니다. getRlimit () (이전 제안)와 일부 포인터 산술을 사용하여 가능할 수 있습니까? 그러나 먼저 당신이 정말로 이것을 원하는지 스스로에게 물어보십시오.

void *closeToBase;

main () {
  int closeToBase;
  stackTop = &closeToBase;
}

int stackHasRoomFor(int bytes) {
  int currentTop;
  return getrlimit(...) - (¤tTop  - closeToBase) > bytes + SomeExtra;
}

개인적으로, 나는 이것을하지 않을 것입니다. 힙에 큰 것을 할당하면 스택은 그 의미가 아닙니다.

스택 영역의 끝은 OS에 의해 동적으로 결정됩니다. 가상 메모리 영역 (VMA)을 OS의 종속 방식으로 보면 스택의 "정적"경계를 찾을 수 있지만 (StackVma* 파일 참조 libsigsegv/src/), 당신은 추가로 고려해야합니다

이것이 명백하다면 사과하지만, 해당 크기의 Alloca를 시도하고 스택 오버 플로우 예외를 포착하여 특정 스택 할당 크기를 테스트하는 기능을 쉽게 작성할 수 있습니다. 원한다면 함수 스택 오버 헤드에 대한 사전 결정된 수학으로 기능에 넣을 수 있습니다. 예 :

bool CanFitOnStack( size_t num_bytes )
{
    int stack_offset_for_function = 4; // <- Determine this
    try
    {
        alloca( num_bytes - stack_offset_for_function );
    }
    catch ( ... )
    {
        return false;
    }

    return true;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top