多次调用 gethostbyname 什么时候不安全?

When would multiple calls to gethostbyname be unsafe?

来自 gethostbyname(3) - Linux 手册

The functions gethostbyname() and gethostbyaddr() may return pointers
to static data, which may be overwritten by later calls.  Copying the
struct hostent does not suffice, since it contains pointers; a deep
copy is required.

我编写了多次调用 gethostbyname 的程序,并且没有因为覆盖静态数据而导致任何中断。

当多次调用 gethostbyname 会覆盖此静态数据时,我可以问一个例子吗?

struct hostent *host1 = gethostbyname("host1");
struct hostent *host2 = gethostbyname("host2");

if(host1......)

第二次调用覆盖了(可能)第一次调用的结果

这样操作会出问题:

struct hostent *google = gethostbyname("www.google.com");
struct hostent *youtube = gethostbyname("www.youtube.com");

printf("Official name of host for www.google.com: %s\n", google->h_name);
printf("Official name of host for www.youtube.com: %s\n", youtube->h_name);

printf("same? %s\n", google == youtube ? "yes" : "no");

输出将是

Official name of host for www.google.com: youtube-ui.l.google.com
Official name of host for www.youtube.com: youtube-ui.l.google.com
same? yes

这是错误的,因为 www.google.com 的官方主机名是 www.google.com 而不是 youtube-ui.l.google.com。问题是 googleyoutube 指向同一位置(正如您从 same? yes 输出中看到的那样), 因此,当您再次执行 gethostbyname 时,有关 www.google.com 的信息将丢失。

如果你这样做

struct hostent *google = gethostbyname("www.google.com");
printf("Official name of host for www.google.com: %s\n", google->h_name);

struct hostent *youtube = gethostbyname("www.youtube.com");
printf("Official name of host for www.youtube.com: %s\n", youtube->h_name);

那么输出将是

Official name of host for www.google.com: www.google.com
Official name of host for www.youtube.com: youtube-ui.l.google.com

所以只要处理第一个gethostbynamehostent指针 在你打第二个电话之前打个电话,你会没事的。

这是一个例子:

struct hostent *he1 = gethostbyname("host1");
struct in_addr *addr1 = (struct in_addr *)(he1->h_addr);

printf("addr1=%s\n", inet_ntoa(*addr1));    // prints IP1

struct hostent *he2 = gethostbyname("host2");
struct in_addr *addr2 = (struct in_addr *)(he2->h_addr);

printf("addr2=%s\n", inet_ntoa(*addr2));    // prints IP2

printf("addr1=%s\n", inet_ntoa(*addr1));    // prints IP1 (!)