0

NetBSD のソースコードを読んで「コードを読む」ことを勉強しています。
(興味のある方は < Code Reading: The Open Source Perspective > を読んでいます)

そして、私はこの機能を見つけました:

/* convert IP address to a string, but not into a single buffer
*/
char *
naddr_ntoa(naddr a)
{
#define NUM_BUFS 4
    static int bufno;
    static struct {
    char str[16];   /* xxx.xxx.xxx.xxx\0 */
    } bufs[NUM_BUFS];
    char *s;
    struct in_addr addr;

    addr.s_addr = a;
    strlcpy(bufs[bufno].str, inet_ntoa(addr), sizeof(bufs[bufno].str));
    s = bufs[bufno].str;
    bufno = (bufno+1) % NUM_BUFS;
    return s;
#undef NUM_BUFS
}

inet_ntoa は再入可能ではないため、inet_ntoa 関数をラップするために 4 つの異なる一時バッファーが導入されています。
しかし、私には、この naddr_ntoa 関数も再入
可能ではないように思えます。静的な bufno 変数は他のユーザーによって操作される可能性があるため、ここでは一時バッファーが期待どおりに機能しないようです。

それで、それは潜在的なバグですか?

4

2 に答える 2

2

はい、これは潜在的なバグです。再入可能である可能性が最も高い同様の関数が必要な場合は、たとえばinet_ntop(ちなみに、IPv6も処理します)を使用できます。

于 2012-09-20T06:11:56.620 に答える
0

そのコードはsrc/sbin/routed/trace.c、一般的なライブラリ ルーチンではなく、ルーティングされたプログラムでのみ使用されるカスタム ハックから派生したものです。同じファイル内のaddrname()関数は、同じ理由で同じトリックを利用しています。それ自体は NetBSD コードでさえありませんが、元々は SGI から来ており、Vernon Schryver によって保守されています ( The Routed Pageを参照)。

結果が 1 つの printf() 呼び出しで使用されている場合など、同じ式内で複数の呼び出しを使用できるようにするための簡単なハックです。

printf("addr1->%s, addr2->%s, addr3->%s, addr4->%s\n",
       naddr_ntoa(addr1), naddr_ntoa(addr2), naddr_ntoa(addr3), naddr_ntoa(addr4));

ルーティングされたソース ファイル (if.​​c、input.c、rdisc.c) には、同様の使用例がいくつかあります。

このコードにはバグはありません。ルーティングされたプログラムはマルチスレッドではありません。このハックでは、再入可能性はまったく扱われていません。このトリックは、再入可能性とは関係のない非常に特定の目的のために設計されています。コード リーディングの作成者は、このトリックを再入可能性と関連付けるのが間違っています。

これは、単一の式に複数の結果が必要な場合に、1 つの静的変数から呼び出し元の関数の別のストレージに結果を個別にコピーする代わりに、静的変数の配列に複数の結果を保存することを非表示にする方法にすぎません。

静的変数には、識別子の限定されたスコープを除いて、グローバル変数のすべてのプロパティがあることに注意してください。もちろん、関数内でグローバル (または静的) 変数を保護せずに使用すると、その関数が再入不可になることは事実ですが、グローバル変数が引き起こす問題はそれだけではありません。完全に再入可能な関数の使用は、実際にはコードを必要以上に複雑にするため、routed では適切ではありませんが、このハックは呼び出しコードをクリーンでシンプルに保ちます。NUM_BUFSただし、将来のメンテナがいつ調整する必要があるかをより簡単に見つけられるように、ハックが適切に文書化されている方がよいでしょう。

于 2012-11-11T02:14:13.947 に答える