From: Keith Marshall Date: Mon, 30 Jan 2017 15:12:46 +0000 (+0000) Subject: Implement strerror_r()/strerror_s() API. X-Git-Tag: wsl-5.0-release~12 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;ds=sidebyside;h=e52d64b7f86888d5f318fae98fec0536653093d3;p=mingw%2Fmingw-org-wsl.git Implement strerror_r()/strerror_s() API. --- diff --git a/mingwrt/ChangeLog b/mingwrt/ChangeLog index 8064858..1862aa4 100644 --- a/mingwrt/ChangeLog +++ b/mingwrt/ChangeLog @@ -1,5 +1,19 @@ 2017-01-30 Keith Marshall + Implement strerror_r()/strerror_s() API. + + * mingwex/strerror_r.c: New file; it implements... + (strerror_r): ...this new POSIX.1-2001 conforming function. + + * include/string.h (strerror_s): Add function prototype, subject to... + [_MSVCR80_DLL || _WIN32_WINNT_VISTA]: ...this DLL version dependency; + otherwise implement an inline wrapper function to emulate it, using... + [_POSIX_C_SOURCE > 200112L] (strerror_r): ...this; add prototype. + + * Makefile.in (libmingwex.a): Add strerror_r.$OBJEXT + +2017-01-30 Keith Marshall + Avoid -Wformat noise from snprintf() and vsnprintf() * include/stdio.h (snprintf, vsnprintf): Add inline implementations; diff --git a/mingwrt/Makefile.in b/mingwrt/Makefile.in index 20fd2c5..7593cca 100644 --- a/mingwrt/Makefile.in +++ b/mingwrt/Makefile.in @@ -494,9 +494,8 @@ libmingwex.a: $(addsuffix .$(OBJEXT), glob getopt basename dirname nsleep) libmingwex.a: $(addsuffix .$(OBJEXT), mkstemp mkdtemp cryptnam setenv) libmingwex.a: $(addsuffix .$(OBJEXT), tdelete tfind tsearch twalk) - +libmingwex.a: $(addsuffix .$(OBJEXT), dirent wdirent dlfcn strerror_r) libmingwex.a: $(addsuffix .$(OBJEXT), getdelim gettimeofday) -libmingwex.a: $(addsuffix .$(OBJEXT), dirent wdirent dlfcn) vpath %.s ${mingwrt_srcdir}/mingwex vpath %.sx ${mingwrt_srcdir}/mingwex diff --git a/mingwrt/include/string.h b/mingwrt/include/string.h index a53a71a..ef80f37 100644 --- a/mingwrt/include/string.h +++ b/mingwrt/include/string.h @@ -198,6 +198,35 @@ __CRT_ALIAS size_t strnlen (const char *__text, size_t __maxlen) #endif /* MSVCRT.DLL || pre-MSVCR80.DLL */ #endif /* _POSIX_C_SOURCE >= 200809L */ +#if _POSIX_C_SOURCE >= 200112L +/* POSIX.1-2001 added a re-entrant variant of strerror(), which stores + * the message text in a user supplied buffer, rather than in (possibly + * volatile) system supplied storage. Although inherently thread-safe, + * Microsoft's strerror() also uses a potentially volatile buffer, (in + * the sense that it is overwritten by successive calls within a single + * thread); thus, we provide our own implementation of POSIX.1-2001's + * strerror_r() function, to facilitate the return of non-volatile + * copies of strerror()'s message text. + */ +extern int strerror_r (int, char *, size_t); +#endif + +#if __MSVCRT_VERSION__>=__MSVCR80_DLL || _WIN32_WINNT >= _WIN32_WINNT_VISTA +/* MSVCR80.DLL introduced a safer, (erroneously so called "more secure"), + * alternative to strerror(), named strerror_s(); it was later retrofitted + * to MSVCRT.DLL, from the release of Windows-Vista onwards. + */ +_CRTIMP __cdecl __MINGW_NOTHROW int strerror_s (char *, size_t, int); + +#elif _POSIX_C_SOURCE >= 200112L +/* For the benefit of pre-Vista MSVCRT.DLL users, we provide an approximate + * emulation of strerror_s(), in terms of inline referral to POSIX.1-2001's + * strerror_r() function. + */ +__CRT_ALIAS int strerror_s (char *__buf, size_t __len, int __err) +{ return strerror_r (__err, __buf, __len); } +#endif + #undef __STRING_H_SOURCED__ _END_C_DECLS diff --git a/mingwrt/mingwex/strerror_r.c b/mingwrt/mingwex/strerror_r.c new file mode 100644 index 0000000..4194357 --- /dev/null +++ b/mingwrt/mingwex/strerror_r.c @@ -0,0 +1,89 @@ +/* + * strerror_r.c + * + * Implementation of POSIX standard IEEE 1003.1-2001 strerror_r() function. + * + * $Id$ + * + * Written by Keith Marshall + * Copyright (C) 2016, 2017, MinGW.org Project + * + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +#define _POSIX_C_SOURCE 200112L + +#include +#include +#include +#include + +int strerror_r( int errnum, char *buf, size_t len ) +{ + /* Copy the error message, as retrieved by strerror(), to the user + * supplied buffer, so protecting it from subsequent overwrite by a + * future call to strerror(); returns zero on success, otherwise sets + * errno to, and returns, EINVAL if the user specified errnum doesn't + * refer to a valid message, or ERANGE if the associated message, and + * its terminating NUL, will not fit within the specified buffer. + * + * Note that Microsoft's strerror() DOES appear to be thread-safe, + * but it uses a single static buffer per thread; thus, within any + * one thread, successive calls will overwrite the previous contents + * of this buffer; use of strerror_r() allows the user to save a copy + * of strerror()'s buffer contents, following each call, where they + * are not subject to overwriting by a subsequent strerror() call. + */ + if( buf == NULL ) + /* POSIX does not recommend any handling for the case of a NULL + * return buffer argument; rather than segfault, we will treat it + * as a zero-length buffer, into which we can fit no message text + * at all, and so we simply return, setting errno to ERANGE. + */ + return errno = ERANGE; + + /* The buffer pointer isn't NULL; assume it is valid, (we will fail + * on segfault if it isn't), and proceed to validate errnum. + */ + if( ((unsigned)(errnum)) >= sys_nerr ) + { /* Note that we check errnum as unsigned; this will also catch a + * negative value, since it will appear to be within the positive + * range INT_MAX < errnum <= UINT_MAX, while sys_nerr is expected + * to be less than INT_MAX. + */ + snprintf( buf, len, "Unknown error: %d", errnum ); + return errno = EINVAL; + } + /* errnum appears to be valid; copy the associated message, while + * checking that its entire text is copied... + */ + if( snprintf( buf, len, "%s", strerror( errnum )) >= len ) + /* + * ...otherwise, set errno on truncation. + */ + return errno = ERANGE; + + /* If we get to here, return zero, indicating success; (DO NOT + * modify errno, in this case). + */ + return 0; +} + +/* $RCSfile$: end of file */