ランタイム環境は無限ループを検出できますか?


19

ランタイム環境で無限ループを検出し、その後関連するプロセスを停止することは可能でしょうか、またはそのようなロジックを実装することは停止問題を解決することと同等でしょうか?

この質問の目的のために、「無限ループ」を定義して、実行時にプロセスを以前とまったく同じ状態(データを含む)に戻す一連の命令と関連する開始スタック/ヒープデータを意味します。無限ループを開始します。(言い換えると、piの無限に長い10進展開を生成するプログラムは、「無限ループ」に「スタック」しません。反復ごとに、関連付けられたメモリのどこかにpiの桁が増えるためです。)

/programming//q/16250472/1858225から移植)



そうは思いません。入力に制約はありません。
カイルストランド

実際のランタイム環境(JVMなど)について、またはそのようなループを検出するプログラム的に汎用的な方法についての質問はありますか?
ベンジュ

@Benj stackoverflow.com/q/16249785/1858225元の質問(私の質問ではありませんでした)は、実際のランタイム環境(またはOS)についてでした。しかし、それは閉じられたので、私はそれを書き直し、理論的な側面に焦点を移しました。
カイルストランド

OK。私が見る唯一の方法は、いくつかのキーポイントをサンプリングしてそれらのハッシュを作成することです(これはログ出力の最後の行、またはスタックptrなどのCPU状態です)。所定の時間に)マルコフ連鎖で。次に、(正しい「プローブ」を選択することにより)循環ロックを検出できるようになります。また、システムライブラリアクセスをフックし、そのエントリをプローブとして使用することも考えています。お楽しみください;)
ベンジ

回答:


11

ランタイム環境では、次の手順を使用して、このようなループをチェックすることが理論的に可能です。

命令が実行されるたびに、ランタイム環境は実行中のプロセスの状態の完全なイメージ(つまり、レジスタ、PC、スタック、ヒープ、グローバルを含むそれに関連するすべてのメモリ)を作成し、そのイメージをどこかに保存してから、そのプロセスで以前に保存された画像のいずれかに一致するかどうかを確認します。一致する場合、プロセスは無限ループに陥ります。それ以外の場合、次の命令が実行され、プロセスが繰り返されます。

実際、すべての命令の後にこのチェックを実行するのではなく、ランタイム環境は単にプロセスを定期的に一時停止し、状態を保存することができます。プロセスがn個の状態を含む無限ループでスタックしている場合、せいぜいn回のチェックの後、重複した状態が観察されます。

もちろん、これは停止する問題の解決策ではないことに注意してください。ここで区別について議論します

しかし、そのような機能はリソースの膨大な浪費になります。プロセスに関連するすべてのメモリを保存するためにプロセスを継続的に一時停止すると、プロセスの速度が大幅に低下し、非常に高速に大量のメモリを消費します。(しばらくすると古い画像が削除される可能性がありますが、保存できる画像の総数を制限するのは危険です。なぜなら、多数の状態を持つループなど、大きな無限ループは、少なすぎると捕まえられない可能性があるからです。さらに、この機能は、エラーをキャッチする機能が非常に制限され、他のデバッグメソッド(コードをステップ実行するなど)で無限ループを見つけるのが比較的簡単であるため、実際にはそれほどメリットはありません論理エラーの認識)。

したがって、このようなランタイム環境が存在すること、または誰かがキックのためだけにプログラムしない限り、それが存在することを疑います。(私は今やる気があります。)


8
(少なくともチューリングマシンなどの理想的な世界では)プログラムが状態を繰り返さずに無限ループに入る可能性があります。Cループのようなものを考えてくださいfor(i = 0; ; i++) ;
フォンブランド

nn<nn+1

@vonbrand、この特定のループは、この特定の質問の目的のための「ループ」の定義に適合しません(これが、質問自体で定義を明示した理由です)。
カイルストランド

n

たぶん私はあなたの質問を理解していませんでした。私はあなたがそれをするかどうかを判断することが可能であったかどうかを知りたかったと思った任意のプログラムの状態が繰り返されます。いくつかのプログラムが状態を繰り返すかどうを判断できるかどうかを尋ねましたか?
ハックベネット

6

プログラムが外の世界と相互作用しないと仮定しましょう。したがって、プログラムの状態全体をカプセル化することは本当に可能です。(これは、少なくとも入力を行わないことを意味します。)さらに、プログラムが何らかの決定論的環境で実行されているため、各状態に一意の後続があり、ランタイムがスレッド化されていないか、スレッド化されている決定論的にシーケンスに縮小できます。

これらの非常にありそうにないが、理論的には非限定的な仮定の下で、プログラムを複製し、2つの別個のランタイムで実行できます。それぞれがまったく同じ計算を行います。

それでは、そうしましょう。Tortoiseランタイムで1回実行し、同時にHareランタイムで実行します。ただし、Hareランタイムが正確に2倍の速度で動作するように調整します。Tortoiseランタイムが1つのステップを実行するたびに、Hareランタイムは2つのステップを実行します。

npknkknp

テストの総コストは、ステップごとに1つの追加状態と1つの状態比較であり、プログラムが最初のループを完了するために必要なステップの3倍以下で終了します。(カメで1回、ノウサギで2回、合計3回)

私が使用した用語が暗示しているように、これはロバート・フロイドの有名なカメとウサギのサイクル検出アルゴリズムです。


3

私がフロイドのサイクル検出アルゴリズムを提案しようとしていたように、リチの投稿は私にそれを打ち負かしました。ただし、完全な状態の比較を高速化することにより、全体をより実用的にすることができます。

提案されたアルゴリズムのボトルネックは、完全な状態を比較することにあります。これらの比較は通常終了しませんが、最初の違いで早期に停止します。最適化の1つは、過去の違いがどこで発生したかを記憶し、最初に状態のそれらの部分をチェックすることです。たとえば、場所のリストを維持し、完全な比較を行う前にこのリストを確認します。このリストの場所で差異が明らかになったら、比較を(失敗して)停止し、その場所をリストの先頭に移動します。

別の(そして潜在的によりスケーラブルな)アプローチは、増分ハッシュを使用することです。状態の一部が変化したときにハッシュ値がO(1)で簡単に調整できるように、完全な状態の関数を選択します。たとえば、いくつかの大きな素数のmodの状態語の重み付き合計を取り、他の大きな素数のmodの重みなし合計と連結します(異なる重みとモジュラスを持つモジュール式の重み付き平方和もスローできます)。この方法では、ハッシュの更新は各実行ステップでO(1)時間かかり、ヒットするまで比較はO(1)時間かかります。偽陽性(つまり、状態が異なるときにハッシュが一致する)の可能性は非常に低く、これが発生した場合でも、多数の真のネガティブで償却されます(偽ネガティブは不可能です)。

もちろん、実際には、数字piの数字を生成するような状況になる可能性が高くなります。別のよくある可能性は、無限ループがメモリを割り当てることです。その場合、利用可能なすべてのメモリがすぐに使い果たされます。

アルゴリズムとデータ構造に関する私のコースでは、オートグレーダーは、時々無限ループになる学生の提出物に対処する必要があります。これは、30秒のタイムアウトと特定のメモリ制限によって処理されます。どちらも、グレーディングの一部として課すランタイムおよびメモリの予算よりもはるかに緩やかです。このようなプログラムはかなり遅く実行されるため、真の無限ループ検出を実装することがこのコンテキストで多くの意味をなすかどうかはわかりません(これは状態ハッシュのハードウェアサポートが役立つ可能性がありますが、ここでも追加の使用が必要ですこれを正当化する)。プログラムがタイムアウトしたことを生徒が知っている場合、通常は無限ループを見つけることができます。


2

AProVEができる(Haskellプログラムのサブクラスを含む)、書き換えシステムで終端工具行う静的解析証明非終端プログラムの実際の例を与え、非終了。この手法は非常に強力で、ナローイングと呼ばれる手法の変形を使用して機能します。

私の知る限り、一般的な言語の実際の非終了を検出する作業はあまりありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.