OSDN Git Service

Implement strerror_r()/strerror_s() API.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Mon, 30 Jan 2017 15:12:46 +0000 (15:12 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Mon, 30 Jan 2017 15:12:46 +0000 (15:12 +0000)
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/string.h
mingwrt/mingwex/strerror_r.c [new file with mode: 0644]

index 8064858..1862aa4 100644 (file)
@@ -1,5 +1,19 @@
 2017-01-30  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
+       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  <keithmarshall@users.sourceforge.net>
+
        Avoid -Wformat noise from snprintf() and vsnprintf()
 
        * include/stdio.h (snprintf, vsnprintf): Add inline implementations;
index 20fd2c5..7593cca 100644 (file)
@@ -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
index a53a71a..ef80f37 100644 (file)
@@ -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 (file)
index 0000000..4194357
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * strerror_r.c
+ *
+ * Implementation of POSIX standard IEEE 1003.1-2001 strerror_r() function.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+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 */