--- 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;