0

forセグメンテーション違反が発生しました。これをコールバック関数のループに絞り込みました。プログラムが以前は機能していたのに、今は機能していないのは奇妙です!

struct debuggerth_command debuggerth_protocol[] = { /*
    * Note: These strings are NOT null-terminated. The
    * strings are 4 bytes long for memory alignment and
    * integer-cast comparisons.
    */

    { "run ", debuggerth_startprocess },
    { "stop", 0 },
    { "inp ", 0 },
    { "sig ", 0 },
    { 0, 0 }
};

そして、これはコードです:

int debuggerth_callback (struct libwebsocket_context * context,
                    struct libwebsocket * wsi,
                    enum libwebsocket_callback_reasons reason,
                    void * user,
                    void * in,
                    size_t len){

switch (reason) {

case LWS_CALLBACK_RECEIVE:

    if (len < 4){
        /* send error */
        return -1;
    }

    /* Getting a segmentation fault
     * within this loop.
     */

    // I used this break to determine where the seg fault starts
    // break

    int i = 0;
    for (; debuggerth_protocol[i].cmd; i++)
        if (cmpcmd (debuggerth_protocol[i].cmd, in)) break;


    //break;

    if (!debuggerth_protocol[i].cmd){
        int byteswritten = sprintf
            (debuggerth_message,
             debuggerth_format,
             debuggerth_headers[0],
             debuggerth_errors [0]);

         libwebsocket_write (wsi, debuggerth_message,
                                      byteswritten,
                                      LWS_WRITE_TEXT);
         return -1;
    }

    break;

これは文字列比較マクロです:

#define cmpcmd(cmd, str) ((*(int*)(cmd)) == (*(int*)(str)))

誰にもアイデアはありますか?

4

3 に答える 3

3

1 つのアイデア: 文字列が正確に のサイズであるという事実に依存することは、intかなり恐ろしいことです。

多くの場合、人々はそのような巧妙なことをしようとしますが、int型が 8 バイトのプラットフォームに移行するなど、根底にある仮定が変更されたときにひどく噛まれるだけです。

strcmpそのマクロを捨てて、 or strncmp (a)を使用するように書き直します。


他にもいくつかやるべきことがあります。

まず、変数を使用する前に、すべての変数を出力 (またはデバッガーを使用して調べます) します。inNULLである可能性があります。

stopあるいは、 やのような NULL コマンドを呼び出そうとしたりsig、テーブルにないコマンドを取得してiが に等しいときにやみくもに呼び出したりすることもあります4。これらの特定の可能性は、ループに続く、示されていないコードにあるため、それは純粋です。


別の可能性として、アラインされていないアクセスを許可しないアーキテクチャで実行していることが考えられます。一部のアーキテクチャは、特定の境界 (32 ビットでアラインされたアドレスから 32 ビット値を取得するなど) でのアクセス用に最適化されており、そのアラインメントに違反すると実行が遅くなります。

ただし、一部のアーキテクチャでは、アラインされていないアクセスがまったく許可されず、試行すると BUS エラーのようなものが発生します。

ARM を使用していることをコメントで示したので、ほぼ間違いなくそうです。詳細については、こちらを参照してください。

その場合は、トリッキーなマクロを取り除き、より従来型のソリューションを使用することをお勧めします


(a) : これは技術的に未定義の動作である可能性があるため、ある時点で「厳密なエイリアシング」という用語を調査することもできます。

于 2013-06-12T04:40:58.917 に答える
0

これがARMで実行されていることを考えると、あなたの問題は、整列されていないメモリアクセスを行っていることであり、失敗するか、非常に遅くなると思います。正確にはセグフォルトではありません。 たとえば、この質問を参照してください。示唆されているように、-Wcast-alignおそらくリスクがあるとフラグが立てられます。ソフトウェアの回避策を有効にすることはできますが、コードで修正するよりもおそらく遅くなります。

1つのオプションはmemcmp、整列されている場合、どのgccが単語の読み取りとほぼ同じくらい単純なものにコンパイルできるかを使用することです。

パフォーマンスが重要な場合の別のオプションは、ループをコマンドの最初のバイトで切り替える case ステートメントに巻き戻すことです。次に、次の文字が期待どおりであることを確認してください。

于 2013-06-12T05:10:43.357 に答える
0

@Jonothan Lefflerが提案したように、コードの変更のいくつかを見ました。これは私が行った変更です:

struct debuggerth_command {
    char * cmd;
    int (*function)(struct debuggerth_session *, char * input);
};

struct debuggerth_command {
    char cmd[4]; // changed this an array
    int (*function)(struct debuggerth_session *, char * input);
};

したがって、ここで構造を初期化すると、次のようになります。

struct debuggerth_command debuggerth_protocol[] = { /*
    * Note: These strings are NOT null-terminated. The
    * strings are 4 bytes long for memory alignment and
    * integer-cast comparisons.
    */

    { "run ", debuggerth_startprocess },
    { "stop", 0 },
    { "inp ", 0 },
    { "sig ", 0 },
    { 0, 0 } /* Zero used to be a pointer value,
              * but now it's the first element in a 
              * 4 byte array
              */
};

forループの評価を変更したもの:

int i = 0;
for (; debuggerth_protocol[i].cmd; i++)
    if (cmpcmd (debuggerth_protocol[i].cmd, in)) break;

は 4 バイト配列への有効なポインタになったため、常に true と評価されます。cmdその最初の値は0です。

一部のアーキテクチャではうまく機能しない可能性があるため、マクロを削除します。でも、これはC11alignas機能を使って直せませんか?

于 2013-06-12T05:32:12.370 に答える