2

小さなコンピューター言語用の仮想マシンを作成しています。この仮想マシンは、GNU ユーティリティ Flex を使用して C で開発されています。したがって、プロジェクトのコンパイルは GNU GCC を使用してから Flex を使用します。

この仮想マシン内に、GC Stop & Copy があります。私の変更の前は、GC のワーキング メモリは拡大できませんでした。たとえば、最初のフリップで新しい割り当てを行うために使用されるスペースが最適化されていない場合、512 バイトから 1024 バイトになりました。

この変更は機能しているように見えました。実際、これらの変更以降、実際に機能したかどうかはわかりませんが、今はバグがあります。最初のフリップで登場しました。確かに、データのコピーに関しては、変化する定数変数があります。しかし、この変数はコピーしたい項目を指しているので重要です。Stop & Copy では、この変数を使用してスロット(ここではSLOT_FORWARD) を変更し、メモリ内のデータの新しい位置を通知します (まだコピーする場合)。

そのため、メモリ内の位置が variable によって指定されている前のコンテナーの各ボックスをコピーするループがありますold。そして、位置から満たされる新しいコンテナがありaddrます。しかし、古い値は反復中に変更されます! コピー後、スロットを前方に変更して、新しいコンテナーのアドレスを配置したいと考えています。しかし、時代が変わったので、私がこの値を間違った場所に記録していることは想像に難くないでしょう。

そのため、これが非常にまれにしか発生しないケースのデバッグに長い時間を費やしました (3 ~ 4 個のコンテナーで 2 回フリップした後に発生することがあります)。GDB を使用して、デバッグ関数の 1 つで値が変更されたことを認識します (デバッグ関数を追加することで値も修正されました)。次に、コンパイラー (clang から gcc) を変更して GDB を再起動し、値を変更したのが中括弧文字 (まだデバッグ関数内) であることを確認しましたconst...ファイルの 37 行目で値が変更されていると言われましたiofwrite.c。したがって、別世界の間違いです。

バグがここにある問題のコード:

static t_case
copy(t_dono *dono, const t_case old)
{
  t_case  addr;
  t_case  size;
  t_case  temp;
  int     i;

  temp = old;

  if (mem[old + SLOT_FORWARD] >= ns
      && mem[old + SLOT_FORWARD] <= ts)
    return (mem[old + SLOT_FORWARD]);
  else
    {
      addr = mp;
      size = mem[old + SLOT_SIZE];
      i = 0;

      fprintf(stderr, "change:\t");
      dump(stderr, mem, old);

      assert(old == temp);

      while (i < size)
        {
          fprintf(stderr, "!!!COPY:\t");
          dump(stderr, mem, old);
          assert(old == temp);
          mem[addr + i] = mem[old + i]; /* BUG IS HERE */
          i = i + 1;
        }

      mem[old + SLOT_FORWARD] = addr;
      fprintf(stderr, "change:\t");
      dump(stderr, mem, old);
      assert(old == temp);
      mp = mp + size;

      return (addr);
    }
}

ご覧のとおり、エラーをターゲットにするために多くのデバッグを行い、次のログ ファイルを取得しました。

ref:            [ 0005 0001 0003 0004 0035 ]
copy:           [ 0007 0001 0003 0004 0075 0001 00f9 ]
change:         [ 0007 0001 0003 0004 0075 0001 00f9 ]
!!!COPY:        [ 0007 0001 0003 0004 0075 0001 00f9 ]
!!!COPY:        [ 0007 0001 0003 0004 0075 0001 00f9 ]
!!!COPY:        [ 0007 0001 0003 0004 0075 0001 00f9 ]
!!!COPY:        [ 0003 0001 0003 ]
!!!COPY:        [ 0003 0004 0003 ]
!!!COPY:        [ 0003 0004 0075 ]
!!!COPY:        [ 0003 0004 0075 ]
change:         [ 0003 0033 0075 ]

また、Valgrind を使用すると、多くのエラーが発生しましたが、このバグの後でのみ発生しました (GC がランダム データにアクセスするため、これは正常です)。この変数の変更中、エラーはまったくありません。

関数 copy (l: 662) を通過する他のコンテナーでは、この未定義の動作が発生しないことがわかります (ログ ファイルの 10、48、54、66、82、120、126、および 134 行を参照)。すべてがうまくいかないのは実行時だけであり、もちろんすべての GC データに誤りがあります。

目的は 1 つのファイル C で VM を実行することであるため、コードは非常に長くなります (約 1000 行)。しかし、問題は魔法のように現れるだけで、私はさらに進んで Python を超える未来の言語を作ることができません (冗談)。

リポジトリのリンク: git.osau.re
変更のリンク: ompldr

敬具。

4

1 に答える 1