のマニュアルページを読んでくださいvfork。特に、あなたが子供の中で何をすることが許されているかを教えてくれる部分. getpidお子様をお呼びすることはできません。printfお子様をお呼びすることはできません。変数を設定することはできませんa。子で呼び出した関数から戻ることはできませんvfork。これらすべてのことを行ったので、コードは予期しないことを行います。残念ながら、予期しないことはクラッシュしていません。
:ed 子の関数_exitの 1 つまたは 1 つだけを呼び出すことができます。他には何もありません。exec*vfork
システムコールは、非常に高価だっvforkた時代からの最適化ハックです。forkしたがって、親プロセスを一時停止し、子で親アドレス空間を使用するために何をするか (オペレーティング システムによっては、これが当てはまる場合とそうでない場合があります) は、子プロセスが or を呼び出すまでexec*です_exit。子が行うメモリ書き込みは、親プロセスのメモリを上書きします。関数を呼び出すと、親プロセスが予期しない方法でメモリが上書きされます。呼び出された関数から戻るvforkと、親が無傷であると期待する状態 (戻りアドレスや保存されたスタック ポインターなど) が確実に上書きされます。呼び出しprintfは、親が上書きされることを予期していない stdio バッファーを上書きします。
あなたの場合、すべてのコンピューターが非常に決定論的であるため、子が終了した後に親が再び自分自身を呼び出すのはおそらく理由があるでしょう。main を呼び出す crt コード、libc のさまざまな atexit ハンドラー、およびその他のクリーンアップを分析すると、スタックの適切な場所に何を書き込んで親を混乱させ、その後間違った場所に戻るのかを正確に把握できる可能性があります。システムコールが戻ります。コードを分解して実行してください。または、このサイトで他の何十もの質問を検索して、それらがすべて同じテーマに従っていることvforkに気付くこともできます。ドキュメンテーションで何かをするときは、しないように言われますか?」。それは未定義の動作であり、未定義の動作の動作方法が未定義であるためです。あなたの場合、親が上書きするとは予想していなかったメモリを上書きすると、たまたま親が他のケースでは、printf が 2 回印刷されるのを見たことがある. 他のケースでは何も悪いことは起こらなかった. 他のケースではプログラムがクラッシュした.