ned14/status-code

Issue compiling on arm-none-eabi (newlib) with GNU extensions off

CrustyAuklet opened this issue · 4 comments

I'm using experimental outcome in a bare metal ARM cortex-m project. The code is using C++20 and I wanted to change it to -std=c++20 instead of -std=gnu++20 but this causes Outcome to no longer compile.

Compiler: arm-none-eabi-11.3.1-rel1 (latest ARM provided toolchain)
arch: ARM-v8M-baseline (M23)

I traced the issue to the following snippet:
https://github.com/ned14/outcome/blob/94035926674a6db75152a98981a400f074c91534/single-header/outcome-experimental.hpp#L9066-L9081

The code in newlib looks like this:

/* There are two common strerror_r variants.  If you request
   _GNU_SOURCE, you get the GNU version; otherwise you get the POSIX
   version.  POSIX requires that #undef strerror_r will still let you
   invoke the underlying function, but that requires gcc support.  */
#if __GNU_VISIBLE
char	*strerror_r (int, char *, size_t);
#elif __POSIX_VISIBLE >= 200112
# ifdef __GNUC__
int	strerror_r (int, char *, size_t)
#ifdef __ASMNAME
             __asm__ (__ASMNAME ("__xpg_strerror_r"))
#endif
  ;
# else
int	__xpg_strerror_r (int, char *, size_t);
#  define strerror_r __xpg_strerror_r
# endif
#endif

/* Reentrant version of strerror.  */
char *	_strerror_r (struct _reent *, int, int, int *);

With GNU extensions on the function int strerror_r (int, char *, size_t); is available, but with GNU extensions off
we are only left with char* _strerror_r (struct _reent *, int, int, int *);

I fixed this in my vendored copy by adding an additional macro branch based on __GNU_VISIBLE

...
#elif __GNU_VISIBLE
    strerror_r(c, buffer, sizeof(buffer));
#else
    char *s = strerror(c);  // NOLINT
    if(s != nullptr)
    {
      strncpy(buffer, s, sizeof(buffer)); // NOLINT
      buffer[1023] = 0;
    }
#endif
ned14 commented

strerror_r is not racy unlike strerror so I can't replace as you suggest. Can you suggest an alternative fix?

providing a definition works with GNU extensions on and off.

// ensure definition of strerror_r exists when GNU extensions off
char *strerror_r (int, char *, size_t);
#include <outcome/outcome-experimental.hpp>

Other than that the only function available
in all cases is char * _strerror_r (struct _reent *, int, int, int *);. This appears to be the functions that all the other
flavors of strerror are implemented against.

char* strerror_r (int errnum, char *buffer, size_t n)
{
    char *error = _strerror_r (_REENT, errnum, 1, NULL);
    if (strlen (error) >= n)
        return error;
    return strcpy (buffer, error);
}
ned14 commented

Can you check if PR #49 fixes your problem?

Works in my project, thanks!