maxmind / libmaxminddb

C library for the MaxMind DB file format

Home Page:https://maxmind.github.io/libmaxminddb/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Misuse of _POSIX_C_SOURCE feature macro

RhodiumToad opened this issue · comments

As a general rule, it's not desirable for a library's public header file(s) to try and define feature macros such as _POSIX_C_SOURCE. The place to do that is either in the compiler flags, or in a private header file.

The reason why it's a problem is that it potentially messes with the namespace/feature choices of clients of the library - but only if they happen to #include "maxminddb.h" before including any standard header. If instead they include it after some other header, that's even worse: the result is undefined.

(I've seen #158 and #267 for some context for why you're defining this, but it remains that you're doing it in the wrong place, in a way that can cause build failures for client code - an example of which I've just spent an hour or two assisting someone to fix.)

Thanks! Do you know of a good reference stating practices around this? From what I've found searching around, it does sound like it is not an ideal spot for it though.

It's been there since the first version of this library, so I'm hesitant to remove it now. I suspect it would cause different breakages for existing users.

I'm guessing that most existing clients don't see a problem (and wouldn't see any effect from fixing it) because the include of maxminddb.h is done after including some system header. While this is undefined in the spec, in practice what it means is that the definition is simply ignored (the usual implementation is to have a header included first by all system headers that checks all feature macros and defines internal visibility flags based on them, so after this point the feature macros themselves are ignored).

(In fact this is the workaround I suggested to the guy with the original problem.)

I can't find a good "best practices" reference. The spec itself says that the values must be defined before including any header (see: https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_02 etc.), which implies defining it either directly in every source file (ugh) or in the compiler options. (Some references discourage using the compiler options on the grounds that the sources should be self-describing.) In practice I see no way that using a private header file (included first in all source files within the project) could fail to work correctly: i.e.

maxminddb_private.h

/* include guards, etc. */
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif

#include "maxminddb.h"
...

Thank you! Yeah, it sounds like removing it would probably be fine then.