alloca () 사용이 왜 좋은 습관으로 간주되지 않습니까?


400

alloca()의 경우와 같이 힙이 아닌 스택에 메모리를 할당합니다 malloc(). 그래서 루틴에서 돌아올 때 메모리가 해제됩니다. 따라서 실제로 이것은 동적으로 할당 된 메모리를 확보하는 문제를 해결합니다. 할당 된 메모리를 확보 malloc()하는 것은 심각한 골치 거리이며, 놓친 경우 모든 종류의 메모리 문제를 일으 킵니다.

alloca()위의 기능에도 불구하고 사용이 권장되지 않는 이유는 무엇 입니까?


40
간단한 메모입니다. 이 함수는 대부분의 컴파일러에서 찾을 수 있지만 ANSI-C 표준에서는 필요하지 않으므로 이식성을 제한 할 수 있습니다. 또 다른 것은, 당신이해서는 안된다는 것입니다! free () 당신이 얻는 포인터와 함수를 종료하면 자동으로 해제됩니다.
merkuro 2016 년

9
또한 alloca () 함수는 선언 된 경우 인라인되지 않습니다.
Justicle

2
@Justicle, 당신은 몇 가지 설명을 제공 할 수 있습니까? 나는이 행동의 의미를 매우 궁금 하군요
migajek

47
이식성에 대한 모든 소음을 잊어 버릴 필요가 없습니다 free(명백히 이점 임), 인라인 할 수 없음 (분명히 힙 할당이 훨씬 무거움) 등 피해야 할 유일한 이유 alloca는 큰 크기입니다. 즉, 많은 양의 스택 메모리를 낭비하는 것은 좋은 생각이 아니며 스택 오버플로가 발생할 가능성이 있습니다. 이 경우 malloca/freea
valdo를 사용하십시오.

5
또 다른 긍정적 인 측면은 alloca스택을 힙처럼 조각화 할 수 없다는 것입니다. WCRU는 고유 한 문제 세트 (임시적 지역성, 최적이 아닌 리소스)가있는 사용자 지정 메모리 풀에 의존하지 않고 정적으로 분석 할 수 있기 때문에 어려운 실시간 런타임 스타일 응용 프로그램 또는 안전에 중요한 응용 프로그램에 유용 할 수 있습니다. 사용하다).
Andreas

답변:


245

그 대답은 man페이지에 있습니다 (적어도 Linux에서는 ).

반환 값 alloca () 함수는 할당 된 공간의 시작에 대한 포인터를 반환합니다. 할당으로 인해 스택 오버플로가 발생하면 프로그램 동작이 정의되지 않습니다.

절대 사용해서는 안된다는 말은 없습니다. 내가 작업하는 OSS 프로젝트 중 하나는 광범위하게 사용되며, 당신이 그것을 학대하지 않는 한 ( alloca'큰 가치 를 지니고있는 한) 괜찮습니다. "수백 바이트"표시를 지나면 malloc대신 친구와 친구 를 사용할 차례 입니다. 여전히 할당 실패가 발생할 수 있지만 최소한 스택을 제거하는 대신 실패에 대한 표시가있을 것입니다.


35
따라서 큰 배열을 선언해도 아무런 문제가 없습니까?
TED

88
@Sean : 예, 스택 오버플로 위험이 주어진 이유이지만 그 이유는 약간 어리 석습니다. 첫째, Vaibhav가 말했듯이 큰 로컬 배열은 정확히 같은 문제를 일으키지 만 거의 비방되지 않습니다. 또한 재귀는 스택을 쉽게 날려 버릴 수 있습니다. 죄송하지만 매뉴얼 페이지에 제공된 이유가 정당하다는 일반적인 아이디어에 반기를 들려주십시오.
j_random_hacker

49
내 요지는 alloca ()가 정결 한 것으로 간주되는 다른 것들 (로컬 배열 또는 재귀 함수)과 똑같이 "나쁜"것이기 때문에 매뉴얼 페이지에 주어진 정당화는 의미가 없다.
j_random_hacker

39
@ninjalj : 경험이 많은 C / C ++ 프로그래머는 아니지만, 두려워하는 많은 사람들 alloca()이 로컬 배열이나 재귀에 대해 같은 두려움을 가지고 있지 않다고 생각합니다. (실제로 소리를 지르는 많은 사람들은 alloca()"우아해 보이기 때문에 재귀를 칭찬합니다") . 나는 Shaun의 충고에 동의하지만 ( "alloca ()는 소량 할당에 적합하다") 나는 alloca ()를 3 중에서 독특하게 악한 것으로 생각한다는 생각에 동의하지 않는다.
j_random_hacker

35
참고 : Linux의 "낙관적"메모리 할당 전략을 고려할 때 힙 소모 오류가 발생 하지 않을 가능성 높습니다 . 대신 malloc ()은 NULL이 아닌 멋진 포인터를 반환하고 실제로 시도하려고 할 때 가리키는 주소 공간에 액세스하면 프로세스 (또는 다른 프로세스, 예측할 수없는)가 OOM 킬러에 의해 종료됩니다. 물론 이것은 C / C ++ 문제 그 자체가 아니라 Linux의 "기능"이지만 alloca () 또는 malloc ()이 "safer"인지 토론 할 때 명심해야합니다. :)
Jeremy Friesner

209

내가 가진 가장 기억에 남는 버그 중 하나는 사용한 인라인 함수와 관련이있었습니다 alloca. 프로그램 실행의 임의의 지점에서 스택 오버플로로 인해 스택 오버플로로 나타납니다.

헤더 파일에서 :

void DoSomething() {
   wchar_t* pStr = alloca(100);
   //......
}

구현 파일에서 :

void Process() {
   for (i = 0; i < 1000000; i++) {
     DoSomething();
   }
}

따라서 컴파일러 인라인 DoSomething함수가 발생했으며 모든 스택 할당이 Process()함수 내부에서 발생 하여 스택을 폭파했습니다. 내 방어에서 (그리고 나는 문제를 발견 한 사람이 아니었고, 고칠 수 없을 때 고위 개발자 중 한 명에게 가서 울어야했다), 그것은 직선적이지 않았다 alloca. 그것은 ATL 문자열 변환 중 하나였다. 매크로.

따라서 교훈은- alloca인라인 될 것으로 생각되는 함수 에는 사용하지 마십시오 .


91
흥미 롭군 그러나 이것이 컴파일러 버그로 적합하지 않습니까? 결국, 인라인은 코드의 동작을 변경했습니다 (alloca를 사용하여 할당 된 공간 확보를 지연시킵니다).
sleske

60
분명히 최소한 GCC는 이것을 고려할 것입니다 : "함수 정의의 특정 사용법은 인라인 대체에 적합하지 않을 수 있습니다. 이러한 사용법 중에는 varargs 사용, alloca 사용, [...]"이 있습니다. gcc.gnu.org/onlinedocs/gcc/Inline.html
sleske

136
어떤 컴파일러를 피웠습니까?
Thomas Eding

22
내가 이해하지 못하는 것은 컴파일러가 범위를 잘 사용하지 않아 서브 스코프의 allocas가 다소 "해제"되었는지 확인하는 것입니다. 스택 포인터는 범위에 들어가기 전에 시점으로 돌아올 수 있습니다. 기능에서 복귀 (그렇지 않습니까?)
moala

7
나는 downvoted했지만 그 대답은 잘 쓰여졌다 : 나는 분명히 컴파일러 버그 가 무엇인지 alloca를 잘못 생각하는 다른 사람들과 동의한다 . 컴파일러는 최적화하지 말아야 할 최적화에 잘못된 가정을했습니다. 컴파일러 버그를 해결하는 것은 좋지만 컴파일러를 제외하고는 아무것도 잘못하지 않습니다.
Evan Carroll

75

오래된 질문이지만 아무도 가변 길이 배열로 대체해야한다고 언급하지 않았습니다.

char arr[size];

대신에

char *arr=alloca(size);

표준 C99에 있으며 많은 컴파일러에서 컴파일러 확장으로 존재했습니다.


5
Jonathan Leffler는 Arthur Ulfeldt의 답변에 대한 언급에 대해 언급했습니다.
ninjalj

2
실제로, 게시하기 전에 모든 응답을 읽었음에도 불구하고 그것을 보지 못했기 때문에 얼마나 놓친 것인지도 보여줍니다.
Patrick Schlüter

6
한 가지 참고 사항-동적 배열이 아닌 가변 길이 배열입니다. 후자는 크기를 조정할 수 있으며 일반적으로 힙에서 구현됩니다.
Tim Čas

1
일부 C ++를 컴파일하는 Visual Studio 2015에는 동일한 문제가 있습니다.
ahcox

2
Linus Torvalds는 Linux 커널에서 VLA를 좋아하지 않습니다 . 버전 4.20부터 Linux는 거의 VLA가 없어야합니다.
Cristian Ciupitu

60

alloca ()는 런타임에 크기를 결정해야하기 때문에 표준 로컬 변수를 사용할 수 없고이 함수가 반환 된 후에 alloca ()에서 얻은 포인터가 절대 사용되지 않을 것을 절대 보장 할 수있는 경우 매우 유용 합니다 .

당신은 당신이 상당히 안전 할 수 있습니다

  • 포인터 또는 포인터가 포함 된 것을 반환하지 마십시오.
  • 힙에 할당 된 구조에 포인터를 저장하지 마십시오
  • 다른 스레드가 포인터를 사용하지 못하게하십시오.

진짜 위험은 다른 사람이 나중에이 조건을 위반할 가능성에서 비롯됩니다. 그것을 염두에두고 텍스트를 형식화하는 함수에 버퍼를 전달하는 것이 좋습니다 :)


12
C99의 VLA (가변 길이 배열) 기능은 alloca ()를 명시 적으로 요구하지 않고 동적으로 크기가 조정 된 지역 변수를 지원합니다.
Jonathan Leffler 2016 년


1
그러나 그것은 지역 변수에 대한 포인터를 다루는 것과 다르지 않습니다. 그들도 속일 수 있습니다 ...
glglgl

2
@Jonathan Leffler alloca로는 할 수 있지만 VLA로는 할 수없는 것은 키워드를 제한하는 것입니다. 다음과 같이 : float * restrict heavily_used_arr = alloca (sizeof (float) * size); float heavily_used_arr [size] 대신에. 크기가 컴파일 상수 인 경우에도 일부 컴파일러 (필자의 경우 gcc 4.8)가 어셈블리를 최적화하는 데 도움이 될 수 있습니다. 그것에 대한 내 질문을 참조하십시오 : stackoverflow.com/questions/19026643/using-restrict-with-arrays
Piotr Lopusiewicz

@JonathanLeffler VLA는 VLA를 포함하는 블록에 로컬입니다. 반면, alloca()함수가 끝날 때까지 지속되는 메모리를 할당합니다. 이는의 VLA로 간단하고 편리한 번역이없는 것 같습니다 f() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }. allocaVLA 사용을 용도로 자동 변환 할 수 있다고 생각 하지만 방법을 설명하기 위해 설명 이상의 의견이 필요한 경우이 질문을 할 수 있습니다.
Pascal Cuoq

40

이 뉴스 그룹 게시 에서 언급했듯이 사용 alloca이 어렵고 위험한 것으로 간주 될 수 있는 몇 가지 이유 가 있습니다.

  • 모든 컴파일러가 지원하는 것은 아닙니다 alloca.
  • 일부 컴파일러는 의도 된 동작을 alloca다르게 해석 하므로이를 지원하는 컴파일러 간에도 이식성이 보장되지 않습니다.
  • 일부 구현은 버그가 있습니다.

24
이 페이지의 다른 곳이 아닌 링크에서 언급 한 것은 alloca()스택 포인터와 프레임 포인터를 유지하기 위해 별도의 레지스터 가 필요한 함수입니다 . x86 CPU> = 386에서 스택 포인터 ESP는 둘 다에 사용될 수 있으며 사용 EBP되지 않는 한 해제 alloca()됩니다.
j_random_hacker

10
이 페이지의 또 다른 좋은 점은 컴파일러의 코드 생성기가 특수한 경우로 처리하지 않으면 적어도 하나의 인수를 푸시 한 후에f(42, alloca(10), 43); 스택 포인터가 조정될 가능성으로 인해 충돌 할 수 있다는 것입니다. alloca()
j_random_hacker

3
링크 된 게시물은 John Levine이 작성한 것으로 보입니다. "링커와 로더"를 쓴 사람은 그가 말한 것을 신뢰합니다.
user318904

3
링크 된 게시물은 John Levine의 게시물에 대한 회신 입니다.
A. Wilcox

6
1991 년 이후 많은 변화가 있었음을 명심하십시오 . 모든 현대 C 컴파일러 (2009 년에도)는 alloca를 특별한 경우로 처리해야합니다. 일반적인 함수 라기보다는 본질적인 함수이며 함수를 호출하지 않을 수도 있습니다. 따라서 1970 년대부터 K & R C에서 발생한 all-in-parameter 문제는 이제 문제가되지 않습니다. Tony D의 답변
greggo

26

한 가지 문제는 널리 지원되지만 표준이 아니라는 것입니다. 평등 한 다른 것들은 항상 일반적인 컴파일러 확장이 아닌 표준 함수를 사용합니다.


21

여전히 alloca 사용이 권장되지 않는 이유는 무엇입니까?

나는 그러한 합의를 인식하지 못한다. 많은 강력한 프로; 몇 가지 단점 :

  • C99는 가변 길이 배열을 제공하며, 고정 길이 배열과보다 일관성있는 표기법 및 전체적으로 직관적 인 표기법으로 우선적으로 사용되는 가변 길이 배열
  • 많은 시스템이 힙에 비해 스택에 사용할 수있는 전체 메모리 / 주소 공간이 적으므로 프로그램이 스택 오버플로를 통해 메모리 소모에 약간 더 취약 해집니다. 스택이 힙처럼 자동으로 확장되지 않는 이유는 제어 불가능한 프로그램이 전체 시스템에 많은 악영향을 미치지 않도록하기위한 것입니다.
  • 더 많은 로컬 범위 (예 : while또는 for루프) 또는 여러 범위에서 사용되는 경우 메모리는 반복 / 범위 당 누적되며 함수가 종료 될 때까지 해제되지 않습니다. 이는 제어 구조의 범위에 정의 된 일반 변수와 대조됩니다 (예 : for {int i = 0; i < 2; ++i) { X }축적 될 것이다alloca X에서 요청한 -ed 메모리를 하지만 고정 크기 배열의 메모리는 반복마다 재활용됩니다).
  • 현대 컴파일러는 일반적으로을 inline호출하는 함수를 호출 하지 않지만 alloca강제로 실행하면alloca 하면 호출자의 컨텍스트에서 발생합니다 (예 : 호출자가 반환 할 때까지 스택이 해제되지 않습니다)
  • 옛날에 alloca 이식 불가능한 기능 / 해킹에서 표준화 된 확장으로 전환했지만 부정적인 인식이 지속될 수 있습니다.
  • 수명은 프로그래머에게 더 잘 맞거나 그렇지 않을 수있는 기능 범위에 바인딩됩니다. malloc 의 명시 적 제어
  • 사용할 필요하면 malloc할당 해제에 대한 생각을 장려 - 그 래퍼 함수 (예를 통해 관리 않다면 WonderfulObject_DestructorFree(ptr)), 다음 함수는 클라이언트에 명시 적으로 변경하지 않고 (파일 기술자를 닫는 내부 포인터를 자유롭게 또는 일부 로깅을하고 같은) 구현 정리 작업을위한 지점을 제공합니다 코드 : 때로는 일관성있게 채택하는 것이 좋은 모델입니다.
    • 이 의사 -OO 스타일의 프로그래밍 WonderfulObject* p = WonderfulObject_AllocConstructor();에서 "constructor"가 malloc-ed 메모리를 반환하는 함수일 때 가능 합니다 (함수는 저장 될 값을 반환 한 후 메모리가 할당 된 상태 p이므로). "생성자"가alloca
      • 매크로 버전은 WonderfulObject_AllocConstructor이를 달성 할 수 있지만 "매크로는 악의적"입니다. 즉, 매크로와 코드가 아닌 코드가 서로 충돌하여 의도하지 않은 대체와 결과적으로 진단하기 어려운 문제가 발생할 수 있다는 점에서
    • 누락 된 free작업은 ValGrind, Purify 등에서 감지 할 수 있지만 누락 된 "소멸자"호출을 항상 감지 할 수는 없습니다. 의도 된 사용을 시행한다는 측면에서 매우 작은 이점이 있습니다. 일부 alloca()구현 (예 : GCC)은에 인라인 매크로를 사용 alloca()하므로 메모리 사용 진단 라이브러리의 런타임 대체는 malloc/ realloc/와 free같은 방식으로 불가능합니다 (예 : 전기 펜스)
  • 일부 구현에는 미묘한 문제가 있습니다 (예 : Linux 맨 페이지).

    많은 시스템에서 alloca ()는 함수 호출의 인수 목록 내에서 사용될 수 없습니다. alloca ()에 의해 예약 된 스택 공간은 함수 인수를위한 공간의 중간에있는 스택에 나타날 것이기 때문입니다.


나는이 질문에 C 태그가 붙어 있음을 알고 있지만 C ++ 프로그래머로서 C ++을 사용하여 잠재적 인 유틸리티를 설명 할 것이라고 생각했다 alloca. 아래 코드 (및 여기 ideone )는 스택 할당 된 힙 할당이 아닌 함수 반환에 연결된 수명).

#include <alloca.h>
#include <iostream>
#include <vector>

struct Base
{
    virtual ~Base() { }
    virtual int to_int() const = 0;
};

struct Integer : Base
{
    Integer(int n) : n_(n) { }
    int to_int() const { return n_; }
    int n_;
};

struct Double : Base
{
    Double(double n) : n_(n) { }
    int to_int() const { return -n_; }
    double n_;
};

inline Base* factory(double d) __attribute__((always_inline));

inline Base* factory(double d)
{
    if ((double)(int)d != d)
        return new (alloca(sizeof(Double))) Double(d);
    else
        return new (alloca(sizeof(Integer))) Integer(d);
}

int main()
{
    std::vector<Base*> numbers;
    numbers.push_back(factory(29.3));
    numbers.push_back(factory(29));
    numbers.push_back(factory(7.1));
    numbers.push_back(factory(2));
    numbers.push_back(factory(231.0));
    for (std::vector<Base*>::const_iterator i = numbers.begin();
         i != numbers.end(); ++i)
    {
        std::cout << *i << ' ' << (*i)->to_int() << '\n';
        (*i)->~Base();   // optionally / else Undefined Behaviour iff the
                         // program depends on side effects of destructor
    }
}

여러 유형을 처리하는 비린내 관용적 방식으로 인해 +1이 없음 :-(
einpoklum

@einpoklum : 글쎄요.
Tony Delroy

1
다시 말하겠습니다 : 이것은 매우 좋은 답변입니다. 사람들이 일종의 카운터 패턴을 사용하라고 제안하는 시점까지.
einpoklum

리눅스 맨 페이지의 의견은 매우 오래되었으며, 나는 더 이상 쓸모가 없다고 확신합니다. 현대의 모든 컴파일러는 alloca ()가 무엇인지 알고 있으며 그러한 신발 끈을 넘어 가지 않습니다. 기존 K & R C에서는 (1) 모든 함수가 프레임 포인터를 사용했습니다. (2) 모든 함수 호출은 {push args on stack} {call func} {add # n, sp}입니다. alloca는 스택을 올릴 수있는 lib 함수였습니다. 컴파일러는 그 일에 대해 알지 못했습니다. (1)과 (2)는 더 이상 사실이 아니므로 alloca는 그런 식으로 작동 할 수 없습니다 (현재는 본질적입니다). 구식 C에서는 args를 추진하는 도중에 alloca를 호출하면 분명히 이러한 가정을 어길 것입니다.
greggo

4
예를 들어, 나는 일반적으로 메모리 손상을 피하기 위해 always_inline을 요구 하는 것에 대해 걱정하고 있습니다 ....
greggo

14

다른 답변은 모두 맞습니다. 그러나 할당하려는 alloca()것이 합리적으로 작 으면 사용하는 것보다 빠르고 편리한 것이 좋은 기술이라고 생각합니다 malloc().

다시 말해서, alloca( 0x00ffffff )위험하고 오버플로를 유발할 가능성이 높습니다 char hugeArray[ 0x00ffffff ];. 신중하고 합리적이어야합니다.


12

이 "오래된"질문에 대한 많은 흥미로운 답변들, 심지어 비교적 새로운 답변들도 있지만 이것에 대한 언급은 찾지 못했습니다 ...

적절하고주의해서 사용하면 alloca() 작은 가변 길이 할당 (또는 사용 가능한 경우 C99 VLA)을 처리하기 위해 (어쩌면 응용 프로그램 전체에서) 일관성있게 사용 하면 고정 길이의 대형 로컬 배열을 사용하는 동등한 구현보다 전체 스택 성장낮아질 수 있습니다 . 그래서 alloca()수 있습니다 당신의 스택 좋은 당신은 신중하게 사용하는 경우.

나는 그 인용구를 발견했다 .. 좋아, 나는 그 인용구를 만들었다. 하지만 정말로 생각해보십시오.

@j_random_hacker는 다른 답변 아래 그의 의견에 매우 적합합니다. alloca()대형 로컬 배열을 선호 하여 사용 하지 않는 것이 스택 오버플로에서 프로그램을 더 안전하게 만들지 않습니다 (컴파일러가 alloca()어떤 경우에 사용해야하는 함수를 인라인 할 수있을 정도로 오래되지 않은 경우) alloca()내부 루프 를 사용하지 않는 경우, 내부 루프 를 사용 해서는 안됩니다 alloca()).

나는 데스크탑 / 서버 환경과 임베디드 시스템에서 일했다. 많은 임베디드 시스템은 힙을 전혀 사용하지 않으며 (지원하지도 않습니다), 응용 프로그램에서 메모리 누수의 위험으로 인해 동적으로 할당 된 메모리가 악하다는 인식이 포함됩니다. 한 번에 몇 년 동안 다시 부팅하거나 동적 메모리가 위험하다는 더 합리적인 정당화는 응용 프로그램이 힙을 메모리 소진 지점으로 분할하지 않을 것이라는 점을 확실히 알 수 없기 때문에 위험합니다. 따라서 임베디드 프로그래머에게는 몇 가지 대안이 남아 있습니다.

alloca() (또는 VLA)는 해당 직무에 적합한 도구 일 수 있습니다.

프로그래머가 스택 할당 버퍼를 "가능한 경우를 처리하기에 충분히 큰"시간과 시간을 다시 보았습니다. 깊게 중첩 된 호출 트리에서 해당 (anti-?) 패턴을 반복해서 사용하면 스택 사용이 과장됩니다. (20 레벨 깊이의 콜 트리를 상상해보십시오. 다른 이유로 각 레벨에서이 함수는 일반적으로 16 개 이하의 버퍼 만 사용하는 경우 "안전하게"1024 바이트의 버퍼를 맹목적으로 할당합니다. 드문 경우에는 더 많이 사용할 수 있습니다.) 대안은alloca()또는 스택에 불필요하게 부담을주지 않도록 함수에 필요한만큼의 스택 공간 만 할당하십시오. 호출 트리의 한 함수가 정상보다 큰 할당을 필요로 할 때, 호출 트리의 다른 함수는 여전히 정상적인 작은 할당을 사용하고 있으며, 전체 함수 스택 사용량이 모든 함수가 로컬 버퍼에 맹목적으로 초과 할당 된 경우보다 훨씬 적습니다. .

그러나 사용하기로 선택하면 alloca()...

이 페이지의 다른 답변에 따르면 VLA는 안전해야합니다 (루프 내에서 호출되면 스택 할당을 복합화하지 않음)하지만 alloca()을 사용하는 경우 루프 내에서 사용하지 않도록주의하십시오. 다른 함수의 루프 내에서 호출 될 가능성이있는 경우 함수를 인라인 할 수 없는지 확인 하십시오.


나는이 점에 동의한다. 의 위험 alloca()은 사실이지만 메모리 누수에 대해서도 마찬가지입니다 malloc()(GC를 사용하지 않는 이유는 무엇입니까?). alloca()주의해서 사용하면 스택 크기를 줄이는 데 정말 유용 할 수 있습니다.
Felipe Tonello

동적 메모리, 특히 내장 메모리를 사용하지 않는 또 다른 좋은 이유는 스택에 고정하는 것보다 더 복잡합니다. 동적 메모리를 사용하려면 특별한 절차와 데이터 구조가 필요하지만 스택에서는 스택 포인터에서 더 많은 수를 더하거나 뺄 수 있습니다.
tehftw

참고 : "고정 버퍼 사용 [MAX_SIZE]"예제는 오버 커밋 메모리 정책이 효과적인 이유를 강조합니다. 프로그램은 버퍼 길이의 한계를 제외하고는 절대 만질 수없는 메모리를 할당합니다. 따라서 리눅스 (및 다른 OS)는 실제로 malloc'd와는 달리 처음 사용될 때까지 메모리 페이지를 할당하지 않는 것이 좋습니다. 버퍼가 한 페이지보다 큰 경우 프로그램은 첫 번째 페이지 만 사용할 수 있으며 나머지 실제 메모리는 낭비되지 않습니다.
Katastic Voyage 2013

@KatasticVoyage MAX_SIZE가 시스템의 가상 메모리 페이지 크기보다 크거나 같지 않으면 인수에 물이 들어 가지 않습니다. 또한 가상 메모리가없는 내장형 시스템 (많은 내장형 MCU에는 MMU가 없음)에서 오버 커밋 메모리 정책은 "모든 상황에서 프로그램이 실행되도록 보장"관점에서 우수하지만 보장은 스택 크기의 가격과 함께 제공됩니다 오버 커밋 메모리 정책을 지원하려면 마찬가지로 할당해야합니다. 일부 임베디드 시스템에서는 저렴한 제품의 일부 제조업체가 지불하지 않는 가격입니다.
phonetagger

11

모든 사람들은 이미 스택 오버플로에서 정의되지 않은 동작이 될 수있는 큰 것을 지적했지만 Windows 환경에는 구조적 예외 (SEH) 및 가드 페이지를 사용하여이를 포착 할 수있는 훌륭한 메커니즘이 있습니다. 스택은 필요한만큼만 커지므로 이러한 보호 페이지는 할당되지 않은 영역에 있습니다. 스택을 오버플로하여 할당하면 예외가 발생합니다.

이 SEH 예외를 포착하고 _resetstkoflw를 호출하여 스택을 재설정하고 순조롭게 진행할 수 있습니다. 이상적이지는 않지만 물건이 팬에 부딪 칠 때 무언가 잘못되었다는 것을 아는 또 다른 메커니즘입니다. * nix는 내가 모르는 것과 비슷한 것을 가지고있을 수 있습니다.

alloca를 래핑하고 내부에서 추적하여 최대 할당 크기를 제한하는 것이 좋습니다. 실제로 하드 코어 인 경우 함수 상단에 일부 범위 센트리를 던져 함수 범위의 모든 할당량을 추적하고 프로젝트에서 허용되는 최대량과 비교하여 정상 성을 확인할 수 있습니다.

또한 메모리 누수를 허용하지 않는 것 외에도 alloca는 메모리 조각화를 일으키지 않으므로 매우 중요합니다. 나는 당신이 그것을 지능적으로 사용한다면 alloca가 나쁜 습관이라고 생각하지 않습니다. :-)


문제는 alloca()너무 많은 공간을 요구하여 스택 포인터가 힙에 도달한다는 것입니다. 이를 통해 크기 alloca()와 해당 버퍼에 들어가는 데이터를 제어 할 수있는 공격자 는 힙을 덮어 쓸 수 있습니다 (매우 나쁩니다).
12431234123412341234123

SEH는 Windows 전용입니다. Windows에서 실행되는 코드에만 관심이 있지만 코드가 크로스 플랫폼이어야하는 경우 (또는 Windows 이외의 플랫폼에서만 실행되는 코드를 작성하는 경우) 유용합니다. SEH.
조지

10

alloca () 는 훌륭하고 효율적이지만 ...

  • 끊어진 범위 동작 (블록 범위 대신 기능 범위)
  • malloc에와 일관성이 사용 ( alloca 함수 () -ted 포인터가 해제되지해야한다, 이제부터 당신은 당신이 포인터가 어디에서 오는지 추적 할 수 있습니다 ) (무료 오직 당신이있어 이들 의 malloc () )
  • 인라인을 사용할 때도 잘못된 동작 (수신자가 인라인인지 여부에 따라 범위가 발신자 기능으로 이동 함).
  • 스택 경계 검사 없음
  • 실패시 정의되지 않은 동작 (malloc과 같은 NULL을 반환하지 않습니다 ... 그리고 실패는 스택 경계를 검사하지 않기 때문에 무엇을 의미합니까 ...)
  • ANSI 표준이 아님

대부분의 경우 지역 변수와 주요 크기를 사용하여 바꿀 수 있습니다. 큰 물체에 사용되는 경우 더미 위에 놓는 것이 일반적으로 더 안전한 생각입니다.

실제로 C가 필요한 경우 VLA를 사용할 수 있습니다 (C ++에는 vla가 없으며 너무 나쁩니다). 범위 동작 및 일관성과 관련하여 alloca ()보다 훨씬 낫습니다. 내가 알다시피 VLA 는 일종의 alloca () 가 올바르게 만들어졌습니다.

물론 필요한 공간을 많이 사용하는 로컬 구조 또는 배열이 여전히 더 좋으며, 일반 malloc ()을 사용하여 이러한 주요 힙 할당이 없으면 아마도 제정신입니다. alloca () 또는 VLA 가 정말로 필요한 정상적인 사용 사례는 없습니다 .


나는 downvote의 이유를 보지 못합니다 (어쨌든 아무런 언급없이)
gd1

이름에만 범위가 있습니다. alloca이름을 만들지 않고 메모리 범위 만 있으며 수명은 입니다.
curiousguy

@ curiousguy : 당신은 단지 단어를 가지고 놀고 있습니다. 자동 변수의 경우 이름의 범위와 일치하므로 기본 메모리의 수명을 말할 수 있습니다. 어쨌든 문제는 우리가 그것을 부르는 방법이 아니라 alloca에 의해 반환 된 메모리의 수명 / 범위의 불안정성과 예외적 인 행동입니다.
kriss

2
alloca가 해당 "freea"를 갖고 있었으면 좋겠다. "freea"를 호출하면 객체와 그 이후의 모든 객체를 생성 한 "alloca"의 영향을 취소하고 기능 내에서 "alloca"스토리지 요구 사항을 취소해야합니다. 그 안에도 '무료'가 되십시오. 이는 거의 모든 구현에서 알로 카 / 프리카를 호환 가능한 방식으로 지원하고 인라인 문제를 완화 시켰으며 일반적으로 상황을 훨씬 깨끗하게 만들었습니다.
supercat

2
@supercat — 나도 그래. 그 이유를 (더)를 위해, 나는 내가 전화하지 않는 그래서 추상화 계층 (주로 매크로와 인라인 함수)를 사용 alloca하거나 malloc또는 free직접. 나는 일이 같은 말을 {stack|heap}_alloc_{bytes,items,struct,varstruct}하고 {stack|heap}_dealloc. 그래서, heap_dealloc바로 호출 freestack_deallocno-op입니다. 이러한 방식으로 스택 할당을 힙 할당으로 쉽게 다운 그레이드 할 수 있으며 의도도 더 명확합니다.
Todd Lehman

9

이유는 다음과 같습니다.

char x;
char *y=malloc(1);
char *z=alloca(&x-y);
*z = 1;

누구나이 코드를 작성하지는 않지만, 크기 인수는 alloca거의 확실하게 일종의 입력에서 나옵니다. 이는 악의적으로 프로그램을 alloca거대한 무언가 로 가져 오는 것을 목표로 할 수 있습니다 . 결국, 크기가 입력을 기반으로하지 않거나 크게 될 가능성이 없다면 왜 작은 고정 크기 로컬 버퍼를 선언하지 않았습니까?

사실상 모든 코드를 사용 alloca하거나 C99 vlas를 사용하는 경우 심각한 버그가 발생하여 충돌 (운이 좋을 경우) 또는 권한 손상 (운이 좋지 않은 경우)이 발생할 수 있습니다.


1
세상은 알지 못할 수도 있습니다. :( 즉, 나는 당신이 내가 가지고있는 질문을 분명히 할 수 있기를 바라고있다 alloca. 당신은 그것을 사용하는 거의 모든 코드에 버그가 있다고 말했지만 그것을 사용할 계획이다. 나는 가상 머신을 작성하고 있으며 막대한 속도 향상으로 인해 스택의 함수에서 벗어나지 않는 변수를 동적 대신 동적으로 할당하고 싶습니다. 메모리 풀에 접근 할 수 있지만 여전히 저렴하지는 않다는 것을 알고 있습니까?
GManNickG

7
무엇이 위험한지 아십니까? 이것은 : *0 = 9;굉장하다 !!! 포인터를 사용해서는 안됩니다 (또는 적어도 역 참조하지 않아야합니다). 잠깐만 null인지 테스트 할 수 있습니다. 흠. 또한 할당하려는 메모리의 크기를 테스트 할 수 있다고 생각 alloca합니다. 이상한 남자. 기묘한.
Thomas Eding

7
*0=9;유효하지 않습니다 C. 전달하는 크기를 alloca테스트 할 때는 무엇에 대해 테스트 하시겠습니까? 한계를 알 수있는 방법이 없으며 알려진 고정 안전 크기 (예 : 8k)에 대해 테스트하려는 경우 스택에서 고정 크기 배열을 사용할 수도 있습니다.
R .. GitHub 중지 지원 얼음

7
"크기가 충분히 작거나 입력에 따라 다르기 때문에 임의로 클 수 있습니다"라는 문제는 재귀에도 마찬가지로 적용됩니다. 실제적인 타협은 (두 경우 모두) 크기가 제한되어 small_constant * log(user_input)있으면 충분한 메모리 가 있다고 가정하는 것입니다.
j_random_hacker

1
실제로 VLA / alloca가 유용한 하나의 사례를 식별했습니다. 모든 호출 프레임에 필요한 최대 공간이 N만큼 클 수 있지만 모든 재귀 수준에 필요한 공간의 합이 N 또는 일부 함수 인 순환 알고리즘 빠르게 성장하지 않는 N의
R .. GitHub 중지 지원 얼음

9

컴파일러가 함수의 스택 프레임 크기를 알 수 없기 때문에 함수에 alloca를 사용하면 함수에 적용될 수있는 일부 최적화가 방해되거나 비활성화됩니다.

예를 들어, C 컴파일러의 일반적인 최적화는 함수 내에서 프레임 포인터를 사용하지 않고 스택 포인터를 기준으로 프레임 액세스를하는 것입니다. 일반적인 사용을위한 레지스터가 하나 더 있습니다. 그러나 alloca가 함수 내에서 호출되면 sp와 fp의 차이를 함수의 일부에서 알 수 없으므로이 최적화를 수행 할 수 없습니다.

드물게 사용하고 표준 기능으로 그늘진 상태를 감안할 때, 컴파일러 디자이너 는 alloca와 함께 작동하도록 약간의 노력을 기울이면 alloca에 문제를 일으킬 있는 최적화를 비활성화 있습니다.

업데이트 : 가변 길이의 로컬 배열이 C에 추가되었고, 이것들이 alloca와 같이 컴파일러에 매우 유사한 코드 생성 문제를 제시하기 때문에 '사용의 희소성 및 그늘진 상태'는 기본 메커니즘에 적용되지 않습니다. 그러나 나는 여전히 alloca 또는 VLA를 사용하면 코드를 사용하는 함수 내에서 코드 생성을 손상시키는 경향이 있다고 생각합니다. 컴파일러 디자이너의 의견을 환영합니다.


1
가변 길이 배열은 C ++에 추가되지 않았습니다.
Nir Friedman

@NirFriedman 실제로. 오래된 제안을 기반으로 한 Wikipedia 기능 목록이 있다고 생각합니다.
greggo

> 여전히 alloca 또는 VLA를 사용하면 코드 생성이 손상되는 경향 이 있다고 생각합니다. alloca를 사용하려면 스택 포인터가 컴파일 타임에 분명하지 않은 방식으로 이동하기 때문에 프레임 포인터가 필요하다고 생각합니다. 더 많은 스택 메모리를 잡거나 런타임 계산 된 크기 등을 유지하기 위해 alloca를 루프에서 호출 할 수 있습니다. 프레임 포인터가있는 경우 생성 된 코드는 로컬에 대한 안정적인 참조를 가지며 스택 포인터는 원하는 모든 작업을 수행 할 수 있습니다. 사용되지 않습니다.
Kaz

8

한 가지 함정 alloca은 그것을 longjmp되 감는 것입니다.

당신이 가진 컨텍스트 저장하는 경우 즉, 말을하는 것입니다 setjmp, 다음 alloca일부 메모리, 다음 longjmp상황에, 당신은 잃을 수 있습니다 alloca메모리를. 스택 포인터는 원래 있던 위치로 돌아가므로 메모리가 더 이상 예약되지 않습니다. 함수를 호출하거나 다른 함수를 수행 alloca하면 원본이 클로버됩니다 alloca.

명확히하기 위해, 여기서 구체적으로 언급하는 것은 발생한 longjmp위치에서 기능이 반환되지 않는 상황입니다 alloca! 오히려 함수는 다음과 같이 컨텍스트를 저장합니다 setjmp. 그런 다음 메모리를 할당 alloca하고 마지막으로 longjmp가 해당 컨텍스트에 발생합니다. 이 함수의 alloca메모리가 모두 해제되지는 않았습니다. 이후에 할당 한 모든 메모리 setjmp. 물론 관찰 된 행동에 대해 이야기하고 있습니다. 그러한 요구 사항은alloca 내가 아는 .

문서의 초점은 일반적으로 alloca메모리가 블록이 아닌 기능 활성화 와 관련되어 있다는 개념에 있습니다 . 여러 번 호출하면 alloca더 많은 스택 메모리를 가져와 함수가 종료되면 모두 해제됩니다. 별로; 메모리는 실제로 프로 시저 컨텍스트와 연관됩니다. 로 컨텍스트가 복원 longjmp되면 이전 alloca상태도 복원됩니다 . 이는 스택 포인터 레지스터 자체가 할당에 사용되고 결과적으로에 저장 및 복원 된 결과 jmp_buf입니다.

또한이 방법으로 작동하면에 할당 된 메모리를 고의적으로 해제하기위한 적절한 메커니즘을 제공합니다 alloca.

나는 이것을 버그의 근본 원인으로 삼았습니다.


1
그것은 그것이해야 할 일입니다- longjmp돌아가서 프로그램이 스택에서 일어난 모든 것을 잊어 버리게합니다 : 모든 변수, 함수 호출 등. alloca스택의 배열과 같습니다. 스택의 다른 모든 것들처럼.
tehftw

1
man alloca"alloca ()에 의해 할당 된 공간이 스택 프레임 내에 할당되기 때문에 longjmp (3) 또는 siglongjmp (3)에 대한 호출에 의해 함수 리턴이 점프되면 해당 공간이 자동으로 해제됩니다." 따라서 할당 된 메모리 alloca가 a 다음에 클로버 된다는 것이 문서화되어 longjmp있습니다.
tehftw

@tehftw 설명 된 상황은에 의해 함수 리턴을 건너 뛰지 않고 발생합니다 longjmp. 대상 함수가 아직 반환되지 않았습니다. 이 행하신 setjmp, alloca다음과 longjmp. 은 longjmp앞뒤로 계속 할 수 alloca는 있었다 무엇 상태 다시 setjmp시간을. 즉, 이동 한 포인터는 alloca표시되지 않은 지역 변수와 동일한 문제가 발생합니다 volatile!
Kaz

3
예상치 못한 이유를 이해할 수 없습니다. 이 때 setjmp다음 alloca, 다음 longjmp, 정상 있다는 alloca되 감을 것입니다. 요점 longjmp은에 저장된 상태로 돌아가는 것입니다 setjmp!
tehftw

@tehftw이 특정 상호 작용이 문서화 된 것을 본 적이 없습니다. 따라서 컴파일러를 사용한 경험적 조사가 아닌 다른 방법으로 신뢰할 수 없습니다.
Kaz

7

커널 alloca()보다 특히 위험한 장소 malloc()-일반적인 운영 체제의 커널에는 고정 된 스택 공간이 헤더 중 하나에 하드 코딩되어 있습니다. 애플리케이션 스택만큼 유연하지 않습니다. alloca()보증되지 않은 크기 로 호출 하면 커널이 중단 될 수 있습니다. 특정 컴파일러 alloca()는 커널 코드를 컴파일하는 동안 켜져 야하는 특정 옵션에서 해당 문제에 대한 VLA 사용에 대해 경고합니다. 여기서 하드 코딩 된 한계로 수정되지 않은 힙에 메모리를 할당하는 것이 좋습니다.


7
alloca()임의의 정수 가 int foo[bar];있는 곳 보다 더 위험하지 않습니다 bar.
Todd Lehman

@ToddLehman 맞습니다. 정확한 이유로 우리는 몇 년 동안 커널에서 VLA를 금지했으며 2018 년 이후 VLA가 없습니다 :-)
Chris Down

6

실수로 할당 된 블록 이상으로 작성하는 경우 alloca(때문에 예를 들어, 버퍼 오버 플로우에), 당신은 덮어 쓰게됩니다 반환 주소 하나가 스택에, 즉 "위에"위치하기 때문에, 당신의 기능을 한 후 귀하의 할당 된 블록.

스택의 _alloca 블록

이것의 결과는 두 가지입니다.

  1. 이 프로그램은 눈에 띄게 충돌하며 왜 또는 어디서 충돌했는지 알 수 없습니다 (겹친 프레임 포인터로 인해 임의의 주소로 스택이 풀릴 수 있음).

  2. 악의적 인 사용자가 스택에 놓일 수있는 특수 페이로드를 만들 수 있기 때문에 버퍼 오버플로가 여러 번 더 위험 해집니다.

반대로, 힙에 블록을 넘어 쓰면 힙 손상이 발생합니다. 프로그램이 예기치 않게 종료되지만 스택을 올바르게 해제하여 악성 코드가 실행될 가능성을 줄입니다.


11
이 상황에서는 고정 크기의 스택 할당 버퍼가 버퍼 오버플로 될 위험과 크게 다르지 않습니다. 이 위험은 고유하지 않습니다 alloca.
phonetagger

2
당연히 아니지. 그러나 원래 질문을 확인하십시오. 문제는 다음 alloca과 비교할 때 의 위험은 무엇입니까 malloc(따라서 스택의 고정 크기 버퍼는 아닙니다).
rustyx

작은 점이지만 일부 시스템의 스택은 위쪽으로 커집니다 (예 : PIC 16 비트 마이크로 프로세서).
EBlake

5

슬프게도 정말 굉장한 alloca()것이 거의 굉장한 tcc에서 빠져 있습니다. Gcc는 가지고 있습니다 alloca().

  1. 그것은 자신의 멸망의 씨를 뿌린다. 소멸자로 돌아온다.

  2. 마찬가지로 malloc()MMU가있는 최신 시스템에서 segfault를 수행 할 때 잘못된 포인터를 반환합니다 (없으면 다시 시작하십시오).

  3. 자동 변수와 달리 런타임시 크기를 지정할 수 있습니다.

재귀와 잘 작동합니다. 정적 변수를 사용하여 꼬리 재귀와 유사한 것을 달성하고 다른 반복자를 사용하여 각 반복에 정보를 전달할 수 있습니다.

너무 세게 밀면 segfault가 보장됩니다 (MMU가있는 경우).

참고 malloc() 이벤트 더 이상이 시스템의 메모리가 부족하면 (할당 된 경우도 세그 폴트 것) NULL을 반환한다.하지 즉, 당신이 할 수있는 일은 보석이나 그냥 방법을 할당하려고합니다.

사용하려면 malloc()전역 을 사용 하고 NULL을 할당하십시오. 포인터가 NULL이 아닌 경우 사용하기 전에 해제합니다.malloc() .

realloc()기존 데이터를 복사하려는 경우 일반적인 경우로 사용할 수도 있습니다 . 당신이 복사하거나 연결하려는 경우 운동하기 전에 포인터를 확인해야합니다realloc() .

3.2.5.2 alloca의 장점


4
실제로 alloca 사양은 정의되지 않은 동작이 있다고 말하면 실패시 잘못된 포인터 (스택 오버플로)를 반환한다고 말하지 않으며 malloc의 경우 임의의 유효하지 않은 포인터가 아닌 NULL을 반환한다고 말합니다 (OK, Linux 낙관적 메모리 구현으로 인해 쓸모없는).
kriss

@kriss Linux는 프로세스를 죽일 수 있지만 적어도 정의되지 않은 동작으로 들어 가지 않습니다
craig65535

@ craig65535 : 정의되지 않은 동작 표현은 일반적으로 해당 동작이 C 또는 C ++ 사양에 의해 정의되지 않음을 의미합니다. 어떤 방식 으로든 주어진 OS 또는 컴파일러에서 무작위이거나 불안정합니다. 따라서 UB를 "Linux"또는 "Windows"와 같은 OS 이름과 연결하는 것은 의미가 없습니다. 그것과 관련이 없습니다.
kriss

malloc이 NULL을 반환하거나 Linux의 경우 프로세스를 종료하는 메모리 액세스가 alloca의 정의되지 않은 동작보다 바람직하다고 말하려고했습니다. 첫 의견을 잘못 읽었어야한다고 생각합니다.
craig65535

3

프로세스는 사용 가능한 메모리 양보다 훨씬 적은 제한된 양의 스택 공간 만 사용할 수 있습니다 malloc().

를 사용 alloca()하면 스택 오버플로 오류가 발생할 가능성이 크게 높아집니다 (행운이 있거나 그렇지 않은 경우 설명 할 수없는 충돌).


그것은 응용 프로그램에 따라 크게 다릅니다. 메모리 제한 임베디드 응용 프로그램이 힙보다 큰 스택 크기를 갖는 것은 드문 일이 아닙니다 (힙이있는 경우에도).
EBlake

3

아주 예쁘지는 않지만 성능이 정말로 중요하다면 스택의 일부 공간을 미리 할당 할 수 있습니다.

이미 메모리 블록의 최대 크기가 필요하고 오버플로 검사를 유지하려는 경우 다음과 같이 할 수 있습니다.

void f()
{
    char array_on_stack[ MAX_BYTES_TO_ALLOCATE ];
    SomeType *p = (SomeType *)array;

    (...)
}

12
모든 데이터 유형에 대해 char 배열이 올바르게 정렬되어 있습니까? alloca는 그러한 약속을 제공합니다.
Juho Östman

@ JuhoÖstman : 정렬 문제가있는 경우 char 대신 구조체 배열 (또는 모든 유형)을 사용할 수 있습니다.
kriss

이를 가변 길이 배열 이라고합니다 . C90 이상에서는 지원되지만 C ++에서는 지원되지 않습니다. C ++ 03 및 C ++ 11에서 C 가변 길이 배열을 사용할 수 있습니까?를
jww

3

alloca 함수는 훌륭하고 모든 naysayer는 단순히 FUD를 확산시킵니다.

void foo()
{
    int x = 50000; 
    char array[x];
    char *parray = (char *)alloca(x);
}

배열과 parray는 정확히 같은 위험과 동일합니다. 하나가 다른 것보다 낫다는 것은 기술적 인 선택이 아니라 구문상의 선택입니다.

스택 변수 대 힙 변수를 선택하는 경우 범위 내 수명이있는 변수에 대해 스택 오버 힙을 사용하는 장기 실행 프로그램에는 많은 이점이 있습니다. 힙 조각화를 피하고 사용되지 않는 (사용할 수없는) 힙 공간으로 프로세스 공간이 커지는 것을 피할 수 있습니다. 정리할 필요가 없습니다. 프로세스에서 스택 할당을 제어 할 수 있습니다.

왜 이것이 나쁜가요?


3

실제로 alloca는 스택 사용을 보장하지 않습니다. 실제로, alloca의 gcc-2.95 구현은 malloc 자체를 사용하여 힙에서 메모리를 할당합니다. 또한 구현이 버그가 있으므로 goto를 추가로 사용하여 블록 내에서 호출하면 메모리 누수가 발생하고 예기치 않은 동작이 발생할 수 있습니다. 당신이 그것을 사용해서는 안된다고 말하는 것은 아니지만, 때로는 alloca가 그것보다 더 많은 오버 헤드를 가져옵니다.


gcc-2.95가 alloca를 깨뜨린 것처럼 들리며 아마도 필요한 프로그램에는 안전하게 사용할 수 없습니다 alloca. longjmp그렇게 한 프레임을 버릴 때 메모리를 어떻게 정리 했 alloca습니까? 오늘 누가 gcc 2.95를 사용합니까?
Kaz

2

IMHO, alloca는 스택 크기 제한을 모두 사용하기를 두려워하기 때문에 나쁜 습관으로 간주됩니다.

이 스레드와 다른 링크를 읽으면서 많은 것을 배웠습니다.

나는 alloca를 사용하여 변경없이 C89 스타일, #ifdef _MSC_VER 등이없는 평범한 C 파일을 msvc 및 gcc에서 컴파일 가능하게 만듭니다.

감사합니다 ! 이 스레드로 인해이 사이트에 가입하게되었습니다. :)


이 사이트에는 "스레드"와 같은 것이 없습니다. 스택 오버플로에는 토론 스레드 형식이 아닌 질문 및 답변 형식이 있습니다. "답변"은 토론 포럼의 "답변"과 다릅니다. 실제로 질문에 대한 답변을 제공하고 있으며 다른 답변에 답변하거나 주제에 대한 의견을 제시하는 데 사용해서는 안됩니다. 담당자가 50 명 이상인 경우 댓글게시 할 수 있지만 '언제 댓글을 달지 말아야 합니까?' 를 읽어보십시오. 부분. 사이트 형식을 더 잘 이해 하려면 정보 페이지를 읽으십시오 .
Adi Inbar 2016 년

1

제 생각에 alloca ()는 가능한 경우 제한적인 방식으로 만 사용해야합니다. "goto"를 사용하는 것과 마찬가지로, 합리적으로 많은 사람들은 alloca ()의 사용뿐만 아니라 alloca ()의 존재로도 강력한 혐오감을 가지고 있습니다.

임베디드 사용의 경우 스택 크기가 알려져 있고 할당 크기에 대한 규칙 및 분석을 통해 제한을 적용 할 수 있으며 C99 +를 지원하도록 컴파일러를 업그레이드 할 수없는 경우 alloca () 사용이 좋습니다. 그것을 사용하는 것으로 알려져 있습니다.

사용 가능한 경우 VLA는 alloca ()에 비해 몇 가지 장점이 있습니다. 컴파일러는 배열 스타일 액세스가 사용될 때 범위를 벗어난 액세스를 잡을 스택 제한 검사를 생성 할 수 있습니다 (컴파일러가이 작업을 수행하는지는 모르겠지만 코드를 분석하면 배열 액세스 표현식이 올바르게 바인드되었는지 판별 할 수 있습니다. 자동차, 의료 장비 및 항공 전자 공학과 같은 일부 프로그래밍 환경에서이 분석은 자동 (스택) 및 정적 할당 (전역 또는 로컬)의 고정 크기 어레이에 대해서도 수행해야합니다.

스택에 데이터와 리턴 주소 / 프레임 포인터를 모두 저장하는 아키텍처에서 (내가 아는 바로는 전부입니다) 변수의 주소를 취할 수 있기 때문에 스택 할당 변수는 위험 할 수 있으며 검사되지 않은 입력 값은 허용 될 수 있습니다 온갖 종류의 장난.

이식성은 임베드 된 공간에서 큰 문제가되지 않지만 신중하게 제어되는 환경 외부에서 alloca ()를 사용하지 않는 것이 좋습니다.

임베디드 공간 밖에서 나는 효율성을 위해 로깅 및 포맷 함수 내부에서 alloca ()를 사용했으며 비 재귀 어휘 스캐너에서 토큰 화 및 분류 중에 임시 구조 (alloca ()를 사용하여 할당 됨)가 사용되었습니다. 소규모의 임시 구조에 alloca ()를 사용하면 영구 객체가 할당 될 때 조각화가 크게 줄어 듭니다.


1

여기서 대부분의 대답은 요점을 크게 놓친 것입니다. _alloca() 것입니다. 스택에 큰 객체를 저장하는 것보다 이 잠재적으로 더 나쁜 가 있습니다.

자동 스토리지와의 주요 차이점 _alloca()은 후자가 추가적인 (심각한) 문제를 겪고 있다는 것입니다. 할당 된 블록은 컴파일러에 의해 제어되지 않으므로 컴파일러가이를 최적화하거나 재활용 할 방법이 없습니다.

비교:

while (condition) {
    char buffer[0x100]; // Chill.
    /* ... */
}

와:

while (condition) {
    char* buffer = _alloca(0x100); // Bad!
    /* ... */
}

후자의 문제는 명백해야합니다.


당신은 VLA 사이의 차이를 보여주는 어떤 실례가 있습니까 alloca(때문에, 그래, 내가 말 할 VLA를 alloca정적 크기의 배열의 단지 창조자보다 더)?
Ruslan

두 번째 경우에는 유스 케이스가 있으며 첫 번째는 지원하지 않습니다. 루프가 'n'번 실행 된 후 '연결된 목록 또는 트리에서'n '레코드를 원할 수 있습니다. 이 데이터 구조는 함수가 결국 반환 될 때 폐기됩니다. 어떤 식 으로든 코드를 작성하겠다고 말하는 것은 아닙니다 :-)
greggo

1
그리고 "컴파일러가 그것을 제어 할 수 없다"고 말하고 싶습니다. 이것이 alloca ()가 정의 된 방식이기 때문입니다. 현대의 컴파일러는 alloca가 무엇인지 알고 그것을 특별하게 취급합니다. 80 년대와 같은 라이브러리 기능이 아닙니다. C99 VLA는 기본적으로 블록 범위 (및 더 나은 입력)를 가진 alloca입니다. 다소 다른 제어가 아니라 단지 다른 의미론을 준수합니다.
greggo

@ greggo : 당신이 downvoter라면 내 대답이 유용하지 않다고 생각하는 이유를 기쁘게 들었습니다.
alecov

C에서 재활용은 컴파일러의 작업이 아니라 c 라이브러리의 작업입니다 (free ()). alloca ()는 반환되면 해제됩니다.
peterh-Reinstate Monica

1

나는 아무도 이것을 언급하지 않았다고 생각하지만, alloca는 malloc과 함께 반드시 존재하지 않는 심각한 보안 문제를 가지고 있습니다 (이러한 문제는 스택 기반 배열에서 발생하지만 동적이든 아니든 상관 없습니다). 메모리가 스택에 할당되므로 버퍼 오버플로 / 언더 플로는 malloc보다 훨씬 심각한 결과를 초래합니다.

특히 함수의 반환 주소는 스택에 저장됩니다. 이 값이 손상되면 실행 가능한 메모리 영역으로 이동하도록 코드를 만들 수 있습니다. 컴파일러는 특히 주소 레이아웃을 무작위 화하여이를 어렵게 만들기 위해 많은 노력을 기울입니다. 그러나 반환 값이 손상된 경우 가장 좋은 경우 SEGFAULT이기 때문에 스택 오버플로보다 분명히 나쁘지만 임의의 메모리 조각 또는 최악의 경우 프로그램의 보안을 손상시키는 메모리 영역이 실행될 수 있습니다. .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.