2

編集:解決策が見つかりました(下を参照)

Mac OS X 10.8 x86_64 システムでソフトウェア パッケージ ( owfs )をビルドしようとしています。このソフトウェア パッケージは主に Linux 用に開発されていますが、古いバージョンをコンパイルして正しく機能させることができました。インターネット上には、さまざまなバージョンを実行している人々の投稿がたくさんあります。 . コンパイル プロセスを正常に完了することができましたが、プログラムを実行しようとすると segfault が発生します。GDBで調査したところ、次のことがわかりました。

問題のあるコード:

void FS_dir_entry_aliased(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn)
{
if ( ( pn->state & ePS_unaliased ) == 0 ) {
    // Want alias substituted
    struct parsedname s_pn_copy ;
    struct parsedname * pn_copy = & s_pn_copy ;

    ASCII path[PATH_MAX+3] ;
    ASCII * path_pointer = path ; // current location in original path

    // Shallow copy
    memcpy( pn_copy, pn, sizeof(struct parsedname) ) ;
    pn_copy->path[0] = '\0' ;

    // path copy to use for separation
    strcpy( path, pn->path ) ;

    // copy segments of path (delimitted by "/") to copy
    while( path_pointer != NULL ) {
                    ASCII * path_segment = NULL;
        path_segment = strsep( &path_pointer, "/" ) ;
        BYTE sn[SERIAL_NUMBER_SIZE] ;

        if ( PATH_MAX < strlen(pn_copy->path) + strlen(path_segment) ) {

が範囲外のアドレスであるためstrlen(path_segment)、ブロック内のへの呼び出しはif失敗します。path_segment

GDB で一歩一歩物事を進めると、ここに私が見つけたものがあります。で初期化する呼び出しに入るpath_segmentstrsep、gdb は次のようになります。

path_pointer = (ASCII *) 0x7fff5fbf99a5 "/uncached/bus.0/interface"

次の行を実行すると、path_pointer期待どおりに進みました。

path_pointer = (ASCII *) 0x7fff5fbf99a6 "uncached/bus.0/interface"

しかし、gdb レポート:

path_segment = (ASCII *) 0x5fbf99a5 <Address 0x5fbf99a5 out of bounds>

これはアドレスの正しい「開始」ですが、32 ビットのポインター アドレスです。私のシステムは 64 ビット システムなので、strlenこれを呼び出すと、EXC_BAD_ACCESS が返されます。

ここで多くのことが起こっていることは理解していますが、問題がパッケージのビルド プロセスに深く潜んでいる場合は、十分な情報を提供できませんでした。関数は基本的に正しく動作していますが、間違ったサイズのポインターを返すだけなので、これには簡単な解決策があるように思えます。ただし、64 ビット システムと 32 ビット システムの複雑さについての経験はほとんどありません。そのため、誰かが明らかなことを見つけたり、この問題をデバッグする次のステップの指示を提供したりできるかどうか疑問に思っていました。興味深いことに、strsepgdb ( p (ASCII *) strsep (&path_pointer, "/")) で手動でコマンドを実行すると、正常に動作しているように見え、期待どおりの 64 ビット ポインターが得られます。

最後に、便利な場合に備えて、 strsep呼び出しのアセンブリ ラインは次のとおりです。

0x0000000100036eee <FS_dir_entry_aliased+318>:  callq  0x1000a56a0 <dyld_stub_strsep>
0x0000000100036ef3 <FS_dir_entry_aliased+323>:  mov    %eax,%ecx
0x0000000100036ef5 <FS_dir_entry_aliased+325>:  movslq %ecx,%rcx
0x0000000100036ef8 <FS_dir_entry_aliased+328>:  mov    %rcx,-0x1d10(%rbp)

そのcallqアドレスにあるstrsepの逆アセンブル:

0x00007fff915c0fc7 <strsep+0>:  push   %rbp
0x00007fff915c0fc8 <strsep+1>:  mov    %rsp,%rbp
0x00007fff915c0fcb <strsep+4>:  mov    (%rdi),%r8
0x00007fff915c0fce <strsep+7>:  xor    %eax,%eax
0x00007fff915c0fd0 <strsep+9>:  test   %r8,%r8
0x00007fff915c0fd3 <strsep+12>: je     0x7fff915c1007 <strsep+64>
0x00007fff915c0fd5 <strsep+14>: mov    %r8,%r10
0x00007fff915c0fd8 <strsep+17>: jmp    0x7fff915c0fe4 <strsep+29>
0x00007fff915c0fda <strsep+19>: inc    %rdx
0x00007fff915c0fdd <strsep+22>: test   %al,%al
0x00007fff915c0fdf <strsep+24>: jne    0x7fff915c0fee <strsep+39>
0x00007fff915c0fe1 <strsep+26>: mov    %r9,%r10
0x00007fff915c0fe4 <strsep+29>: mov    (%r10),%cl
0x00007fff915c0fe7 <strsep+32>: lea    0x1(%r10),%r9
0x00007fff915c0feb <strsep+36>: mov    %rsi,%rdx
0x00007fff915c0fee <strsep+39>: mov    (%rdx),%al
0x00007fff915c0ff0 <strsep+41>: cmp    %cl,%al
0x00007fff915c0ff2 <strsep+43>: jne    0x7fff915c0fda <strsep+19>
0x00007fff915c0ff4 <strsep+45>: xor    %edx,%edx
0x00007fff915c0ff6 <strsep+47>: test   %cl,%cl
0x00007fff915c0ff8 <strsep+49>: je     0x7fff915c1001 <strsep+58>
0x00007fff915c0ffa <strsep+51>: movb   $0x0,(%r10)
0x00007fff915c0ffe <strsep+55>: mov    %r9,%rdx
0x00007fff915c1001 <strsep+58>: mov    %rdx,(%rdi)
0x00007fff915c1004 <strsep+61>: mov    %r8,%rax
0x00007fff915c1007 <strsep+64>: pop    %rbp
0x00007fff915c1008 <strsep+65>: retq

編集: string.h は間違いなく含まれています。それを含むシステム全体のインクルード ファイルがありますが、この特定のファイルを追加しようとしたことを確認するためです。-D_BSD_SOURCE=1は、自動的に追加されるコンパイラ オプションの 1 つです。-D_ISOC99_SOURCE=1デフォルトでコンパイラオプションもあります。追加しようとしましたが-std=gnu99(私のコンパイラであるllvm-gcc 4.2は好きではありません-std=gnu90)、修正しませんでした。次のコンパイラ エラーが発生します。

このファイルに対して表示されるコンパイラの警告は次のとおりです。

ow_alias.c: In function 'ReadAliasFile':
ow_alias.c:40: warning: implicit declaration of function 'getline'
ow_alias.c:48: warning: implicit declaration of function 'strsep'
ow_alias.c:48: warning: assignment makes pointer from integer without a cast
ow_alias.c:64: warning: assignment makes pointer from integer without a cast
ow_alias.c: In function 'FS_dir_entry_aliased':
ow_alias.c:177: warning: initialization makes pointer from integer without a cast

2番目の編集:もう少し掘り下げた後(gcc -E | grep strsepヒントをありがとう!)、問題はコンパイラフラグにあることがわかりました-D_POSIX_C_SOURCE=200112L。このコンパイラ フラグは strsep の定義をブロックしていたため、コンパイラは暗黙の宣言を行っていました。これを構成スクリプトから削除したところ、すべて正常に動作しているようです。助けてくれてありがとう!

4

1 に答える 1

5

が含まれていることを確認する必要がありますstring.h

それがすでに行われている場合は、機能テスト マクロを定義して の宣言を有効にする必要がありますstrsep()。追加する-D_GNU_SOURCE-D_BSD_SOURCE、トリックを行う必要があります。ただし、現在どのように構成されているかを調べたい場合があります-_BSD_SOURCE通常はデフォルトで有効になっています. おそらく、gcc に-std=c90orを使用してコンパイルするように指示している-std=c99可能性があります。これにより、多くの機能テスト マクロがオフになります。代わりに-std=gnu90またはを使用してください。-std=gnu99

「初期化により、キャストなしで整数からポインターが作成されます」または「関数の暗黙の宣言」などの警告が表示されますか?

于 2012-12-12T09:51:00.407 に答える