456

alloca()の場合のように、ヒープではなくスタックにメモリを割り当てますmalloc()。したがって、ルーチンから戻ると、メモリが解放されます。したがって、実際には、これにより、動的に割り当てられたメモリを解放するという私の問題が解決されます。割り当てられmalloc()たメモリの解放は大きな頭痛の種であり、何らかの理由で見落とされた場合、あらゆる種類のメモリの問題が発生します。

上記の機能にもかかわらず、なぜ使用がalloca()推奨されないのですか?

4

24 に答える 24

292

答えはmanページのすぐそこにあります(少なくともLinuxでは):

戻り値alloca()関数は、割り当てられたスペースの先頭へのポインターを返します。割り当てによってスタックオーバーフローが発生した場合、プログラムの動作は未定義です。

それは決して使用されるべきではないということではありません。私が取り組んでいるOSSプロジェクトの1つはそれを広範囲に使用しており、それを悪用しない限り(alloca'巨大な価値を持っている)、それは問題ありません。「数百バイト」のマークを超えたらmalloc、代わりに友人を使用します。それでも割り当ての失敗が発生する可能性がありますが、少なくとも、スタックを吹き飛ばすだけでなく、失敗の兆候が見られます。

于 2009-06-19T16:27:17.543 に答える
238

私が抱えていた最も記憶に残るバグの1つは、を使用したインライン関数に関するものallocaでした。これは、プログラムの実行のランダムなポイントで(スタックに割り当てられるため)スタックオーバーフローとして現れました。

ヘッダーファイル:

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

実装ファイル:

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

つまり、コンパイラのインラインDoSomething関数が発生し、すべてのスタック割り当てがProcess()関数内で発生し、スタックが爆発しました。私の弁護では(そして私は問題を見つけた人ではありませんでした;私がそれを修正できなかったとき私は上級開発者の1人に行って泣かなければなりませんでした)、それはまっすぐではありませんでしたalloca、それはATL文字列変換の1つでしたマクロ。

したがって、レッスンは-allocaインライン化される可能性があると思われる関数では使用しないでください。

于 2010-08-04T23:35:07.060 に答える
97

古い質問ですが、可変長配列に置き換える必要があるとは誰も言及していません。

char arr[size];

それ以外の

char *arr=alloca(size);

これは標準のC99にあり、多くのコンパイラでコンパイラ拡張として存在していました。

于 2010-08-01T20:45:08.660 に答える
71

alloca()は、実行時にサイズを決定する必要があるため、標準のローカル変数を使用できない場合に非常に便利です 。また、この関数が。を返した後は、alloca()から取得したポインターが使用されないことを絶対に保証できます。

あなたがするならあなたはかなり安全になることができます

  • ポインタまたはそれを含むものを返さないでください。
  • ヒープに割り当てられた構造体にポインタを格納しないでください
  • 他のスレッドにポインタを使用させないでください

本当の危険は、他の誰かが後でこれらの条件に違反する可能性から来ています。それを念頭に置いて、テキストをフォーマットする関数にバッファを渡すのに最適です:)

于 2009-06-22T23:46:08.043 に答える
45

このニュースグループの投稿に記載されているように、使用allocaが困難で危険であると見なされる理由はいくつかあります。

  • すべてのコンパイラがをサポートしているわけではありませんalloca
  • 一部のコンパイラは意図した動作をalloca異なる方法で解釈するため、それをサポートするコンパイラ間でも移植性は保証されません。
  • 一部の実装にはバグがあります。
于 2009-06-19T16:28:33.347 に答える
31

1つの問題は、広くサポートされていますが、標準ではないことです。他の条件が同じであれば、私は常に、一般的なコンパイラ拡張ではなく、標準関数を使用します。

于 2009-06-19T16:35:44.020 に答える
25

それでもアロカの使用は推奨されていません、なぜですか?

私はそのようなコンセンサスを認識していません。強力なプロがたくさん。いくつかの短所:

  • C99は可変長配列を提供します。これは、表記が固定長配列とより一貫性があり、全体的に直感的であるため、優先的に使用されることがよくあります。
  • 多くのシステムでは、ヒープよりもスタックに使用できる全体的なメモリ/アドレス空間が少ないため、プログラムは(スタックオーバーフローによる)メモリの枯渇の影響を受けやすくなります。これは、良いことまたは悪いことと見なされる場合があります。スタックがヒープのように自動的に大きくならない理由の1つは、制御不能なプログラムがマシン全体に大きな悪影響を与えるのを防ぐためです。
  • よりローカルなスコープ(whileまたはforループなど)または複数のスコープで使用される場合、メモリは反復/スコープごとに蓄積され、関数が終了するまで解放されません。これは、制御構造のスコープで定義された通常の変数とは対照的です(例:Xで要求された-edメモリfor {int i = 0; i < 2; ++i) { X }を蓄積しますが、固定サイズの配列のメモリは反復ごとにリサイクルされます)。alloca
  • inline最近のコンパイラは通常、を呼び出す関数を実行しませんallocaが、強制するallocaと、呼び出し元のコンテキストで発生します(つまり、呼び出し元が戻るまでスタックは解放されません)
  • ずっと前allocaに、移植性のない機能/ハックから標準化された拡張機能に移行しましたが、いくつかの否定的な認識が続く可能性があります
  • malloc存続期間は関数スコープにバインドされます。関数スコープは、の明示的な制御よりもプログラマーに適している場合とそうでない場合があります。
  • 使用する必要がmallocあると、割り当て解除について考えることが奨励されます-ラッパー関数(例WonderfulObject_DestructorFree(ptr))を介して管理されている場合、この関数は、クライアントに明示的な変更を加えることなく、実装のクリーンアップ操作(ファイル記述子のクローズ、内部ポインターの解放、ロギングの実行など)のポイントを提供しますコード:一貫して採用するのが良いモデルである場合があります
    • この疑似OOスタイルのプログラミングでは、次のようなものが必要になるのは自然です。これWonderfulObject* p = WonderfulObject_AllocConstructor();は、「コンストラクター」がmallocメモリを返す関数である場合に可能です(関数が格納される値を返した後もメモリは割り当てられたままであるためp)。 「コンストラクター」が使用する場合alloca
      • のマクロバージョンはWonderfulObject_AllocConstructorこれを達成できますが、「マクロは悪」であり、マクロ以外のコードが互いに競合し、意図しない置換が発生し、その結果、診断が困難になる可能性があります。
    • 欠落しているfree操作はValGrind、Purifyなどで検出できますが、欠落している「デストラクタ」呼び出しは常に検出できるとは限りません。一部のalloca()実装(GCCなど)は、にインラインマクロを使用するためalloca()、メモリ使用量診断ライブラリの実行時の置換は、//(電気柵など)の場合とはmalloc異なりますreallocfree
  • 一部の実装には微妙な問題があります。たとえば、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
    }
}
于 2013-02-26T10:31:06.390 に答える
18

他のすべての答えは正しいです。ただし、使用するものalloca()が適度に小さい場合は、使用するよりも速くて便利な良いテクニックだと思いmalloc()ます。

言い換えれば、alloca( 0x00ffffff )危険であり、オーバーフローを引き起こす可能性がありchar hugeArray[ 0x00ffffff ];ます。注意して合理的にすれば大丈夫です。

于 2009-06-19T16:32:27.013 に答える
16

この「古い」質問に対する興味深い回答がたくさんあり、比較的新しい回答もいくつかありますが、これについて言及しているものは見つかりませんでした。

適切かつ注意深く使用すると、alloca() (おそらくアプリケーション全体で)小さな可変長の割り当て(または利用可能な場合はC99 VLA)を一貫して使用すると、固定長の特大のローカル配列を使用する同等の実装よりも全体的なスタックの増加を抑えることができます。したがって、慎重に使用すれば、スタックに適してalloca()いる可能性があります。

私はその引用を見つけました....OK、私はその引用を作りました。しかし、本当に、それについて考えてください....

@j_random_hackerは、他の回答の下での彼のコメントで非常に正しいです:alloca()特大のローカル配列を支持しての使用を避けても、プログラムがスタックオーバーフローから安全になるわけではありません(コンパイラが使用する関数のインライン化を可能にするのに十分古い場合を除きますalloca()。アップグレードするか、alloca()内部ループを使用しない限り、その場合は...alloca()内部ループを使用しないでください)。

私はデスクトップ/サーバー環境と組み込みシステムに取り組んできました。多くの組み込みシステムは、ヒープをまったく使用しません(ヒープをサポートするためにリンクすることさえありません)。これには、動的に割り当てられたメモリが悪であるという認識が含まれるためです。一度に何年も再起動するか、動的メモリが危険であるというより合理的な理由は、アプリケーションが誤ったメモリ枯渇のポイントまでヒープを断片化しないことを確実に知ることができないためです。そのため、組み込みプログラマーにはいくつかの選択肢が残されています。

alloca()(またはVLA)は、この作業に最適なツールである可能性があります。

プログラマーがスタックに割り当てられたバッファーを「考えられるすべてのケースを処理するのに十分な大きさ」にするということを何度も目にしました。深くネストされたコールツリーでは、その(アンチ?)パターンを繰り返し使用すると、スタックの使用が誇張されます。(20レベルの深さのコールツリーを想像してみてください。各レベルで、さまざまな理由で、関数は1024バイトのバッファを「安全のために」盲目的に過剰に割り当てますが、通常は16バイト以下しか使用しません。まれなケースではもっと使用する場合があります。)別の方法は使用することですalloca()またはVLAを使用して、スタックに不必要な負担をかけないように、関数が必要とするだけのスタックスペースを割り当てます。うまくいけば、コールツリー内の1つの関数が通常よりも大きい割り当てを必要とする場合、コールツリー内の他の関数は引き続き通常の小さな割り当てを使用し、アプリケーションスタック全体の使用量は、すべての関数がローカルバッファを盲目的に過剰に割り当てた場合よりも大幅に少なくなります。 。

しかし、使用することを選択した場合alloca()...

このページの他の回答に基づくと、VLAは安全であるはずです(ループ内から呼び出された場合、スタック割り当てを複合しません)が、alloca()を使用している場合は、ループ内で使用しないように注意して、別の関数のループ内で呼び出される可能性がある場合は、関数をインライン化できないようにしてください

于 2016-03-31T22:00:52.420 に答える
14

誰もこれについて言及していないと思います。コンパイラが関数のスタックフレームのサイズを知ることができないため、関数でallocaを使用すると、関数に適用できる最適化が妨げられたり無効になったりします。

たとえば、Cコンパイラによる一般的な最適化は、関数内でのフレームポインタの使用を排除することであり、代わりにスタックポインタを基準にしてフレームアクセスが行われます。したがって、一般的に使用するレジスタがもう1つあります。ただし、関数内でallocaが呼び出された場合、関数の一部でspとfpの違いが不明になるため、この最適化を行うことはできません。

その使用の希少性と標準関数としての日陰の状態を考えると、コンパイラの設計者は、allocaで動作させるために少し以上の努力が必要な場合、allocaで問題を引き起こす可能性のある最適化を無効にする可能性があります。

更新: 可変長のローカル配列がCに追加され、これらはallocaと非常によく似たコード生成の問題をコンパイラーに提示するため、「使用の希少性と日陰の状態」は基盤となるメカニズムには適用されないことがわかります。しかし、allocaまたはVLAのいずれかを使用すると、それらを使用する関数内のコード生成が危険にさらされる傾向があるのではないかと思います。コンパイラ設計者からのフィードバックを歓迎します。

于 2016-11-04T16:00:30.210 に答える
13

スタックオーバーフローによる未定義動作の可能性については、すでに誰もが指摘していますが、Windows環境には、構造化例外(SEH)とガードページを使用してこれをキャッチする優れたメカニズムがあることを述べておきます。スタックは必要な場合にのみ増大するため、これらのガードページは未割り当ての領域に存在します。(スタックをオーバーフローさせることによって)それらに割り当てると、例外がスローされます。

このSEH例外をキャッチし、_resetstkoflwを呼び出してスタックをリセットし、陽気な方法で続行できます。それは理想的ではありませんが、少なくとも何かがファンに当たったときに何かがうまくいかなかったことを知るための別のメカニズムです。*nixには私が気付いていない似たようなものがあるかもしれません。

allocaをラップして内部で追跡することにより、最大割り当てサイズを制限することをお勧めします。あなたがそれについて本当にハードコアであるなら、あなたはあなたの関数の上部にいくつかのスコープ歩哨を投げて、関数スコープ内のアロカ割り当てを追跡し、プロジェクトに許可された最大量に対してこれを健全性チェックすることができます。

また、メモリリークを許可しないことに加えて、allocaはメモリの断片化を引き起こしません。これは非常に重要です。アロカをインテリジェントに使用すれば、アロカは悪い習慣ではないと思います。これは基本的にすべてに当てはまります。:-)

于 2011-03-21T16:19:04.990 に答える
11

落とし穴の1つallocaは、longjmp巻き戻すことです。

つまり、コンテキストを保存しsetjmp、次にallocaメモリを保存してlongjmpから、コンテキストに保存すると、メモリが失われる可能性がありallocaます。スタックポインタが元の場所に戻ったため、メモリは予約されなくなりました。関数を呼び出すか、別の関数を実行allocaすると、元の関数が壊滅しますalloca

明確にするために、ここで私が具体的に言及しているのは、発生longjmpした機能から戻らない状況allocaです!むしろ、関数はsetjmp;でコンテキストを保存します。次に、でメモリを割り当てalloca、最後にそのコンテキストでlongjmpが実行されます。その関数のallocaメモリはすべて解放されるわけではありません。以降に割り当てられたすべてのメモリsetjmp。もちろん、私は観察された行動について話している。alloca私が知っていることについては、そのような要件は文書化されていません。

ドキュメントの焦点は通常、メモリがブロックではなく関数allocaのアクティブ化に関連付けられているという概念にあります。の複数の呼び出しは、関数が終了したときにすべて解放されるスタックメモリをさらに取得します。そうではありません。メモリは実際にはプロシージャコンテキストに関連付けられています。コンテキストがで復元されると、以前の状態も復元されます。これは、スタックポインタレジスタ自体が割り当てに使用され、(必然的に)に保存および復元された結果です。allocalongjmpallocajmp_buf

ちなみに、これがそのように機能する場合、で割り当てられたメモリを意図的に解放するためのもっともらしいメカニズムを提供しallocaます。

私はバグの根本的な原因としてこれに遭遇しました。

于 2018-02-26T04:12:23.547 に答える
10

理由は次のとおりです。

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

誰もがこのコードを書くわけではありませんが、渡すサイズの引数は、ほぼ確実に、プログラムをそのような巨大なものallocaにすることを悪意を持って狙う可能性のある、ある種の入力から来ています。alloca結局のところ、サイズが入力に基づいていないか、大きくなる可能性がない場合は、なぜ小さな固定サイズのローカルバッファーを宣言しなかったのでしょうか。

事実上、C99 vlasを使用するすべてのコードallocaには重大なバグがあり、クラッシュ(運が良ければ)または特権の侵害(運が悪ければ)につながります。

于 2010-08-01T20:32:39.617 に答える
10

alloca()は素晴らしく効率的です...しかしそれはまた深く壊れています。

  • 壊れたスコープの動作(ブロックスコープではなく関数スコープ)
  • mallocと矛盾する使用(alloca() -tedポインターは解放されるべきではありません。したがって、ポインターがどこから来ているかを追跡する必要があります。これは、 malloc()取得したポインターのみです) 。
  • インライン化も使用すると、動作が悪くなります(呼び出し先がインライン化されているかどうかによって、スコープが呼び出し元の関数に移動することがあります)。
  • スタック境界チェックなし
  • 失敗した場合の未定義の動作(mallocのようにNULLを返さない...そしてスタック境界をチェックしないので失敗とはどういう意味ですか...)
  • ANSI規格ではありません

ほとんどの場合、ローカル変数とメジャーサイズを使用して置き換えることができます。大きなオブジェクトに使用する場合は、通常、ヒープに配置する方が安全です。

本当にCが必要な場合は、VLAを使用できます(C ++にはvlaがない、残念です)。スコープの動作と一貫性に関しては、alloca()よりもはるかに優れています。私が見ているように、 VLAは一種のalloca()が正しく作成されています。

もちろん、必要なスペースの大部分を使用するローカル構造または配列の方が優れています。そのような大部分のヒープ割り当てがない場合は、プレーンなmalloc()を使用するのがおそらく適切です。alloca()またはVLAのいずれかが本当に必要な正気のユースケースは見当たりません。

于 2014-09-02T10:26:20.137 に答える
7

alloca()カーネルよりも特に危険な場所malloc()-一般的なオペレーティングシステムのカーネルには、ヘッダーの1つにハードコードされた固定サイズのスタックスペースがあります。アプリケーションのスタックほど柔軟ではありません。保証されていないサイズでを呼び出すとalloca()、カーネルがクラッシュする可能性があります。特定のコンパイラはalloca()、カーネルコードのコンパイル中にオンにする必要がある特定のオプションの下での使用(さらにはVLA)を警告します。ここでは、ハードコードされた制限によって固定されていないメモリをヒープに割り当てることをお勧めします。

于 2010-11-27T18:49:15.397 に答える
6

プロセスでは、使用可能なスタックスペースの量が限られています。これは、で使用可能なメモリの量よりはるかに少ない量ですmalloc()

使用alloca()することで、スタックオーバーフローエラーが発生する可能性が大幅に高まります(運が良ければ、そうでない場合は不可解なクラッシュが発生します)。

于 2009-06-19T16:27:46.547 に答える
6

で割り当てられたブロックを超えて誤って書き込んだ場合alloca(たとえば、バッファオーバーフローが原因で)、関数のリターンアドレスはスタックの「上」、つまり割り当てられたブロックの後にあるため、上書きされます。

スタック上の_allocaブロック

この結果は2つあります。

  1. プログラムは見事にクラッシュし、クラッシュした理由や場所を特定することはできません(フレームポインタが上書きされるため、スタックはランダムなアドレスにアンワインドする可能性があります)。

  2. 悪意のあるユーザーがスタックに配置される特別なペイロードを作成して実行される可能性があるため、バッファオーバーフローは何倍も危険になります。

対照的に、ヒープ上のブロックを超えて書き込むと、「ただ」ヒープが破損します。プログラムはおそらく予期せず終了しますが、スタックを適切に巻き戻し、悪意のあるコードが実行される可能性を減らします。

于 2016-02-17T10:43:45.337 に答える
5

悲しいことに、本当に素晴らしいものalloca()は、ほとんど素晴らしいtccから欠落しています。Gccにはありますalloca()

  1. それはそれ自身の破壊の種をまきます。デストラクタとしてのリターン付き。

  2. 同様malloc()に、失敗すると無効なポインタが返され、MMUを備えた最新のシステムでセグメンテーション違反が発生します(できれば、MMUを使用せずにシステムを再起動します)。

  3. 自動変数とは異なり、実行時にサイズを指定できます。

再帰でうまく機能します。静的変数を使用して末尾再帰に似たものを実現し、他のいくつかの変数を使用して各反復に情報を渡すことができます。

深く押しすぎると、セグメンテーション違反が発生することが保証されます(MMUがある場合)。

malloc()システムのメモリが不足している場合はNULLを返すため(割り当てられている場合はセグメンテーション違反も発生します)、はこれ以上提供されないことに注意してください。つまり、あなたができることは保釈するか、それをなんらかの方法で割り当てようとすることだけです。

使用するmalloc()には、グローバルを使用してNULLを割り当てます。ポインタがNULLでない場合は、を使用する前にポインタを解放しますmalloc()

realloc()既存のデータをコピーしたい場合は、一般的なケースとして使用することもできます。の後にコピーまたは連結する場合は、解決する前にポインタを確認する必要がありますrealloc()

3.2.5.2アロカの利点

于 2011-03-30T06:58:49.993 に答える
3

実際、allocaがスタックを使用することは保証されていません。実際、allocaのgcc-2.95実装は、malloc自体を使用してヒープからメモリを割り当てます。また、その実装にはバグがあり、gotoをさらに使用してブロック内で呼び出すと、メモリリークが発生し、予期しない動作が発生する可能性があります。決して使用してはいけないと言っているわけではありませんが、アロカは、それが元から離れるよりも多くのオーバーヘッドにつながることがあります。

于 2017-01-30T18:14:22.037 に答える
2

私の意見では、alloca()は、利用可能な場合、制限された方法でのみ使用する必要があります。「goto」の使用と非常によく似ていますが、それ以外の点では合理的な人々のかなりの数が、alloca()の使用だけでなく、その存在にも強い嫌悪感を抱いています。

組み込み用途の場合、スタックサイズがわかっていて、割り当てのサイズに関する規則と分析によって制限を課すことができ、コンパイラをアップグレードしてC99 +をサポートできない場合は、alloca()を使用しても問題ありません。それを使用することが知られています。

利用可能な場合、VLAにはalloca()に比べていくつかの利点があります。コンパイラーは、配列スタイルのアクセスが使用されたときに範囲外のアクセスをキャッチするスタック制限チェックを生成できます(コンパイラーがこれを行うかどうかはわかりませんが、可能ですコードを分析することで、配列アクセス式が適切に制限されているかどうかを判断できます。自動車、医療機器、アビオニクスなどの一部のプログラミング環境では、この分析は、自動(スタック上)と静的割り当て(グローバルまたはローカル)の両方の固定サイズのアレイに対しても実行する必要があることに注意してください。

データとリターンアドレス/フレームポインタの両方をスタックに格納するアーキテクチャでは(私が知っていることから、それがすべてです)、変数のアドレスを取得できるため、スタックに割り当てられた変数は危険である可能性があり、チェックされていない入力値は許可する可能性がありますあらゆる種類のいたずら。

埋め込みスペースでは移植性はそれほど重要ではありませんが、慎重に制御された状況以外でalloca()を使用することには反対の良い議論です。

埋め込みスペースの外では、効率を上げるために主にロギングおよびフォーマット関数内でalloca()を使用しました。また、非再帰的な字句スキャナーでは、トークン化と分類中に一時構造(alloca()を使用して割り当てられたもの)が作成され、その後永続的になります。オブジェクト(malloc()を介して割り当てられる)は、関数が戻る前に入力されます。小さな一時構造にalloca()を使用すると、永続オブジェクトが割り当てられるときの断片化が大幅に減少します。

于 2016-12-13T14:36:17.440 に答える
1

誰もこれについて言及していないと思いますが、allocaには、mallocに必ずしも存在しない深刻なセキュリティ問題もあります(これらの問題は、動的かどうかに関係なく、スタックベースの配列でも発生します)。メモリはスタックに割り当てられるため、バッファオーバーフロー/アンダーフローは、mallocだけの場合よりもはるかに深刻な結果をもたらします。

特に、関数のリターンアドレスはスタックに格納されます。この値が破損した場合、コードはメモリの任意の実行可能領域に移動する可能性があります。コンパイラは、これを困難にするために非常に長い時間を費やします(特に、アドレスレイアウトをランダム化することによって)。ただし、戻り値が破損している場合はSEGFAULTが最良のケースであるため、これは単なるスタックオーバーフローよりも明らかに悪いですが、ランダムなメモリの実行を開始したり、最悪の場合、プログラムのセキュリティを危険にさらすメモリの一部の領域を実行したりする可能性もあります。 。

于 2018-12-30T22:29:57.113 に答える
1

GNUドキュメンテーションによって導入されたこの例に誰も言及しないのはなぜですか?

https://www.gnu.org/software/libc/manual/html_node/Advantages-of-Alloca.html

で実行された非ローカル出口longjmp非ローカル出口allocaを参照)は、を呼び出した関数を介して終了するときに、で割り当てられたスペースを自動的に解放しますallocaこれが使用する最も重要な理由です alloca

読み上げ順序を提案する1->2->3->1

  1. https://www.gnu.org/software/libc/manual/html_node/Advantages-of-Alloca.html
  2. 非ローカル出口からのイントロ詳細
  3. Allocaの例
于 2021-08-05T17:08:22.937 に答える
0

アロカおよび可変長配列のIMOの最大のリスクは、割り当てサイズが予想外に大きい場合に非常に危険な方法で失敗する可能性があることです。

スタック上の割り当てには、通常、ユーザーコードのチェックインはありません。

最近のオペレーティングシステムでは、通常、スタックオーバーフローを検出するためにガードページが下に配置されます*。スタックがオーバーフローすると、カーネルはスタックを拡張するか、プロセスを強制終了する可能性があります。Linuxは、2017年にこのガード領域をページよりも大幅に大きくするように拡張しましたが、サイズはまだ有限です。

したがって、原則として、以前の割り当てを利用する前に、スタックに1ページ以上を割り当てることは避けるのが最善です。アロカ配列または可変長配列を使用すると、攻撃者がスタック上で任意のサイズを割り当てて、ガードページをスキップして任意のメモリにアクセスできるようになる可能性があります。

*今日のほとんどの普及したシステムでは、スタックは下向きに成長します。

于 2021-09-17T16:48:04.927 に答える
-1

_alloca()ここでのほとんどの回答は、主に要点を見逃しています。単に大きなオブジェクトをスタックに格納するよりも、使用が潜在的に悪い理由があります。

自動ストレージとの主な違い_alloca()は、後者には追加の(重大な)問題があることです。割り当てられたブロックはコンパイラによって制御されないため、コンパイラがそれを最適化またはリサイクルする方法はありません。

比較:

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

と:

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

後者の問題は明らかなはずです。

于 2017-04-28T14:31:41.020 に答える