Macos man 3 getaddrinfo is wrong
I stumbled across an old project where I was porting Beej’s guide to network programming to Fortran and was reminded of some pain I endured during that effort due to apparently inaccurate macos manpages.
Typically when working with getaddrinfo and the addrinfo struct, whether in linux or *bsd you don’t have to worry
too much about how things are actually laid out in memory, you just read/write to the struct’s fields as provided by the API.
But when trying to accomplish the same in Fortran, I had to manually set up this struct, which required knowing the actual layout so that I could mirror it in Fortran. You can see that here.
I started out, naturally, by consulting the man page which you can do on macos with man 3 getaddrinfo.
This will return the following excerpt:
struct addrinfo {
int ai_flags; /* input flags */
int ai_family; /* protocol family for socket */
int ai_socktype; /* socket type */
int ai_protocol; /* protocol for socket */
socklen_t ai_addrlen; /* length of socket-address */
struct sockaddr *ai_addr; /* socket-address for socket */
char *ai_canonname; /* canonical name for service location */
struct addrinfo *ai_next; /* pointer to next in list */
};
Note the order of the last 3 pointer fields: ai_addr, ai_canonname, and ai_next.
Try as I might, I could not get this to work, it would crash with a segfault every time. Eventually I broke out lldb (macos’ default debugger instead of gdb) and fairly quickly noticed that the layout in the man page was just wrong: the order of ai_canonname and ai_addr are switched, ai_canonname should be first.
Making that change fixed all of the problems haha no of course it did not, IIRC it would still crash in some cases that I could not reliably reproduce and so gave up trying to fix, as the itch had been scratched.
Interestingly, if you consult what I believe is the source code it shows the expected layout: netdb.h from Libinfo:
struct addrinfo {
int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
int ai_family; /* PF_xxx */
int ai_socktype; /* SOCK_xxx */
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
socklen_t ai_addrlen; /* length of ai_addr */
char *ai_canonname; /* canonical name for hostname */
struct sockaddr *ai_addr; /* binary address */
struct addrinfo *ai_next; /* next structure in linked list */
};
If git history is correct, this docs bug has been around since at least 2005. I looked into opening a PR to fix this, but the Libinfo repo does not allow PRs from internet randos, probably sensibly.