1

私はこの問題に無作為に悩まされており、何が原因なのかわかりません。

多数の変数、ポインター、および配列を宣言する関数があります。しかし、新しい変数を宣言すると、ある時点でプログラムがクラッシュするようです。クラッシュした場合でも、一貫性がないようです。以下の関数のコードで、変数 b を int として宣言するとプログラムがクラッシュしますが、int b[10] として宣言するとクラッシュしません。

大量のコードで申し訳ありませんが、何か不足している場合に備えて、関数全体を提供したかったのです。私が参照している変数 b は一番上にあります。

ある種のメモリの問題であると思われますが、私が見たものは実際には一貫していないようです.

static should_inline void decode_image_internal(PictureDecoderData* pdd, FILE* outfile)
{
  unsigned int mb_row;
  unsigned int mb_col;
  unsigned int mb_idx;
  unsigned int i;
  unsigned int j;
  unsigned int b[10];
  unsigned char topy[30720];
  unsigned char topcb[7680];
  unsigned char topcr[7680];

  Picture* pic = pdd->pic;
  unsigned int bottom_field_flag = pdd->prev_sh->bottom_field_flag; // TODO: remove the     use of prev_sh since it really depends on the pdd decoding context.
  slice_header_t* slice0 = pic->field_sh[bottom_field_flag][0]; // get a slice header.   It is used for variables that are the same for the whole picture
  seq_parameter_set_rbsp_t* sps = slice0->sps;
  pic_parameter_set_rbsp_t* pps = slice0->pps;
  int PicWidthInMbs = sps->PicWidthInMbs;
  unsigned int PicWidthY = PicWidthInMbs * 16;
  unsigned int PicHeightInMbs = slice0->PicHeightInMbs;
  unsigned int PicSizeInMbs = PicWidthInMbs*PicHeightInMbs;
  int CurrMbAddr;
  MbAttrib* mb_attr = pic->field_data[bottom_field_flag].mb_attr;
  MbAttrib* curr_mb_attr;
  unsigned int mbc_width = MbWidthC[1];
  unsigned int mbc_height = MbHeightC[1];
//  unsigned int mbc_size = mbc_width*mbc_height;
  unsigned int PicWidthC = PicWidthInMbs * mbc_width;
  int clipY = (1<<sps->BitDepthY)-1;
  int meanY = 1<<(sps->BitDepthY-1);
  int clipC = (1<<sps->BitDepthC)-1;
  int meanC = 1<<(sps->BitDepthC-1);
  int mb_data_size = (256+2*MbSizeC[1]);
  int16_t* mb_data = pic->field_data[bottom_field_flag].data;
  int16_t* curr_mb_data;
  unsigned int field_pic_flag = slice0->field_pic_flag;
  unsigned int strideY = PicWidthY << field_pic_flag;
  unsigned int strideC = PicWidthC << field_pic_flag;
  slice_header_t* sh;
  unsigned int constrained_intra_pred_flag = pps->constrained_intra_pred_flag;

  pixel_t* Y;
  pixel_t* C[2];
  pixel_t* y;
  pixel_t* c[2];

  Y = (pixel_t*)((uint32_t)pic->Y + (bottom_field_flag!=0)*PicWidthY);
  C[0] = (pixel_t*)((uint32_t)pic->C[0]+ (bottom_field_flag!=0)*PicWidthC);
  C[1] = (pixel_t*)((uint32_t)pic->C[1]+ (bottom_field_flag!=0)*PicWidthC);


  for (j = 0; j<=pic->slice_num[bottom_field_flag]; j++)
  {
    sh = pic->field_sh[bottom_field_flag][j];
    CurrMbAddr = sh->first_mb_in_slice;

    //for (i = 0; i<sh->mb_nb; i++)
     for (i = 0; i<2; i++)
    {
      pixel_t ysamp[256], cbsamp[8*8], crsamp[8*8];
      mb_row = (CurrMbAddr) / PicWidthInMbs;
      mb_col = (CurrMbAddr) % PicWidthInMbs;
      mb_idx = (CurrMbAddr);
      curr_mb_attr = &mb_attr[mb_idx];
      curr_mb_data = mb_data + mb_idx * mb_data_size;
     // printf(" %d %d \n ",strideY, mb_row);
      y = Y + mb_col*16 + mb_row*strideY*16;
      c[0] = C[0] + mb_col*mbc_width + mb_row*strideC*mbc_height;
      c[1] = C[1] + mb_col*mbc_width + mb_row*strideC*mbc_height;


        {
          MB_TYPE mb_type = curr_mb_attr->mb_type;
          unsigned int mb_field_decoding_flag = curr_mb_attr->mb_field_decoding_flag;
          pixel_t* mb_C_samples[2];

          mb_C_samples[0] = c[0];
          mb_C_samples[1] = c[1];


          //if (mb_type <= SI) // Intra mb
            decode_intra_mb(curr_mb_attr, mb_type, curr_mb_data, 1920, 960, y, mb_C_samples[0], mb_C_samples[1],
            ysamp, cbsamp, crsamp,
            mbc_height, mbc_width, clipY, clipC, meanY, meanC, mb_field_decoding_flag, mb_row&1, PicWidthInMbs, 0,
            constrained_intra_pred_flag);

            rgbconvert(ysamp, cbsamp, crsamp, outfile);


        }

      CurrMbAddr = NextMbAddress(sh->MbToSliceGroupMap, CurrMbAddr, PicSizeInMbs, pps->num_slice_groups_minus1);
    }

  }


  // Release the ref picture it was using
  release_picture_refpics(pic, bottom_field_flag); // it is OK even when the pic is a frame because both field points to the same lists

  filter_image(pic, bottom_field_flag);

  // Output the picture !
  add_image_to_dpb(pic);
}

どんなガイダンスも大歓迎です!

編集*返信してくれてありがとう!スタックの破損が正解でした。私はそれを修正する途中です。

4

4 に答える 4

2

スタックに大きすぎる配列を割り当てることは悪い考えです。スタックはこれを意図したものではなく、スタック メモリがすぐに不足してしまいます。さらに悪いことに、このような問題を制御して把握することは困難です。

代わりに、大量のメモリをheapに割り当てる必要があります。そこにははるかに多くのメモリがあります (ただし、もちろん無限ではありません!)

要するに交換

unsigned char topy[30720];

unsigned char* topy = (char*)malloc(30720);

はるかに優れている必要があり、おそらく問題を解決します。free(topy)必要がなくなったら、割り当てられたメモリ ( ) を解放することを忘れないでください。

UPD : もちろん、これらは一般的な推論であり、特殊なケース (組み込みシステムなど) には適用されません。

于 2013-02-22T10:13:34.043 に答える
1

変数 b を int として宣言するとプログラムがクラッシュしますが、int b[10] として宣言するとクラッシュしません。

明らかな理由は、後者では 10 倍のメモリを予約することになるからです。bただし、どこでも使用しているようには見えないため、ほぼ確実に他の場所でメモリをオーバーランしています。違いは、余分なメモリを予約することで、バグが重要なものを上書きするのを防ぐことです (プログラムがデバッグ下でのみ動作する場合と同じ)。

問題は、これがプログラムの一部にすぎないことです。他の関数を呼び出して引数として渡されたデータを使用しているため、実際のエラーは別の場所にある可能性があります。

bottom_field_flagチェックすべき明らかな値です。

どのタイプのクラッシュが発生するかについては言及していません。これは、解決をさらに進めるために重要です。たとえば、スタック オーバーフローが発生し、Windows を使用している場合は、コンパイラのスタック サイズ設定を確認する必要があります (Visual Studio の /F とリンカー オプションだと思います)。

于 2013-02-22T10:23:49.733 に答える
0

どのオペレーティングシステム?これがWindows上にある場合、コンパイラが 4k を超えるローカルを持つ関数をいつ確認せずに挿入する chkstk ルーチンが原因である可能性が最も高いです。-nostdlibを使用した場合、これは失敗します。

于 2013-02-22T10:11:35.547 に答える
0

Valgrind (@nevelis が提案) は、このような問題を解決するための非常に良いアイデアです。

もう 1 つのオプションは、デバッガー ( gdb ) を使用してアプリケーションを実行し、クラッシュを待ってバック トレースを確認することです。

gdb のコマンドは次のとおりです。

run

そしてクラッシュ後:

bt

スタックサイズ(自動変数)も減らすべきだと思います。スタック上の 44K は良い考えとは思えません。

于 2013-02-22T10:14:19.333 に答える