昨日、getnameinfo の問題について述べたが、 念のため、glibc のソースを確認してみた。 手元に展開してあった glibc-2.3.5 を見ると、 glibc-2.3.5/inet/getnameinfo.c の 440行目で、
case AF_LOCAL: strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen); break;
とある。sun_path が 0 終端されていないと、 sun_path が実際に何バイト確保されているかとは関係なく、 servlen バイトがコピーされてしまう。
getnameinfo の salen 引数のチェックは、 同じく getnameinfo.c 182行目の、
case AF_LOCAL: if (addrlen < (socklen_t) (((struct sockaddr_un *) NULL)->sun_path)) return EAI_FAMILY; break;
だけであった。 つまり sun_path の部分が 0 バイトでもエラーにならない。
今回の問題とは関係ないが、
(socklen_t) (((struct sockaddr_un *) NULL)->sun_path))
という書き方は参考になる。 stone.c では
(((struct sockaddr_un*)sa)->sun_path - (char*)sa)
と書いていたのだが、 NULL を使えば簡潔に書ける、 というのは目から鱗だった。