Bug 827070. r=smontagu
authorMats Palmgren <matspal@gmail.com>
Sun, 20 Jan 2013 13:40:09 +0100
changeset 119383 2106f6631cd6f2368c090f2efa3a169176ff1033
parent 119382 5dc1c3d2e2c416274f64fdcf4dc5cdc8bdb062c7
child 119384 56efd49e70dd3994e07287b5a5bb1fd69327d98b
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerssmontagu
bugs827070
milestone21.0a1
Bug 827070. r=smontagu
intl/unicharutil/src/nsSaveAsCharset.cpp
--- a/intl/unicharutil/src/nsSaveAsCharset.cpp
+++ b/intl/unicharutil/src/nsSaveAsCharset.cpp
@@ -1,9 +1,10 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "prmem.h"
 #include "prprf.h"
 #include "nsIServiceManager.h"
@@ -122,16 +123,18 @@ nsSaveAsCharset::GetCharset(char * *aCha
   }
 
   *aCharset = nsCRT::strdup(charset);
   return (*aCharset) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
+#define RESERVE_FALLBACK_BYTES 512
+
 // do the fallback, reallocate the buffer if necessary
 // need to pass destination buffer info (size, current position and estimation of rest of the conversion)
 NS_IMETHODIMP
 nsSaveAsCharset::HandleFallBack(uint32_t character, char **outString, int32_t *bufferLength, 
                                 int32_t *currentPos, int32_t estimatedLength)
 {
   NS_ENSURE_ARG_POINTER(outString);
   NS_ENSURE_ARG_POINTER(bufferLength);
@@ -139,24 +142,26 @@ nsSaveAsCharset::HandleFallBack(uint32_t
 
   char fallbackStr[256];
   nsresult rv = DoConversionFallBack(character, fallbackStr, 256);
   if (NS_SUCCEEDED(rv)) {
     int32_t tempLen = (int32_t) PL_strlen(fallbackStr);
 
     // reallocate if the buffer is not large enough
     if ((tempLen + estimatedLength) >= (*bufferLength - *currentPos)) {
-      char *temp = (char *) PR_Realloc(*outString, *bufferLength + tempLen);
+      int32_t addLength = tempLen + RESERVE_FALLBACK_BYTES;
+      // + 1 is for the terminating NUL, don't add that to bufferLength
+      char *temp = (char *) PR_Realloc(*outString, *bufferLength + addLength + 1);
       if (temp) {
         // adjust length/pointer after realloc
-        *bufferLength += tempLen;
+        *bufferLength += addLength;
         *outString = temp;
       } else {
         *outString = nullptr;
-        *bufferLength =0;
+        *bufferLength = 0;
         return NS_ERROR_OUT_OF_MEMORY;
       }
     }
     memcpy((*outString + *currentPos), fallbackStr, tempLen);
     *currentPos += tempLen;
   }
   return rv;
 }
@@ -175,22 +180,29 @@ nsSaveAsCharset::DoCharsetConversion(con
   int32_t dstLength;
   int32_t pos1, pos2;
   nsresult saveResult = NS_OK;                         // to remember NS_ERROR_UENC_NOMAPPING
 
   // estimate and allocate the target buffer (reserve extra memory for fallback)
   rv = mEncoder->GetMaxLength(inString, inStringLength, &dstLength);
   if (NS_FAILED(rv)) return rv;
 
-  bufferLength = dstLength + 512; // reserve 512 byte for fallback.
-  char *dstPtr = (char *) PR_Malloc(bufferLength);
+  bufferLength = dstLength + RESERVE_FALLBACK_BYTES; // extra bytes for fallback
+  // + 1 is for the terminating NUL -- we don't add that to bufferLength so that
+  // we can always write dstPtr[pos2] = '\0' even when the encoder filled the
+  // buffer.
+  char *dstPtr = (char *) PR_Malloc(bufferLength + 1);
+  if (!dstPtr) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
   
   for (pos1 = 0, pos2 = 0; pos1 < inStringLength;) {
     // convert from unicode
     dstLength = bufferLength - pos2;
+    NS_ASSERTION(dstLength >= 0, "out of bounds write");
     rv = mEncoder->Convert(&inString[pos1], &srcLength, &dstPtr[pos2], &dstLength);
 
     pos1 += srcLength ? srcLength : 1;
     pos2 += dstLength;
     dstPtr[pos2] = '\0';
 
     // break: this is usually the case (no error) OR unrecoverable error
     if (NS_ERROR_UENC_NOMAPPING != rv) break;