Main()の前にプログラムがクラッシュする方法はありますか?
Gccを使用すると、関数に コンストラクタ属性 をタグ付けできます(これにより、main
の前に関数が実行されます)。次の関数では、premain
がmain
の前に呼び出されます。
#include <stdio.h>
void premain() __attribute__ ((constructor));
void premain()
{
fputs("premain\n", stdout);
}
int main()
{
fputs("main\n", stdout);
return 0;
}
したがって、premain
にクラッシュするバグがある場合、main
の前にクラッシュします。
はい、少なくともWindowsでは。プログラムがDLLを利用する場合、main()
が開始する前にDLLをロードできます。これらのDLLのDllMain
関数は、main()
の前に実行されます。エラーが発生した場合、プロセス全体が停止またはクラッシュする可能性があります。
C++プログラムがある場合、mainに入る前に、関数とコンストラクターを介して変数とオブジェクトを初期化できます。これらのいずれかのバグにより、プログラムがクラッシュする可能性があります。
簡単な答えははいです。
具体的には、2つの原因を区別できます。それらをimplementation-dependentおよびimplementation-independentと呼びます。
環境にまったく依存しない1つのケースは、C++の静的オブジェクトのケースで、ここで説明しました。次のコードはmain()
の前に終了します。
_#include <iostream>
class Useless {
public:
Useless() { throw "You can't construct me!"; }
};
static Useless object;
int main() {
std::cout << "This will never be printed" << std::endl;
return 0;
}
_
より興味深いのはプラットフォーム依存の原因です。いくつかはここで言及されました。ここで何度か言及されたのは、動的にリンクされたライブラリ(WindowsのDLL、LinuxのSOなど)の使用でした-OSのローダーがmain()
の前にそれらをロードすると、アプリケーションが実行する可能性がありますmain()
の前に死ぬ。
この原因のより一般的なバージョンは、your entry point(main()
)を呼び出す前にyour binaryのエントリポイントが行うすべてのことについて話します。通常、バイナリをビルドすると、オペレーティングシステムのローダーがバイナリの実行を開始したときに呼び出されるかなり深刻なコードブロックがあり、実行が完了するとmain()
が呼び出されます。このコードが行う一般的なことの1つは、C/C++標準ライブラリの初期化です。このコードは、さまざまな理由で失敗する可能性があります(1つに割り当てようとするあらゆる種類のシステムリソースの不足)。
Windowsでmain()
の前にバイナリがコードを実行する興味深い方法の1つは、TLSコールバックを使用することです(Googleがそれらについて詳しく説明します)。この手法は通常、マルウェアで基本的なデバッグ防止のトリックとして発見されます(このトリックは、当時ollydbgをだますために使用されていましたが、まだそうであるかどうかはわかりません)。
ポイントは、あなたの質問は実際には「バイナリをロードするとユーザーコードがmain()
のコードの前に実行される方法があるのですか」と同等であり、答えはhell、yeah !
確かにC++で。コンストラクタを持つ静的オブジェクトはメインの前に呼び出されます-それらは死ぬ可能性があります
cについてわからない
ここにサンプルがあります
class X
{
public:
X()
{
char *x = 0;
*x = 1;
}
};
X x;
int main()
{
return 0;
}
これはメインの前にクラッシュします
メインの前に読み込まれる共有オブジェクト(DLL)に依存するプログラムは、メインの前に失敗する可能性があります。
Linuxでは、ダイナミックリンカーライブラリ(ld-*。so)のコードが実行されて、メインのかなり前にライブラリの依存関係が提供されます。必要なライブラリが見つからない場合、それらにアクセスできない、通常のファイルではない、またはプログラムをリンクしたダイナミックリンカーが必要とするシンボルを持たない場合は、それはあなたのプログラムをリンクし、これは失敗を引き起こす可能性があります。
さらに、各ライブラリは、リンクされたときにいくつかのコードを実行します。これは主に、ライブラリがより多くのライブラリをリンクする必要がある場合や、いくつかのコンストラクタを実行する必要がある場合があるためです(Cプログラムの場合でも、ライブラリには、C++など、コンストラクタを使用するものがあります)。さらに、標準のCプログラムでは、stdio FILEのstdin、stdout、およびstderrがすでに作成されています。多くのシステムでは、これらも閉じることができます。これは、それらもfree()されていることを意味します。これは、それら(およびそれらのバッファー)がmalloc()され、失敗する可能性があることを意味します。また、それらのFILE構造が表すファイル記述子に対して他の処理を行った可能性があり、失敗する可能性があることも示唆しています。
OSがプログラムに渡された環境変数やコマンドライン引数、あるいはその両方の設定をめちゃくちゃにしていた場合、他に起こり得る可能性があります。 mainの前のコードは、mainを呼び出す前にこのデータで何かしなければならなかった可能性があります。
メインの前にたくさんのことが起こります。それらはどれも致命的な方法で失敗する可能性があります。
わかりませんが、次のようなグローバル変数がある場合:
static SomeClass object;
int main(){
return 0;
}
'SomeClass'コンストラクターは、メインが実行される前にプログラムをクラッシュさせる可能性があります。
多くの可能性があります。
まず、mainが実行される前に、実際に何が行われているのかを理解する必要があります。
これにより、いくつかの方法でクラッシュが発生する可能性があります。
catch
がないため、terminate
が呼び出され、プログラムが終了しますもちろん、これは本当に厄介で、デバッグが難しい可能性があります。そのため、main
の前のコードの実行をできるだけ控え、可能な場合は遅延初期化、またはmain
内の明示的な初期化を優先する必要があります。
もちろん、DLLが失敗して修正できない場合は、苦痛の世界にいます。
並べ替え: http://blog.ksplice.com/2010/03/libc-free-world/
次のように、標準ライブラリなしでコンパイルする場合:gcc -nostdlib -o hello hello.c
main()の実行方法がわからず、クラッシュします。
これは「メインの前」の意味に依存しますが、「メインのコードが実際に実行される前」を意味する場合は、1つの例が考えられます。大きな配列をメインのローカル変数として宣言すると、この配列のサイズが使用可能なスタックスペースを超えている場合、stack overflow
mainへのエントリ時、コードの最初の行が実行される前。
C++プログラムのグローバルオブジェクトと静的オブジェクトは、main()の最初のステートメントが実行される前にコンストラクターが呼び出されるため、コンストラクターの1つにバグがあるとクラッシュする可能性があります。
ただし、これはCプログラムでは発生しません。
class Crash
{
public:
Crash( int* p )
{ *p = 0; }
};
static Crash static_crash( 0 );
void main()
{
}
やや工夫された例は次のとおりです。
int a = 1;
int b = 0;
int c = a / b;
int main()
{
return 0;
}
このようなことをすることはほとんどありませんが、多くのマクロマジックを実行している場合、それは完全に可能です。
私は同じ問題に直面していました。見つかった根本的な原因は..メインプロセスで初期化されたローカル変数(巨大な配列)が多すぎるため、ローカル変数のサイズが1.5 mbを超えていました。
スタックポインタが非常に大きく、OSがこのジャンプを無効として検出し、悪意のあるプログラムをクラッシュさせるため、これは大きなジャンプをもたらします。
これをデバッグするには。
1。 GDBを起動する
2。メインにブレークポイントを追加する
3。メインを分解
4。サブ$ 0xGGGGGGG、%espを確認します
このGGGGGG値が高すぎる場合、私と同じ問題が表示されます。
メインのすべてのローカル変数の合計サイズを確認してください。
あなたはどのプラットフォーム/ libcを言っていません。組み込みの世界では、多くの場合、main()
の前に実行される多くのものがあり、主にプラットフォームのセットアップに関係しており、これはうまくいかない可能性があります。 (実際に、通常のOSでファンキーなリンカースクリプトを使用している場合、すべての賭けはオフになっていますが、それはかなりまれです。)
一部のプラットフォーム抽象化ライブラリーはオーバーライドします(個人的にはQtやACEなどのC++ライブラリーしか知りませんが、これを行うCライブラリーも同様です) "main"。これにより、int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow );
といくつかのライブラリスタッフを設定し、コマンドライン引数を通常の_int argc, char* argv[]
_に変換してから、通常のint main(int argc, char* argv[])
を呼び出します
もちろん、そのようなライブラリは、これを正しく実装しなかった場合にクラッシュする可能性があります(コマンドライン引数の形式が正しくない可能性があります)。
そして、これについて知らない人にとって、これはmain
の前にクラッシュのように見えるかもしれません
確かに、オペレーティングシステムまたはランタイムコードにバグがある場合。 C++はこの動作で特に悪名高いですが、Cでも発生する可能性があります。
スタックのmain
の前にプログラムをクラッシュさせるのに最適な例オーバーフロー:
int main() {
char volatile stackoverflow[1000000000] = {0};
return 0;
}