lunarmodules/lua-compat-5.3

Problems with detection of strerror_r

hishamhm opened this issue · 3 comments

In my system (Linux, GCC 6.2.0, Glibc 2.24), the latest compat-5.3.c is failing to build:

lua-compat-5.3/compat-5.3.c:36:47: error: operator '!' has no right operand
         (!defined(_GNU_SOURCE) || !_GNU_SOURCE)
                                               ^

My app defines _GNU_SOURCE with #define _GNU_SOURCE with no value, as usual.

Changing that line into (!defined(_GNU_SOURCE)), however, produces this compile-time warning:

In file included from lua-compat-5.3/compat-5.3.h:415:0,
                 from lua-compat-5.3/compat-5.3.c:7:
lua-compat-5.3/compat-5.3.c: In function ‘compat53_strerror’:
lua-compat-5.3/compat-5.3.c:85:10: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration]
   return strerror_r(en, buff, sz);
          ^~~~~~~~~~
lua-compat-5.3/compat-5.3.c:85:10: warning: return makes pointer from integer without a cast [-Wint-conversion]
   return strerror_r(en, buff, sz);
          ^~~~~~~~~~~~~~~~~~~~~~~~

I don't get the warning if I force the defines to use the XSI version:

#define COMPAT53_HAVE_STRERROR_R_XSI 1                                                                       
#define COMPAT53_HAVE_STRERROR_R_GNU 0

Something borked in my setup as well, maybe?

First, it should be !defined(_GNU_SOURCE). At least that's what the official headers use apparently (even though the manpage claims (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE), probably to avoid this exact issue.

Second, we have another problem: It seems that we don't have a reliable way to detect whether we have the GNU version or the POSIX version of strerror_r. Checking the same preprocessor symbols might not do it, because those can change between inclusion of string.h and our tests.

At the moment I'm considering something like the following when a glibc is used:

char buffer[255] = { 0 };  /* zero initialized */
int myerrno = errno;
strerror_r(myerrno, buffer, sizeof(buffer));  /* use either version of strerror_r */
if (buffer[0] != '\0')
  return buffer; /* strerror_r wrote into our buffer */
else
  /* buffer is unchanged, so we probably have GNU strerror_r which returned a
   * static constant string. Chances are that strerror will return the same static
   * constant string and therefore be thread-safe. */
  return strerror(myerrno);

When I find time I'll take a look at the glibc sources to make sure that the last assumption at least holds for the current glibc version.

I'm open to other suggestions.