OSDN Git Service

Correct a potential mbsrtowcs() surrogate pair overrun.
authorKeith Marshall <keith@users.osdn.me>
Thu, 19 Mar 2020 21:17:25 +0000 (21:17 +0000)
committerKeith Marshall <keith@users.osdn.me>
Thu, 19 Mar 2020 21:17:25 +0000 (21:17 +0000)
mingwrt/ChangeLog
mingwrt/mingwex/mbrscan.c

index fb57462..fb2ccde 100644 (file)
@@ -1,3 +1,10 @@
+2020-03-19  Keith Marshall  <keith@users.osdn.me>
+
+       Correct a potential mbsrtowcs() surrogate pair overrun.
+
+       * mingwex/mbrscan.c (__mingw_mbtowc_copy) [(count + 1) == len)]: Stop,
+       without storing current multibyte conversion, if surrogate pair.
+
 2020-03-12  Keith Marshall  <keith@users.osdn.me>
 
        Rationalize implementations of fwide() and mbsinit() functions.
index 606ed4a..8f33ff3 100644 (file)
@@ -264,23 +264,58 @@ size_t __mingw_mbtowc_copy
    * an internal scratch buffer, to facilitate counting the number of
    * such elements which would be copied, without storing them).
    */
-  wchar_t scratch[2]; size_t count = (size_t)(0);
+  size_t count = (size_t)(0);
   while( count < len )
-  {
-    int copy, scan = 0;
-    wchar_t *wc = (wcs == NULL) ? scratch : wcs;
+  { /* Scan the multibyte sequence, one character at a time, while we
+     * still have sufficient space to store each conversion, (ensuring
+     * that there is always at least enough space to accommodate one
+     * full conversion, avoiding possible surrogate pair overflow.
+     */
+    int copy, scan = 0, gap = len - count;
+    wchar_t scratch[2], *wc = ((wcs == NULL) || (gap < 2)) ? scratch : wcs;
+
+    /* Determine the length of the next multibyte character, and the
+     * number of wchar_t entities required to store it.
+     */
     do { copy = __mingw_mbtowc_convert( src, ++scan, wc, 2 );
        } while( (copy == 0) && (scan < mbrlen_cur_max) );
 
+    /* Bail out, if no conversion is possible; (this can only occur
+     * if an invalid multibyte sequence is detected).
+     */
     if( copy == 0 ) return errout( EILSEQ, (size_t)(-1) );
 
-    if( *wc == L'\0' ) len = count;
+    /* Stop at any terminating NUL character, or if a surrogate pair
+     * will overflow at the end of the designated buffer...
+     */
+    if( (*wc == L'\0') || (gap < copy) )
+    {
+      /* ...storing a NUL terminator, if necessary...
+       */
+      if( (wcs != NULL) && (*wc == L'\0') ) *wcs = L'\0';
+      len = count;
+    }
     else
-    { count += copy;
-      if( wcs != NULL ) wcs += copy;
+    { /* ...otherwise, adjust the count of wchar_t entities, which
+       * have been converted thus far...
+       */
+      count += copy;
+      if( wcs != NULL )
+      { /* ...ensuring that the conversion is appropriately stored,
+        * and the storage buffer pointer is advanced...
+        */
+               if( wc == scratch ) while( copy-- > 0 ) *wcs++ = *wc++;
+       else wcs += copy;
+      }
+      /* ...and that the scan pointer is repositioned, to process
+       * the next multibyte character, (if any).
+       */
       src += scan;
     }
   }
+  /* Finally, we return the total number of wchar_t entities which have,
+   * (or would have), been stored for this conversion.
+   */
   return count;
 }