Bug 737164 part A - make the nsTSubstring string API infallible by default. Note that this patch for reviewing sanity does not modify the subclass APIs, that will be a separate revision, r=jlebar

--HG--
extra : rebase_source : 48db8595e35e95ea6ddc3a35a553d5641b8d1a42
This commit is contained in:
Benjamin Smedberg 2012-05-08 12:42:27 -04:00
Родитель 603705ce16
Коммит c19ee28084
5 изменённых файлов: 211 добавлений и 100 удалений

Просмотреть файл

@ -277,7 +277,7 @@ Base64Encode(const nsACString &aBinaryData, nsACString &aString)
char *buffer; char *buffer;
// Add one byte for null termination. // Add one byte for null termination.
if (aString.SetCapacity(stringLen + 1) && if (aString.SetCapacity(stringLen + 1, fallible_t()) &&
(buffer = aString.BeginWriting()) && (buffer = aString.BeginWriting()) &&
PL_Base64Encode(aBinaryData.BeginReading(), aBinaryData.Length(), buffer)) { PL_Base64Encode(aBinaryData.BeginReading(), aBinaryData.Length(), buffer)) {
// PL_Base64Encode doesn't null terminate the buffer for us when we pass // PL_Base64Encode doesn't null terminate the buffer for us when we pass
@ -321,7 +321,7 @@ Base64Decode(const nsACString &aString, nsACString &aBinaryData)
char *buffer; char *buffer;
// Add one byte for null termination. // Add one byte for null termination.
if (aBinaryData.SetCapacity(binaryDataLen + 1) && if (aBinaryData.SetCapacity(binaryDataLen + 1, fallible_t()) &&
(buffer = aBinaryData.BeginWriting()) && (buffer = aBinaryData.BeginWriting()) &&
PL_Base64Decode(aString.BeginReading(), aString.Length(), buffer)) { PL_Base64Decode(aString.BeginReading(), aString.Length(), buffer)) {
// PL_Base64Decode doesn't null terminate the buffer for us when we pass // PL_Base64Decode doesn't null terminate the buffer for us when we pass

Просмотреть файл

@ -58,6 +58,8 @@
#include <string.h> #include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include "mozilla/fallible.h"
#define kNotFound -1 #define kNotFound -1
// declare nsAString // declare nsAString

Просмотреть файл

@ -83,6 +83,8 @@ class nsTDefaultStringComparator_CharT
class nsTSubstring_CharT class nsTSubstring_CharT
{ {
public: public:
typedef mozilla::fallible_t fallible_t;
typedef CharT char_type; typedef CharT char_type;
typedef nsCharTraits<char_type> char_traits; typedef nsCharTraits<char_type> char_traits;
@ -155,15 +157,50 @@ class nsTSubstring_CharT
*/ */
char_iterator BeginWriting() char_iterator BeginWriting()
{
if (!EnsureMutable())
NS_RUNTIMEABORT("OOM");
return mData;
}
char_iterator BeginWriting( const fallible_t& )
{ {
return EnsureMutable() ? mData : char_iterator(0); return EnsureMutable() ? mData : char_iterator(0);
} }
char_iterator EndWriting() char_iterator EndWriting()
{
if (!EnsureMutable())
NS_RUNTIMEABORT("OOM");
return mData + mLength;
}
char_iterator EndWriting( const fallible_t& )
{ {
return EnsureMutable() ? (mData + mLength) : char_iterator(0); return EnsureMutable() ? (mData + mLength) : char_iterator(0);
} }
char_iterator& BeginWriting( char_iterator& iter )
{
return iter = BeginWriting();
}
char_iterator& BeginWriting( char_iterator& iter, const fallible_t& )
{
return iter = BeginWriting(fallible_t());
}
char_iterator& EndWriting( char_iterator& iter )
{
return iter = EndWriting();
}
char_iterator& EndWriting( char_iterator& iter, const fallible_t& )
{
return iter = EndWriting(fallible_t());
}
/** /**
* deprecated writing iterators * deprecated writing iterators
@ -171,7 +208,7 @@ class nsTSubstring_CharT
iterator& BeginWriting( iterator& iter ) iterator& BeginWriting( iterator& iter )
{ {
char_type *data = EnsureMutable() ? mData : nsnull; char_type *data = BeginWriting();
iter.mStart = data; iter.mStart = data;
iter.mEnd = data + mLength; iter.mEnd = data + mLength;
iter.mPosition = iter.mStart; iter.mPosition = iter.mStart;
@ -180,24 +217,13 @@ class nsTSubstring_CharT
iterator& EndWriting( iterator& iter ) iterator& EndWriting( iterator& iter )
{ {
char_type *data = EnsureMutable() ? mData : nsnull; char_type *data = BeginWriting();
iter.mStart = data; iter.mStart = data;
iter.mEnd = data + mLength; iter.mEnd = data + mLength;
iter.mPosition = iter.mEnd; iter.mPosition = iter.mEnd;
return iter; return iter;
} }
char_iterator& BeginWriting( char_iterator& iter )
{
return iter = EnsureMutable() ? mData : char_iterator(0);
}
char_iterator& EndWriting( char_iterator& iter )
{
return iter = EnsureMutable() ? (mData + mLength) : char_iterator(0);
}
/** /**
* accessors * accessors
*/ */
@ -339,16 +365,35 @@ class nsTSubstring_CharT
*/ */
void NS_FASTCALL Assign( char_type c ); void NS_FASTCALL Assign( char_type c );
void NS_FASTCALL Assign( const char_type* data, size_type length = size_type(-1) ); bool NS_FASTCALL Assign( char_type c, const fallible_t& ) NS_WARN_UNUSED_RESULT;
void NS_FASTCALL
Assign( const char_type* data, size_type length = size_type(-1) );
bool NS_FASTCALL Assign( const char_type* data, size_type length, const fallible_t& ) NS_WARN_UNUSED_RESULT;
void NS_FASTCALL Assign( const self_type& ); void NS_FASTCALL Assign( const self_type& );
bool NS_FASTCALL Assign( const self_type&, const fallible_t& ) NS_WARN_UNUSED_RESULT;
void NS_FASTCALL Assign( const substring_tuple_type& ); void NS_FASTCALL Assign( const substring_tuple_type& );
bool NS_FASTCALL Assign( const substring_tuple_type&, const fallible_t& ) NS_WARN_UNUSED_RESULT;
void NS_FASTCALL AssignASCII( const char* data, size_type length ); void NS_FASTCALL AssignASCII( const char* data, size_type length );
void NS_FASTCALL AssignASCII( const char* data ); bool NS_FASTCALL AssignASCII( const char* data, size_type length, const fallible_t& ) NS_WARN_UNUSED_RESULT;
void NS_FASTCALL AssignASCII( const char* data )
{
AssignASCII(data, strlen(data));
}
bool NS_FASTCALL AssignASCII( const char* data, const fallible_t& ) NS_WARN_UNUSED_RESULT
{
return AssignASCII(data, strlen(data), fallible_t());
}
// AssignLiteral must ONLY be applied to an actual literal string. // AssignLiteral must ONLY be applied to an actual literal string.
// Do not attempt to use it with a regular char* pointer, or with a char // Do not attempt to use it with a regular char* pointer, or with a char
// array variable. Use AssignASCII for those. // array variable. Use AssignASCII for those.
// There are not fallible version of these methods because they only really
// apply to small allocations that we wouldn't want to check anyway.
#ifdef NS_DISABLE_LITERAL_TEMPLATE #ifdef NS_DISABLE_LITERAL_TEMPLATE
void AssignLiteral( const char* str ) void AssignLiteral( const char* str )
{ AssignASCII(str); } { AssignASCII(str); }
@ -375,7 +420,7 @@ class nsTSubstring_CharT
void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, char_type c ); void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, char_type c );
void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) ); void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const char_type* data, size_type length = size_type(-1) );
void Replace( index_type cutStart, size_type cutLength, const self_type& str ) { Replace(cutStart, cutLength, str.Data(), str.Length()); } void Replace( index_type cutStart, size_type cutLength, const self_type& str ) { Replace(cutStart, cutLength, str.Data(), str.Length()); }
void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple ); void NS_FASTCALL Replace( index_type cutStart, size_type cutLength, const substring_tuple_type& tuple );
void NS_FASTCALL ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length = size_type(-1) ); void NS_FASTCALL ReplaceASCII( index_type cutStart, size_type cutLength, const char* data, size_type length = size_type(-1) );
@ -467,14 +512,12 @@ class nsTSubstring_CharT
/** /**
* Attempts to set the capacity to the given size, without affecting * Attempts to set the capacity to the given size, without affecting
* the length of the string. Also ensures that the buffer is mutable. * the length of the string. Also ensures that the buffer is mutable.
*
* @returns true on success
* false on out-of-memory, or if requesting a size bigger
* than a string can hold (2^31 chars).
*/ */
bool NS_FASTCALL SetCapacity( size_type newCapacity ); void NS_FASTCALL SetCapacity( size_type newCapacity );
bool NS_FASTCALL SetCapacity( size_type newCapacity, const fallible_t& ) NS_WARN_UNUSED_RESULT;
bool NS_FASTCALL SetLength( size_type newLength ); void NS_FASTCALL SetLength( size_type newLength );
bool NS_FASTCALL SetLength( size_type newLength, const fallible_t& ) NS_WARN_UNUSED_RESULT;
void Truncate( size_type newLength = 0 ) void Truncate( size_type newLength = 0 )
{ {
@ -510,7 +553,16 @@ class nsTSubstring_CharT
* @returns The length of the buffer in characters or 0 if unable to * @returns The length of the buffer in characters or 0 if unable to
* satisfy the request due to low-memory conditions. * satisfy the request due to low-memory conditions.
*/ */
inline size_type GetMutableData( char_type** data, size_type newLen = size_type(-1) ) size_type GetMutableData( char_type** data, size_type newLen = size_type(-1) )
{
if (!EnsureMutable(newLen))
NS_RUNTIMEABORT("OOM");
*data = mData;
return mLength;
}
size_type GetMutableData( char_type** data, size_type newLen, const fallible_t& )
{ {
if (!EnsureMutable(newLen)) if (!EnsureMutable(newLen))
{ {
@ -684,7 +736,7 @@ class nsTSubstring_CharT
* memory. * memory.
*/ */
bool ReplacePrep(index_type cutStart, size_type cutLength, bool ReplacePrep(index_type cutStart, size_type cutLength,
size_type newLength) size_type newLength) NS_WARN_UNUSED_RESULT
{ {
cutLength = NS_MIN(cutLength, mLength - cutStart); cutLength = NS_MIN(cutLength, mLength - cutStart);
PRUint32 newTotalLen = mLength - cutLength + newLength; PRUint32 newTotalLen = mLength - cutLength + newLength;
@ -698,10 +750,11 @@ class nsTSubstring_CharT
} }
bool NS_FASTCALL ReplacePrepInternal(index_type cutStart, bool NS_FASTCALL ReplacePrepInternal(index_type cutStart,
size_type cutLength, size_type cutLength,
size_type newFragLength, size_type newFragLength,
size_type newTotalLength); size_type newTotalLength)
NS_WARN_UNUSED_RESULT;
/** /**
* returns the number of writable storage units starting at mData. * returns the number of writable storage units starting at mData.
* the value does not include space for the null-terminator character. * the value does not include space for the null-terminator character.
@ -715,7 +768,7 @@ class nsTSubstring_CharT
* this helper function can be called prior to directly manipulating * this helper function can be called prior to directly manipulating
* the contents of mData. see, for example, BeginWriting. * the contents of mData. see, for example, BeginWriting.
*/ */
bool NS_FASTCALL EnsureMutable( size_type newLen = size_type(-1) ); bool NS_FASTCALL EnsureMutable( size_type newLen = size_type(-1) ) NS_WARN_UNUSED_RESULT;
/** /**
* returns true if this string overlaps with the given string fragment. * returns true if this string overlaps with the given string fragment.

Просмотреть файл

@ -290,7 +290,8 @@ nsTString_CharT::SetCharAt( PRUnichar aChar, PRUint32 aIndex )
if (aIndex >= mLength) if (aIndex >= mLength)
return false; return false;
EnsureMutable(); if (!EnsureMutable())
NS_RUNTIMEABORT("OOM");
mData[aIndex] = CharT(aChar); mData[aIndex] = CharT(aChar);
return true; return true;
@ -304,7 +305,9 @@ nsTString_CharT::SetCharAt( PRUnichar aChar, PRUint32 aIndex )
void void
nsTString_CharT::StripChars( const char* aSet ) nsTString_CharT::StripChars( const char* aSet )
{ {
EnsureMutable(); if (!EnsureMutable())
NS_RUNTIMEABORT("OOM");
mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet); mLength = nsBufferRoutines<CharT>::strip_chars(mData, mLength, aSet);
} }
@ -322,7 +325,8 @@ nsTString_CharT::StripWhitespace()
void void
nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar ) nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar )
{ {
EnsureMutable(); // XXX do this lazily? if (!EnsureMutable()) // XXX do this lazily?
NS_RUNTIMEABORT("OOM");
for (PRUint32 i=0; i<mLength; ++i) for (PRUint32 i=0; i<mLength; ++i)
{ {
@ -334,7 +338,8 @@ nsTString_CharT::ReplaceChar( char_type aOldChar, char_type aNewChar )
void void
nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar ) nsTString_CharT::ReplaceChar( const char* aSet, char_type aNewChar )
{ {
EnsureMutable(); // XXX do this lazily? if (!EnsureMutable()) // XXX do this lazily?
NS_RUNTIMEABORT("OOM");
char_type* data = mData; char_type* data = mData;
PRUint32 lenRemaining = mLength; PRUint32 lenRemaining = mLength;

Просмотреть файл

@ -291,7 +291,7 @@ nsTSubstring_CharT::EnsureMutable( size_type newLen )
newLen = mLength; newLen = mLength;
} }
return SetLength(newLen); return SetLength(newLen, fallible_t());
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -300,19 +300,36 @@ nsTSubstring_CharT::EnsureMutable( size_type newLen )
void void
nsTSubstring_CharT::Assign( char_type c ) nsTSubstring_CharT::Assign( char_type c )
{ {
if (ReplacePrep(0, mLength, 1)) if (!ReplacePrep(0, mLength, 1))
*mData = c; NS_RUNTIMEABORT("OOM");
*mData = c;
} }
bool
nsTSubstring_CharT::Assign( char_type c, const fallible_t& )
{
if (!ReplacePrep(0, mLength, 1))
return false;
*mData = c;
return true;
}
void void
nsTSubstring_CharT::Assign( const char_type* data, size_type length ) nsTSubstring_CharT::Assign( const char_type* data, size_type length )
{ {
// unfortunately, some callers pass null :-( if (!Assign(data, length, fallible_t()))
NS_RUNTIMEABORT("OOM");
}
bool
nsTSubstring_CharT::Assign( const char_type* data, size_type length, const fallible_t& )
{
if (!data) if (!data)
{ {
Truncate(); Truncate();
return; return true;
} }
if (length == size_type(-1)) if (length == size_type(-1))
@ -320,54 +337,66 @@ nsTSubstring_CharT::Assign( const char_type* data, size_type length )
if (IsDependentOn(data, data + length)) if (IsDependentOn(data, data + length))
{ {
// take advantage of sharing here... return Assign(string_type(data, length), fallible_t());
Assign(string_type(data, length));
return;
} }
if (ReplacePrep(0, mLength, length)) if (!ReplacePrep(0, mLength, length))
char_traits::copy(mData, data, length); return false;
char_traits::copy(mData, data, length);
return true;
} }
void void
nsTSubstring_CharT::AssignASCII( const char* data, size_type length ) nsTSubstring_CharT::AssignASCII( const char* data, size_type length )
{
if (!AssignASCII(data, length, fallible_t()))
NS_RUNTIMEABORT("OOM");
}
bool
nsTSubstring_CharT::AssignASCII( const char* data, size_type length, const fallible_t& )
{ {
// A Unicode string can't depend on an ASCII string buffer, // A Unicode string can't depend on an ASCII string buffer,
// so this dependence check only applies to CStrings. // so this dependence check only applies to CStrings.
#ifdef CharT_is_char #ifdef CharT_is_char
if (IsDependentOn(data, data + length)) if (IsDependentOn(data, data + length))
{ {
// take advantage of sharing here... return Assign(string_type(data, length), fallible_t());
Assign(string_type(data, length));
return;
} }
#endif #endif
if (ReplacePrep(0, mLength, length)) if (!ReplacePrep(0, mLength, length))
char_traits::copyASCII(mData, data, length); return false;
}
void char_traits::copyASCII(mData, data, length);
nsTSubstring_CharT::AssignASCII( const char* data ) return true;
{
AssignASCII(data, strlen(data));
} }
void void
nsTSubstring_CharT::Assign( const self_type& str ) nsTSubstring_CharT::Assign( const self_type& str )
{
if (!Assign(str, fallible_t()))
NS_RUNTIMEABORT("OOM");
}
bool
nsTSubstring_CharT::Assign( const self_type& str, const fallible_t& )
{ {
// |str| could be sharable. we need to check its flags to know how to // |str| could be sharable. we need to check its flags to know how to
// deal with it. // deal with it.
if (&str == this) if (&str == this)
return; return true;
if (!str.mLength) if (!str.mLength)
{ {
Truncate(); Truncate();
mFlags |= str.mFlags & F_VOIDED; mFlags |= str.mFlags & F_VOIDED;
return true;
} }
else if (str.mFlags & F_SHARED)
if (str.mFlags & F_SHARED)
{ {
// nice! we can avoid a string copy :-) // nice! we can avoid a string copy :-)
@ -382,22 +411,27 @@ nsTSubstring_CharT::Assign( const self_type& str )
// get an owning reference to the mData // get an owning reference to the mData
nsStringBuffer::FromData(mData)->AddRef(); nsStringBuffer::FromData(mData)->AddRef();
return true;
} }
else
{ // else, treat this like an ordinary assignment.
// else, treat this like an ordinary assignment. return Assign(str.Data(), str.Length(), fallible_t());
Assign(str.Data(), str.Length());
}
} }
void void
nsTSubstring_CharT::Assign( const substring_tuple_type& tuple ) nsTSubstring_CharT::Assign( const substring_tuple_type& tuple )
{
if (!Assign(tuple, fallible_t()))
NS_RUNTIMEABORT("OOM");
}
bool
nsTSubstring_CharT::Assign( const substring_tuple_type& tuple, const fallible_t& )
{ {
if (tuple.IsDependentOn(mData, mData + mLength)) if (tuple.IsDependentOn(mData, mData + mLength))
{ {
// take advantage of sharing here... // take advantage of sharing here...
Assign(string_type(tuple)); return Assign(string_type(tuple), fallible_t());
return;
} }
size_type length = tuple.Length(); size_type length = tuple.Length();
@ -405,14 +439,16 @@ nsTSubstring_CharT::Assign( const substring_tuple_type& tuple )
// don't use ReplacePrep here because it changes the length // don't use ReplacePrep here because it changes the length
char_type* oldData; char_type* oldData;
PRUint32 oldFlags; PRUint32 oldFlags;
if (MutatePrep(length, &oldData, &oldFlags)) { if (!MutatePrep(length, &oldData, &oldFlags))
if (oldData) return false;
::ReleaseData(oldData, oldFlags);
tuple.WriteTo(mData, length); if (oldData)
mData[length] = 0; ::ReleaseData(oldData, oldFlags);
mLength = length;
} tuple.WriteTo(mData, length);
mData[length] = 0;
mLength = length;
return true;
} }
void void
@ -522,8 +558,15 @@ nsTSubstring_CharT::Replace( index_type cutStart, size_type cutLength, const sub
tuple.WriteTo(mData + cutStart, length); tuple.WriteTo(mData + cutStart, length);
} }
bool void
nsTSubstring_CharT::SetCapacity( size_type capacity ) nsTSubstring_CharT::SetCapacity( size_type capacity )
{
if (!SetCapacity(capacity, fallible_t()))
NS_RUNTIMEABORT("OOM");
}
bool
nsTSubstring_CharT::SetCapacity( size_type capacity, const fallible_t& )
{ {
// capacity does not include room for the terminating null char // capacity does not include room for the terminating null char
@ -534,42 +577,48 @@ nsTSubstring_CharT::SetCapacity( size_type capacity )
mData = char_traits::sEmptyBuffer; mData = char_traits::sEmptyBuffer;
mLength = 0; mLength = 0;
SetDataFlags(F_TERMINATED); SetDataFlags(F_TERMINATED);
return true;
} }
else
char_type* oldData;
PRUint32 oldFlags;
if (!MutatePrep(capacity, &oldData, &oldFlags))
return false; // out-of-memory
// compute new string length
size_type newLen = NS_MIN(mLength, capacity);
if (oldData)
{ {
char_type* oldData; // preserve old data
PRUint32 oldFlags; if (mLength > 0)
if (!MutatePrep(capacity, &oldData, &oldFlags)) char_traits::copy(mData, oldData, newLen);
return false; // out-of-memory
// compute new string length ::ReleaseData(oldData, oldFlags);
size_type newLen = NS_MIN(mLength, capacity);
if (oldData)
{
// preserve old data
if (mLength > 0)
char_traits::copy(mData, oldData, newLen);
::ReleaseData(oldData, oldFlags);
}
// adjust mLength if our buffer shrunk down in size
if (newLen < mLength)
mLength = newLen;
// always null-terminate here, even if the buffer got longer. this is
// for backwards compat with the old string implementation.
mData[capacity] = char_type(0);
} }
// adjust mLength if our buffer shrunk down in size
if (newLen < mLength)
mLength = newLen;
// always null-terminate here, even if the buffer got longer. this is
// for backwards compat with the old string implementation.
mData[capacity] = char_type(0);
return true; return true;
} }
bool void
nsTSubstring_CharT::SetLength( size_type length ) nsTSubstring_CharT::SetLength( size_type length )
{ {
if (!SetCapacity(length)) SetCapacity(length);
mLength = length;
}
bool
nsTSubstring_CharT::SetLength( size_type length, const fallible_t& )
{
if (!SetCapacity(length, fallible_t()))
return false; return false;
mLength = length; mLength = length;
@ -683,7 +732,8 @@ nsTSubstring_CharT::StripChar( char_type aChar, PRInt32 aOffset )
if (mLength == 0 || aOffset >= PRInt32(mLength)) if (mLength == 0 || aOffset >= PRInt32(mLength))
return; return;
EnsureMutable(); // XXX do this lazily? if (!EnsureMutable()) // XXX do this lazily?
NS_RUNTIMEABORT("OOM");
// XXX(darin): this code should defer writing until necessary. // XXX(darin): this code should defer writing until necessary.
@ -707,7 +757,8 @@ nsTSubstring_CharT::StripChars( const char_type* aChars, PRUint32 aOffset )
if (aOffset >= PRUint32(mLength)) if (aOffset >= PRUint32(mLength))
return; return;
EnsureMutable(); // XXX do this lazily? if (!EnsureMutable()) // XXX do this lazily?
NS_RUNTIMEABORT("OOM");
// XXX(darin): this code should defer writing until necessary. // XXX(darin): this code should defer writing until necessary.