Bug 1170794 - Improve the length check of the input in nsUnicode*::GetMaxLength, r=dveditz

This commit is contained in:
Andrea Marchesini 2015-06-17 12:21:39 +01:00
parent b3cf1fa93d
commit 5acececf92
16 changed files with 137 additions and 87 deletions

View File

@ -103,10 +103,12 @@ public:
* @param aSrcLength [IN] the length of source data buffer
* @param aDestLength [OUT] the needed size of the destination buffer
* @return NS_EXACT_LENGTH if an exact length was computed
* NS_ERROR_OUT_OF_MEMORY if OOM
* NS_OK is all we have is an approximation
*/
NS_IMETHOD GetMaxLength(const char * aSrc, int32_t aSrcLength,
int32_t * aDestLength) = 0;
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char * aSrc,
int32_t aSrcLength,
int32_t * aDestLength) = 0;
/**
* Resets the charset converter so it may be recycled for a completely

View File

@ -45,41 +45,6 @@ public:
NS_DEFINE_STATIC_IID_ACCESSOR(nsIUnicharEncoder, NS_IUNICHARENCODER_IID)
//
// Malloc an Encoder (unicode -> charset) buffer if the
// result won't fit in the static buffer
//
// p = the buffer pointer (char*)
// e = encoder (nsIUnicodeEncoder*)
// s = string (char16_t*)
// l = string length (int32_t)
// sb = static buffer (char[])
// sbl = static buffer length (uint32_t)
// al = actual buffer length (int32_t)
//
#define ENCODER_BUFFER_ALLOC_IF_NEEDED(p,e,s,l,sb,sbl,al) \
PR_BEGIN_MACRO \
if (e \
&& NS_SUCCEEDED((e)->GetMaxLength((s), (l), &(al)))\
&& ((al) > (int32_t)(sbl)) \
&& (nullptr!=((p)=(char*)moz_xmalloc((al)+1))) \
) { \
} \
else { \
(p) = (char*)(sb); \
(al) = (sbl); \
} \
PR_END_MACRO
//
// Free the Encoder buffer if it was allocated
//
#define ENCODER_BUFFER_FREE_IF_NEEDED(p,sb) \
PR_BEGIN_MACRO \
if ((p) != (char*)(sb)) \
free(p); \
PR_END_MACRO
/**
* Interface for a Converter from Unicode into a Charset.
*
@ -156,10 +121,12 @@ public:
* @param aSrcLength [IN] the length of source data buffer
* @param aDestLength [OUT] the needed size of the destination buffer
* @return NS_OK_UENC_EXACTLENGTH if an exact length was computed
* NS_ERROR_OUT_OF_MEMORY if OOM
* NS_OK if all we have is an approximation
*/
NS_IMETHOD GetMaxLength(const char16_t * aSrc, int32_t aSrcLength,
int32_t * aDestLength) = 0;
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t * aSrc,
int32_t aSrcLength,
int32_t * aDestLength) = 0;
/**
* Resets the charset converter so it may be recycled for a completely

View File

@ -24,9 +24,9 @@ public:
char16_t* aDest,
int32_t* aDestLength);
NS_IMETHOD GetMaxLength(const char* aSrc,
int32_t aSrcLength,
int32_t* aDestLength);
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char* aSrc,
int32_t aSrcLength,
int32_t* aDestLength) override;
NS_IMETHOD Reset();

View File

@ -6,6 +6,7 @@
#include "nsUCSupport.h"
#include "nsUTF8ToUnicode.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/SSE.h"
#include "nsCharTraits.h"
#include <algorithm>
@ -52,7 +53,14 @@ NS_IMETHODIMP nsUTF8ToUnicode::GetMaxLength(const char * aSrc,
int32_t aSrcLength,
int32_t * aDestLength)
{
*aDestLength = aSrcLength + 1;
mozilla::CheckedInt32 length = aSrcLength;
length += 1;
if (!length.isValid()) {
return NS_ERROR_FAILURE;
}
*aDestLength = length.value();
return NS_OK;
}

View File

@ -49,8 +49,9 @@ protected:
//--------------------------------------------------------------------
// Subclassing of nsDecoderSupport class [declaration]
NS_IMETHOD GetMaxLength(const char * aSrc, int32_t aSrcLength,
int32_t * aDestLength);
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char * aSrc,
int32_t aSrcLength,
int32_t * aDestLength) override;
//--------------------------------------------------------------------
// Subclassing of nsBasicDecoderSupport class [declaration]

View File

@ -6,29 +6,40 @@
//----------------------------------------------------------------------
// Global functions and data [declaration]
#include "nsUnicodeToUTF8.h"
#include "mozilla/CheckedInt.h"
NS_IMPL_ISUPPORTS(nsUnicodeToUTF8, nsIUnicodeEncoder)
//----------------------------------------------------------------------
// nsUnicodeToUTF8 class [implementation]
NS_IMETHODIMP nsUnicodeToUTF8::GetMaxLength(const char16_t * aSrc,
int32_t aSrcLength,
int32_t * aDestLength)
NS_IMETHODIMP nsUnicodeToUTF8::GetMaxLength(const char16_t* aSrc,
int32_t aSrcLength,
int32_t* aDestLength)
{
MOZ_ASSERT(aDestLength);
// aSrc is interpreted as UTF16, 3 is normally enough.
// But when previous buffer only contains part of the surrogate pair, we
// But when previous buffer only contains part of the surrogate pair, we
// need to complete it here. If the first word in following buffer is not
// in valid surrogate range, we need to convert the remaining of last buffer
// to 3 bytes.
*aDestLength = 3*aSrcLength + 3;
mozilla::CheckedInt32 length = aSrcLength;
length *= 3;
length += 3;
if (!length.isValid()) {
return NS_ERROR_FAILURE;
}
*aDestLength = length.value();
return NS_OK;
}
NS_IMETHODIMP nsUnicodeToUTF8::Convert(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength)
NS_IMETHODIMP nsUnicodeToUTF8::Convert(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength)
{
const char16_t * src = aSrc;
const char16_t * srcEnd = aSrc + *aSrcLength;

View File

@ -16,7 +16,7 @@
#define NS_UNICODETOUTF8_CONTRACTID "@mozilla.org/intl/unicode/encoder;1?charset=UTF-8"
//#define NS_ERROR_UCONV_NOUNICODETOUTF8
//#define NS_ERROR_UCONV_NOUNICODETOUTF8
// NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_UCONV, 0x31)
//----------------------------------------------------------------------
@ -41,19 +41,20 @@ public:
*/
nsUnicodeToUTF8() {mHighSurrogate = 0;}
NS_IMETHOD Convert(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
NS_IMETHOD Convert(const char16_t * aSrc,
int32_t * aSrcLength,
char * aDest,
int32_t * aDestLength) override;
NS_IMETHOD Finish(char * aDest, int32_t * aDestLength) override;
NS_IMETHOD GetMaxLength(const char16_t * aSrc, int32_t aSrcLength,
int32_t * aDestLength) override;
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t * aSrc,
int32_t aSrcLength,
int32_t * aDestLength) override;
NS_IMETHOD Reset() override {mHighSurrogate = 0; return NS_OK;}
NS_IMETHOD SetOutputErrorBehavior(int32_t aBehavior,
NS_IMETHOD SetOutputErrorBehavior(int32_t aBehavior,
nsIUnicharEncoder * aEncoder, char16_t aChar) override {return NS_OK;}
protected:

View File

@ -5,6 +5,7 @@
#include "nsUTF16ToUnicode.h"
#include "nsCharTraits.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Endian.h"
enum {
@ -181,8 +182,18 @@ NS_IMETHODIMP
nsUTF16ToUnicodeBase::GetMaxLength(const char * aSrc, int32_t aSrcLength,
int32_t * aDestLength)
{
mozilla::CheckedInt32 length = aSrcLength;
if (STATE_HALF_CODE_POINT & mState) {
length += 1;
}
if (!length.isValid()) {
return NS_ERROR_FAILURE;
}
// the left-over data of the previous run have to be taken into account.
*aDestLength = (aSrcLength + ((STATE_HALF_CODE_POINT & mState) ? 1 : 0)) / 2;
*aDestLength = length.value() / 2;
if (mOddHighSurrogate)
(*aDestLength)++;
if (mOddLowSurrogate)

View File

@ -20,12 +20,13 @@ protected:
int32_t * aSrcLength, char16_t * aDest,
int32_t * aDestLength, bool aSwapBytes);
public:
public:
//--------------------------------------------------------------------
// Subclassing of nsDecoderSupport class [declaration]
NS_IMETHOD GetMaxLength(const char * aSrc, int32_t aSrcLength,
int32_t * aDestLength);
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char * aSrc,
int32_t aSrcLength,
int32_t * aDestLength) override;
NS_IMETHOD Reset();
protected:
@ -44,7 +45,7 @@ class nsUTF16BEToUnicode : public nsUTF16ToUnicodeBase
public:
NS_IMETHOD Convert(const char * aSrc, int32_t * aSrcLength,
char16_t * aDest, int32_t * aDestLength);
char16_t * aDest, int32_t * aDestLength);
};
// UTF-16 little endian
@ -53,7 +54,7 @@ class nsUTF16LEToUnicode : public nsUTF16ToUnicodeBase
public:
NS_IMETHOD Convert(const char * aSrc, int32_t * aSrcLength,
char16_t * aDest, int32_t * aDestLength);
char16_t * aDest, int32_t * aDestLength);
};
// UTF-16 with BOM
@ -63,14 +64,14 @@ public:
nsUTF16ToUnicode() { Reset();}
NS_IMETHOD Convert(const char * aSrc, int32_t * aSrcLength,
char16_t * aDest, int32_t * aDestLength);
char16_t * aDest, int32_t * aDestLength);
NS_IMETHOD Reset();
private:
enum Endian {kUnknown, kBigEndian, kLittleEndian};
Endian mEndian;
Endian mEndian;
bool mFoundBOM;
};

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsUnicodeToUTF16.h"
#include "mozilla/CheckedInt.h"
#include <string.h>
NS_IMETHODIMP nsUnicodeToUTF16BE::Convert(const char16_t * aSrc, int32_t * aSrcLength,
@ -54,10 +55,19 @@ needmoreoutput:
NS_IMETHODIMP nsUnicodeToUTF16BE::GetMaxLength(const char16_t * aSrc, int32_t aSrcLength,
int32_t * aDestLength)
{
if(0 != mBOM)
*aDestLength = 2*(aSrcLength+1);
else
*aDestLength = 2*aSrcLength;
mozilla::CheckedInt32 length = 2;
if(0 != mBOM) {
length *= (aSrcLength+1);
} else {
length *= aSrcLength;
}
if (!length.isValid()) {
return NS_ERROR_FAILURE;
}
*aDestLength = length.value();
return NS_OK_UENC_EXACTLENGTH;
}

View File

@ -19,8 +19,9 @@ public:
NS_IMETHOD Convert(const char16_t * aSrc, int32_t * aSrcLength,
char * aDest, int32_t * aDestLength);
NS_IMETHOD GetMaxLength(const char16_t * aSrc, int32_t aSrcLength,
int32_t * aDestLength);
MOZ_WARN_UNUSED_RESULT NS_IMETHOD GetMaxLength(const char16_t * aSrc,
int32_t aSrcLength,
int32_t * aDestLength);
NS_IMETHOD Finish(char * aDest, int32_t * aDestLength);
NS_IMETHOD Reset();
NS_IMETHOD SetOutputErrorBehavior(int32_t aBehavior,

View File

@ -6,6 +6,7 @@
#include "nsUCSupport.h"
#include "nsUnicodeDecodeHelper.h"
#include "nsUnicodeEncodeHelper.h"
#include "mozilla/CheckedInt.h"
#include <algorithm>
#define DEFAULT_BUFFER_CAPACITY 16
@ -185,7 +186,15 @@ NS_IMETHODIMP nsBufferDecoderSupport::GetMaxLength(const char* aSrc,
int32_t* aDestLength)
{
NS_ASSERTION(mMaxLengthFactor != 0, "Must override GetMaxLength!");
*aDestLength = aSrcLength * mMaxLengthFactor;
mozilla::CheckedInt32 length = aSrcLength;
length *= mMaxLengthFactor;
if (!length.isValid()) {
return NS_ERROR_FAILURE;
}
*aDestLength = length.value();
return NS_OK;
}
@ -551,7 +560,14 @@ nsEncoderSupport::GetMaxLength(const char16_t * aSrc,
int32_t aSrcLength,
int32_t * aDestLength)
{
*aDestLength = aSrcLength * mMaxLengthFactor;
mozilla::CheckedInt32 length = aSrcLength;
length *= mMaxLengthFactor;
if (!length.isValid()) {
return NS_ERROR_FAILURE;
}
*aDestLength = length.value();
return NS_OK;
}

View File

@ -211,19 +211,25 @@ nsUnicharStreamLoader::WriteSegmentFun(nsIInputStream *,
uint32_t haveRead = self->mBuffer.Length();
int32_t srcLen = aCount;
int32_t dstLen;
self->mDecoder->GetMaxLength(aSegment, srcLen, &dstLen);
nsresult rv = self->mDecoder->GetMaxLength(aSegment, srcLen, &dstLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
uint32_t capacity = haveRead + dstLen;
if (!self->mBuffer.SetCapacity(capacity, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
DebugOnly<nsresult> rv =
self->mDecoder->Convert(aSegment,
&srcLen,
self->mBuffer.BeginWriting() + haveRead,
&dstLen);
MOZ_ASSERT(NS_SUCCEEDED(rv));
rv = self->mDecoder->Convert(aSegment,
&srcLen,
self->mBuffer.BeginWriting() + haveRead,
&dstLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT(srcLen == static_cast<int32_t>(aCount));
haveRead += dstLen;

View File

@ -241,7 +241,12 @@ nsresult nsScanner::Append(const char* aBuffer, uint32_t aLen,
nsresult res = NS_OK;
if (mUnicodeDecoder) {
int32_t unicharBufLen = 0;
mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen);
nsresult rv = mUnicodeDecoder->GetMaxLength(aBuffer, aLen, &unicharBufLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsScannerString::Buffer* buffer = nsScannerString::AllocBuffer(unicharBufLen + 1);
NS_ENSURE_TRUE(buffer,NS_ERROR_OUT_OF_MEMORY);
char16_t *unichars = buffer->DataStart();

View File

@ -716,7 +716,13 @@ void ConvertHTMLtoUCS2(guchar * data, int32_t dataLength,
}
decoder = EncodingUtils::DecoderForEncoding(encoding);
// converting
decoder->GetMaxLength((const char *)data, dataLength, &outUnicodeLen);
nsresult rv = decoder->GetMaxLength((const char *)data, dataLength,
&outUnicodeLen);
if (NS_WARN_IF(NS_FAILED(rv))) {
outUnicodeLen = 0;
return;
}
// |outUnicodeLen| is number of chars
if (outUnicodeLen) {
*unicodeData = reinterpret_cast<char16_t*>

View File

@ -208,7 +208,11 @@ nsPrimitiveHelpers :: ConvertPlatformPlainTextToUnicode ( const char* inText, in
// Estimate out length and allocate the buffer based on a worst-case estimate, then do
// the conversion.
decoder->GetMaxLength(inText, inTextLen, outUnicodeLen); // |outUnicodeLen| is number of chars
rv = decoder->GetMaxLength(inText, inTextLen, outUnicodeLen); // |outUnicodeLen| is number of chars
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if ( *outUnicodeLen ) {
*outUnicode = reinterpret_cast<char16_t*>(moz_xmalloc((*outUnicodeLen + 1) * sizeof(char16_t)));
if ( *outUnicode ) {