OSDN Git Service

Make strnlen() available for all MSVCRT.DLL versions.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 30 Apr 2016 19:57:08 +0000 (20:57 +0100)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Sat, 30 Apr 2016 19:57:08 +0000 (20:57 +0100)
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/string.h
mingwrt/mingwex/strnlen.s [new file with mode: 0644]
mingwrt/msvcrt-xref/msvcrt.def.in

index 83fe8f2..836d084 100644 (file)
@@ -1,3 +1,22 @@
+2016-04-30  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Make strnlen() available for all MSVCRT.DLL versions.
+
+       * msvcrt-xref/msvcrt.def.in (strnlen): Mark it as...
+       (__MINGW_DLSYM): ...this, excluding its exposure in libmsvcrt.dll, and
+       thus requiring a dlsym() lookup for versions which provide it.
+
+       * include/string.h [__MSVCRT_VERSION__>=__MSVCR80_DLL] (strnlen):
+       Declare prototype, for use from these non-free DLLs, otherwise...
+       [_POSIX_C_SOURCE >= 200809L] (strnlen): Define it as an alias for...
+       (__mingw_strnlen): ...this new libmingwex.a function.
+
+       * mingwex/strnlen.s: New file; it implements...
+       (__mingw_strnlen, __mingw_strnlen_s): ...these new functions.
+
+       * Makefile.in (libmingwex.a): Add requirement for...
+       (strnlen.$OBJEXT): ...this; add vpath specification for its source.
+
 2016-04-26  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Use correct paths for partially included header files.
index 9957a56..b2ec873 100644 (file)
@@ -462,8 +462,9 @@ libmingwex.a: $(addsuffix .$(OBJEXT), tdelete tfind tsearch twalk)
 libmingwex.a: gettimeofday.$(OBJEXT)
 libmingwex.a: $(addsuffix .$(OBJEXT), dirent wdirent dlfcn)
 
-libmingwex.a: $(addsuffix .$(OBJEXT), fwide mbrtowc mbsinit wcrtomb wcstof \
-  wcstold wctob wmemchr wmemcmp wmemcpy wmemmove wmemset)
+vpath %.s ${mingwrt_srcdir}/mingwex
+libmingwex.a: $(addsuffix .$(OBJEXT), fwide mbrtowc mbsinit strnlen wcrtomb \
+  wcstof wcstold wctob wmemchr wmemcmp wmemcpy wmemmove wmemset)
 
 libmingwex.a: $(addsuffix .$(OBJEXT), wctrans wctype)
 
index c10c23f..c617ca9 100644 (file)
@@ -152,6 +152,33 @@ _CRTIMP __cdecl __MINGW_NOTHROW  void swab (const char *, char *, size_t);
 #include <wchar.h>
 
 #endif /* ! __STRICT_ANSI__ */
+
+#if __MSVCRT_VERSION__ >= __MSVCR80_DLL
+/* MSVCR80.DLL adds a (mostly) POSIX.1-2008 conforming strnlen(); (it's
+ * also available in MSVCRT.DLL from _WIN32_WINNT_VISTA onwards, but we
+ * pretend otherwise, since recent GCC will try to use the function when
+ * it can be found in libmsvcrt.a, so breaking it for use on WinXP and
+ * earlier).
+ */
+_CRTIMP __cdecl __MINGW_NOTHROW  char *strnlen (const char *, size_t);
+
+#elif _POSIX_C_SOURCE >= 200809L
+/* Emulation, to support recent POSIX.1; we prefer this for ALL versions
+ * of MSVCRT.DLL, (even those which already provide strnlen()); to avoid
+ * the GCC breakage noted above.  (Note that we implement strnlen() with
+ * the alternative external name, __mingw_strnlen() in libmingwex.a, to
+ * avoid possible link time collision with MSVCR80.DLL's implementation,
+ * then map this to strnlen() via a preprocessor define, so that users
+ * may use it conventionally, (including taking its address); this may
+ * interfere with C++ namespace qualification, but since strnlen() is
+ * not a standard C++ function, we do not anticipate any consequent
+ * usage issues).
+ */
+#define strnlen  __mingw_strnlen
+extern size_t __mingw_strnlen (const char *, size_t);
+
+#endif /* _POSIX_C_SOURCE >= 200809L */
+
 #undef __STRING_H_SOURCED__
 
 _END_C_DECLS
diff --git a/mingwrt/mingwex/strnlen.s b/mingwrt/mingwex/strnlen.s
new file mode 100644 (file)
index 0000000..e023a69
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * strnlen.s
+ *
+ * Implementation of POSIX.1-2008 conforming strnlen(), and a wrapper
+ * extending it to conform with ISO-C11 TR-24731-1 strnlen_s().
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2016, 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 (including the next
+ * paragraph) 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.
+ *
+ *
+ * This file implements a POSIX.1-2008 conforming strnlen() function, under
+ * the alternative public name of __mingw_strnlen(), (to avoid any possible
+ * conflict with Microsoft's DLL implementations, or a replacement function
+ * implemented by the user).
+ *
+ * Note that POSIX does not prescribe any error returns for its strnlen()
+ * function; in particular, it does not specify handling of a NULL pointer,
+ * passed as the string argument to count, and thus, a segmentation fault
+ * is a plausible outcome.  This is consistent with the behaviour exhibited
+ * by Microsoft's implementation, and this implementation acts likewise.
+ *
+ * OTOH, ISO-C11 TR-24731-1 prescribes that strnlen_s() shall return zero,
+ * when passed a NULL pointer as the string argument; the alternative entry
+ * point, __mingw_strnlen_s(), checks for this anomaly, and acts accordingly,
+ * before continuing as for __mingw_strnlen(), when passed a valid pointer
+ * to a string argument; (this is consistent with the documented behaviour
+ * of Microsoft's strnlen_s() implementation).
+ *
+ * Note that I've chosen to implement this in assembly language to enable
+ * sharing of common code between two distinct entry points, with subtly
+ * differing behaviours, while avoiding the overhead of an extra function
+ * call to invoke such shared code; this also allows the code to exploit
+ * the CUP's string scanning instructions, (which GCC does not), and so
+ * achieves a more compact, (and likely more efficient), implementation.
+ *
+ */
+.text
+.align 4
+.globl ___mingw_strnlen
+.def   ___mingw_strnlen;       .scl    2;      .type   32;     .endef
+
+___mingw_strnlen:
+/* Implements: size_t __mingw_strnlen (const char *string, size_t maxlen );
+ *
+ * Scans at most maxlen chars, returning the lesser of strlen (string) and
+ * maxlen; does NOT check for string == NULL, which may thus induce failure
+ * with a segmentation fault.  Note that initialization of return count to
+ * zero, in EAX, also serves as the NUL char reference for SCASB, in AL.
+ */
+       pushl   %edi            /* must preserve this */
+       xorl    %eax, %eax      /* initialize return count to zero */
+       movl    8(%esp), %edx   /* load address of string argument */
+.L1:
+       movl    12(%esp), %ecx  /* load maxlen ... */
+       jecxz   .L4             /* and jump to end, if it's zero */
+.L2:
+       cld                     /* scan string from low-->high address */
+       movl    %edx, %edi      /* using this as the scan pointer ... */
+       repne   scasb           /* as required by this CPU scan */
+       mov     %edi, %eax      /* note where we stopped ... */
+       jz      .L3             /* but if we found NUL, we've overrun ... */
+       decl    %eax            /* so we need to adjust one byte backward */
+.L3:
+       sub     %edx, %eax      /* compute effective count to return */
+.L4:
+       popl    %edi            /* restore saved register ... */
+       ret                     /* and we're done */
+
+.align 4
+.globl ___mingw_strnlen_s
+.def   ___mingw_strnlen_s;     .scl    2;      .type   32;     .endef
+
+___mingw_strnlen_s:
+/* Implements: size_t __mingw_strnlen_s (const char *string, size_t maxlen );
+ *
+ * Exhibits identical behaviour to __mingw_strnlen(), EXCEPT that it DOES
+ * check for string == NULL, returning zero when found.
+ */
+       pushl   %edi            /* must preserve this */
+       xorl    %eax, %eax      /* initialize return count to zero */
+       movl    8(%esp), %edx   /* load address of string argument ... */
+       testl   %edx, %edx      /* checking for NULL pointer, and ... */
+       jnz     .L1             /* proceeding as strnlen(), if not ... */
+       popl    %edi            /* otherwise restore saved register ... */
+       ret                     /* and return zero count value */
+
+/* $RCSfile$: end of file */
index fcb586f..5936ce2 100644 (file)
@@ -3417,7 +3417,7 @@ strncpy
 #if __MSVCRT_VERSION__ >= 0x0600UL
 # if __MSVCRT_VERSION__ < 0x07000000UL || __MSVCRT_VERSION__ >= 0x08000000UL
 strncpy_s
-strnlen
+__MINGW_DLSYM(strnlen); exposure in libmsvcrt.a may break GCC builds.
 # endif
 #endif
 strpbrk