9

楽しみのために C で仮想マシンを作成しています。ラメ、私は知っていますが、幸いなことに私はSOにいるので、誰もからかわないことを願っています:)

私は、(自分の) ASM の行を読み取り、何かを実行する、非常に迅速で汚れた VM を作成しました。現在、3 つの命令しかありません: addjmpend。すべてが順調で、実際に行をフィードできるのはかなりクールです(次のようwrite_line(&prog[1], "jmp", regA, regB, 0);にしてプログラムを実行します:

while (machine.code_pointer <= BOUNDS && DONE != true)
{
    run_line(&prog[machine.cp]);
}

私は C でオペコード ルックアップ テーブル (効率的ではないかもしれませんが、エレガントです) を使用していますが、すべて正常に動作しているようです。

私の質問は「ベストプラクティス」の質問ですが、正しい答えがあると思います。VM がバイナリ ファイルを読み取って (バイトを に格納unsigned char[])、バイトコードを実行できるようにしています。私の質問は次のとおりです。バイトコードが整形式であることを確認するのは VM の仕事ですか、それとも、吐き出すバイナリ ファイルが整形式であることを確認するのはコンパイラの仕事ですか?

誰かがバイナリファイルを編集して何かを台無しにするとどうなるか(その任意の部分を削除するなど)、私がこれを尋ねるだけです。明らかに、プログラムにはバグがあり、おそらく機能しません。これは VM の問題でもありますか? 私よりずっと頭のいい人たちが、これらの問題の解決策を見つけているに違いありません。

4

6 に答える 6

15

バイトコードが整形式であることを確認するのはVMの仕事ですか、それとも、吐き出すバイナリファイルが整形式であることを確認するのはコンパイラの仕事ですか?

あなたが決めることができます。

ベストプラクティスは、VMに実行前に単一のチェックを実行させることです。コストはプログラムのサイズに比例します。これは、実行中に不安定なことが起こらないことを保証するのに十分なほど洗練されています。次に、バイトコードの実際の実行中に、チェックなしで実行します。ただし、実行前のチェックのアイデアには、非常に高度な分析が必要になる場合があり、パフォーマンスを重視するVMでさえ、実行時にチェックが行われることがよくあります(例:配列の境界)

趣味のプロジェクトでは、物事をシンプルに保ち、命令を実行するたびにVMに健全性をチェックさせます。ほとんどの命令のオーバーヘッドはそれほど大きくはありません。

于 2010-05-12T00:50:21.653 に答える
2

Java でも同じ問題が発生します。思い出すと、その場合、VM はバイトコードが適切な形式であることを確認するためにいくつかのチェックを行う必要があります。そのような状況では、セキュリティ上の問題が発生する可能性があるため、実際には深刻な問題です。誰かが Java バイトコード ファイルを変更して、コンパイラが決して出力しないもの (private別のクラスからの変数へのアクセスなど) を含めることができる場合、機密情報が公開される可能性があります。アプリケーションのメモリに保持されているデータ、またはアプリケーションが許可されるべきではないWebサイトへのアクセスを許可する可能性があります。Java の仮想マシンには、バイトコード検証機能が組み込まれており、可能な限り、このようなことが起こらないようにしています。

さて、あなたの場合、自作の言語が人気を博して普及しない限り、セキュリティ面はそれほど心配する必要はありません。結局のところ、あなた以外の誰があなたのプログラムをハッキングするのでしょうか? それでも、バイトコードが無効な場合に備えて、VM に少なくとも合理的な障害戦略があることを確認することをお勧めします。少なくとも、理解できないものや処理できないものに遭遇した場合は、それを検出してエラー メッセージを表示して失敗する必要があります。これにより、デバッグが容易になります。

于 2010-05-11T23:59:23.393 に答える
2

通常、バイトコードを解釈する仮想マシンには、入力を検証する何らかの方法があります。たとえば、クラス ファイルが矛盾した状態にある場合、Java は VerifyError をスローします。

ただし、プロセッサを実装しているように聞こえますが、プロセッサは低レベルになる傾向があるため、検出可能な無効な状態にする方法が少なくなります。未定義のオペコードを与えることは明らかな方法の 1 つです。実際のプロセッサは、プロセスが不正な命令を実行しようとしたことを通知し、OS がそれを処理します (たとえば、Linux は SIGILL で強制終了します)。

于 2010-05-12T00:02:00.197 に答える
0

VM の実装自体がクラッシュしない限り、VM がエミュレートされたプロセッサを発火させるのは正当なことだと思います。VM の実装者として、ルールを設定できます。しかし、仮想ハードウェア会社に仮想チップを仮想的に購入してもらいたい場合は、エラーをもう少し許容する必要があります。例外を発生させる (実装が難しい) か、プロセッサをリセットする (はるかに簡単) のが良い選択肢かもしれません。または、「文書化されていない」ものを除いて、すべてのオペコードを有効に定義するだけかもしれません。実装をクラッシュさせる以外に、特定されていないことを行います。理論的根拠: (!) VM 実装がゲストの複数のインスタンスを同時に実行する場合、1 つのゲストが他のゲストを失敗させる可能性があるとしたら、それは非常に悪いことです。

于 2010-05-14T12:20:31.310 に答える
0

コンパイラに可能な限り多くのサニティ チェックを実行させることは理にかなっていますが (1 回だけ実行する必要があるため)、[咳] スタック オーバーフロー、配列など、静的解析では検出できない問題が常に存在します。範囲エラーなど。

于 2010-05-11T23:57:39.407 に答える