Backout 345ae68f15f4, b3b40121ac8d, 0d18b7a246d7, 9dbb6064ab58, dee9d7fa8eb6, 63eec6bfa948, 323c6be7cfe8 & f4aac7523a48 (bug 732875) for compilation failures

This commit is contained in:
Ed Morley 2012-05-14 21:05:24 +01:00
Родитель fa8d5e0469
Коммит 0f956d7307
29 изменённых файлов: 1174 добавлений и 1391 удалений

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

@ -70,7 +70,7 @@ nsDOMMultipartFile::GetSize(PRUint64* aLength)
length += l;
}
NS_ENSURE_TRUE(length.isValid(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(length.valid(), NS_ERROR_FAILURE);
mLength = length.value();
}

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

@ -39,8 +39,9 @@
#define nsDOMBlobBuilder_h
#include "nsDOMFile.h"
#include "CheckedInt.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/StandardInteger.h"
using namespace mozilla;
@ -127,10 +128,10 @@ protected:
// Start at 1 or we'll loop forever.
CheckedUint32 bufferLen = NS_MAX<PRUint32>(mDataBufferLen, 1);
while (bufferLen.isValid() && bufferLen.value() < mDataLen + aSize)
while (bufferLen.valid() && bufferLen.value() < mDataLen + aSize)
bufferLen *= 2;
if (!bufferLen.isValid())
if (!bufferLen.valid())
return false;
// PR_ memory functions are still fallible

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

@ -61,8 +61,8 @@
#include "nsIUUIDGenerator.h"
#include "nsBlobProtocolHandler.h"
#include "nsStringStream.h"
#include "CheckedInt.h"
#include "nsJSUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Preferences.h"
#include "plbase64.h"
@ -227,7 +227,7 @@ ParseSize(PRInt64 aSize, PRInt64& aStart, PRInt64& aEnd)
newEndOffset = aSize;
}
if (!newStartOffset.isValid() || !newEndOffset.isValid() ||
if (!newStartOffset.valid() || !newEndOffset.valid() ||
newStartOffset.value() >= newEndOffset.value()) {
aStart = aEnd = 0;
}

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

@ -40,7 +40,7 @@
#include "prtypes.h"
#include "mozilla/CheckedInt.h"
#include "CheckedInt.h"
class nsHTMLCanvasElement;
class nsIPrincipal;
@ -63,9 +63,9 @@ inline bool CheckSaneSubrectSize(PRInt32 x, PRInt32 y, PRInt32 w, PRInt32 h,
CheckedInt32 checked_ymost = CheckedInt32(y) + h;
return w >= 0 && h >= 0 && x >= 0 && y >= 0 &&
checked_xmost.isValid() &&
checked_xmost.valid() &&
checked_xmost.value() <= realWidth &&
checked_ymost.isValid() &&
checked_ymost.valid() &&
checked_ymost.value() <= realHeight;
}

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

@ -40,7 +40,7 @@
#include "nsDOMError.h"
#include "nsIDOMCanvasRenderingContext2D.h"
#include "mozilla/CheckedInt.h"
#include "CheckedInt.h"
#include "nsMathUtils.h"
#include "CustomQS_Canvas.h"
@ -169,7 +169,7 @@ CreateImageData(JSContext* cx, JSObject* obj, uint32_t w, uint32_t h, jsval* vp)
h = 1;
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(w) * h * 4;
if (!len.isValid()) {
if (!len.valid()) {
return xpc_qsThrow(cx, NS_ERROR_DOM_INDEX_SIZE_ERR);
}

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

@ -425,7 +425,7 @@ WebGLContext::SetDimensions(PRInt32 width, PRInt32 height)
// If incrementing the generation would cause overflow,
// don't allow it. Allowing this would allow us to use
// resource handles created from older context generations.
if (!(mGeneration + 1).isValid())
if (!(mGeneration+1).valid())
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
gl::ContextFormat format(gl::ContextFormat::BasicRGBA32);

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

@ -64,9 +64,9 @@
#include "GLContextProvider.h"
#include "Layers.h"
#include "CheckedInt.h"
#include "nsDataHashtable.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ImageData.h"
#ifdef XP_MACOSX
@ -481,7 +481,7 @@ public:
private:
WebGLMonotonicHandle NextMonotonicHandle() {
++mCurrentMonotonicHandle;
if (!mCurrentMonotonicHandle.isValid())
if (!mCurrentMonotonicHandle.valid())
NS_RUNTIMEABORT("ran out of monotonic ids!");
return mCurrentMonotonicHandle.value();
}
@ -1748,7 +1748,7 @@ public:
bool HasImageInfoAt(size_t level, size_t face) const {
CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
return checked_index.isValid() &&
return checked_index.valid() &&
checked_index.value() < mImageInfos.Length() &&
ImageInfoAt(level, face).mIsDefined;
}
@ -2328,7 +2328,7 @@ public:
bool NextGeneration()
{
if (!(mGeneration + 1).isValid())
if (!(mGeneration+1).valid())
return false; // must exit without changing mGeneration
++mGeneration;
return true;

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

@ -687,7 +687,7 @@ WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
return ErrorInvalidOperation("BufferData: no buffer bound!");
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data->mLength;
if (!checked_neededByteLength.isValid())
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
if (checked_neededByteLength.value() > boundBuffer->ByteLength())
@ -726,7 +726,7 @@ WebGLContext::BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
return ErrorInvalidOperation("BufferSubData: no buffer bound!");
CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.mLength;
if (!checked_neededByteLength.isValid())
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
if (checked_neededByteLength.value() > boundBuffer->ByteLength())
@ -941,7 +941,7 @@ WebGLContext::CopyTexSubImage2D_base(WebGLenum target,
CheckedUint32 checked_neededByteLength =
GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.isValid())
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
PRUint32 bytesNeeded = checked_neededByteLength.value();
@ -1562,7 +1562,7 @@ WebGLContext::DoFakeVertexAttrib0(WebGLuint vertexCount)
CheckedUint32 checked_dataSize = CheckedUint32(vertexCount) * 4 * sizeof(WebGLfloat);
if (!checked_dataSize.isValid()) {
if (!checked_dataSize.valid()) {
ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
"with %d vertices. Try reducing the number of vertices.", vertexCount);
return false;
@ -1779,7 +1779,7 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
CheckedInt32 checked_firstPlusCount = CheckedInt32(first) + count;
if (!checked_firstPlusCount.isValid())
if (!checked_firstPlusCount.valid())
return ErrorInvalidOperation("drawArrays: overflow in first+count");
if (checked_firstPlusCount.value() > maxAllowedCount)
@ -1847,7 +1847,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
return ErrorInvalidEnum("DrawElements: type must be UNSIGNED_SHORT or UNSIGNED_BYTE");
}
if (!checked_byteCount.isValid())
if (!checked_byteCount.valid())
return ErrorInvalidValue("DrawElements: overflow in byteCount");
// If there is no current program, this is silently ignored.
@ -1863,7 +1863,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
CheckedUint32 checked_neededByteCount = checked_byteCount + byteOffset;
if (!checked_neededByteCount.isValid())
if (!checked_neededByteCount.valid())
return ErrorInvalidOperation("DrawElements: overflow in byteOffset+byteCount");
if (checked_neededByteCount.value() > mBoundElementArrayBuffer->ByteLength())
@ -1880,7 +1880,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
CheckedInt32 checked_maxIndexPlusOne = CheckedInt32(maxIndex) + 1;
if (!checked_maxIndexPlusOne.isValid() ||
if (!checked_maxIndexPlusOne.valid() ||
checked_maxIndexPlusOne.value() > maxAllowedCount)
{
// the index array contains invalid indices for the current drawing state, but they
@ -1893,7 +1893,7 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
CheckedInt32 checked_maxIndexInSubArrayPlusOne = CheckedInt32(maxIndexInSubArray) + 1;
if (!checked_maxIndexInSubArrayPlusOne.isValid() ||
if (!checked_maxIndexInSubArrayPlusOne.valid() ||
checked_maxIndexInSubArrayPlusOne.value() > maxAllowedCount)
{
return ErrorInvalidOperation(
@ -3883,7 +3883,7 @@ WebGLContext::ReadPixels(WebGLint x, WebGLint y, WebGLsizei width,
CheckedUint32 checked_alignedRowSize =
RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
if (!checked_neededByteLength.isValid())
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("ReadPixels: integer overflow computing the needed buffer size");
if (checked_neededByteLength.value() > dataByteLen)
@ -5601,7 +5601,7 @@ WebGLContext::TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum intern
CheckedUint32 checked_alignedRowSize =
RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.isValid())
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
PRUint32 bytesNeeded = checked_neededByteLength.value();
@ -5842,7 +5842,7 @@ WebGLContext::TexSubImage2D_base(WebGLenum target, WebGLint level,
CheckedUint32 checked_alignedRowSize =
RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
if (!checked_neededByteLength.isValid())
if (!checked_neededByteLength.valid())
return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
PRUint32 bytesNeeded = checked_neededByteLength.value();

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

@ -40,7 +40,8 @@
#include "WebGLContext.h"
#include "mozilla/Preferences.h"
#include "mozilla/CheckedInt.h"
#include "CheckedInt.h"
#include "jsfriendapi.h"
@ -142,8 +143,8 @@ WebGLContext::ValidateBuffers(PRInt32 *maxAllowedCount, const char *info)
CheckedInt32 checked_sizeOfLastElement
= CheckedInt32(vd.componentSize()) * vd.size;
if (!checked_byteLength.isValid() ||
!checked_sizeOfLastElement.isValid())
if (!checked_byteLength.valid() ||
!checked_sizeOfLastElement.valid())
{
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
@ -155,7 +156,7 @@ WebGLContext::ValidateBuffers(PRInt32 *maxAllowedCount, const char *info)
CheckedInt32 checked_maxAllowedCount
= ((checked_byteLength - checked_sizeOfLastElement) / vd.actualStride()) + 1;
if (!checked_maxAllowedCount.isValid()) {
if (!checked_maxAllowedCount.valid()) {
ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info, i);
return false;
}
@ -400,7 +401,7 @@ bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum forma
{
CheckedUint32 calculated_byteLength = 0;
CheckedUint32 checked_byteLength = byteLength;
if (!checked_byteLength.isValid()) {
if (!checked_byteLength.valid()) {
ErrorInvalidValue("%s: data length out of bounds", info);
return false;
}
@ -410,7 +411,7 @@ bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum forma
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
{
calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
if (!calculated_byteLength.isValid() || !(checked_byteLength == calculated_byteLength)) {
if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) {
ErrorInvalidValue("%s: data size does not match dimensions", info);
return false;
}
@ -420,7 +421,7 @@ bool WebGLContext::ValidateCompressedTextureSize(WebGLint level, WebGLenum forma
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
{
calculated_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
if (!calculated_byteLength.isValid() || !(checked_byteLength == calculated_byteLength)) {
if (!calculated_byteLength.valid() || !(checked_byteLength == calculated_byteLength)) {
ErrorInvalidValue("%s: data size does not match dimensions", info);
return false;
}

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

@ -108,6 +108,7 @@
#include "nsIMemoryReporter.h"
#include "nsStyleUtil.h"
#include "CanvasImageCache.h"
#include "CheckedInt.h"
#include <algorithm>
@ -115,7 +116,6 @@
#include "jsfriendapi.h"
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h"
@ -3926,14 +3926,14 @@ nsCanvasRenderingContext2D::GetImageDataArray(JSContext* aCx,
MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
if (!len.isValid()) {
if (!len.valid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight;
if (!rightMost.isValid() || !bottomMost.isValid()) {
if (!rightMost.valid() || !bottomMost.valid()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@ -4066,7 +4066,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth;
if (!checkedDirtyX.isValid())
if (!checkedDirtyX.valid())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyX = checkedDirtyX.value();
@ -4078,7 +4078,7 @@ nsCanvasRenderingContext2D::PutImageData_explicit(PRInt32 x, PRInt32 y, PRUint32
CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight;
if (!checkedDirtyY.isValid())
if (!checkedDirtyY.valid())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyY = checkedDirtyY.value();

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

@ -104,6 +104,7 @@
#include "nsIMemoryReporter.h"
#include "nsStyleUtil.h"
#include "CanvasImageCache.h"
#include "CheckedInt.h"
#include <algorithm>
@ -111,7 +112,6 @@
#include "jsfriendapi.h"
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h"
@ -4095,14 +4095,14 @@ nsCanvasRenderingContext2DAzure::GetImageDataArray(JSContext* aCx,
MOZ_ASSERT(aWidth && aHeight);
CheckedInt<uint32_t> len = CheckedInt<uint32_t>(aWidth) * aHeight * 4;
if (!len.isValid()) {
if (!len.valid()) {
return NS_ERROR_DOM_INDEX_SIZE_ERR;
}
CheckedInt<int32_t> rightMost = CheckedInt<int32_t>(aX) + aWidth;
CheckedInt<int32_t> bottomMost = CheckedInt<int32_t>(aY) + aHeight;
if (!rightMost.isValid() || !bottomMost.isValid()) {
if (!rightMost.valid() || !bottomMost.valid()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
@ -4233,7 +4233,7 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(PRInt32 x, PRInt32 y, PRU
CheckedInt32 checkedDirtyX = CheckedInt32(dirtyX) + dirtyWidth;
if (!checkedDirtyX.isValid())
if (!checkedDirtyX.valid())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyX = checkedDirtyX.value();
@ -4245,7 +4245,7 @@ nsCanvasRenderingContext2DAzure::PutImageData_explicit(PRInt32 x, PRInt32 y, PRU
CheckedInt32 checkedDirtyY = CheckedInt32(dirtyY) + dirtyHeight;
if (!checkedDirtyY.isValid())
if (!checkedDirtyY.valid())
return NS_ERROR_DOM_INDEX_SIZE_ERR;
dirtyY = checkedDirtyY.value();

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

@ -38,10 +38,10 @@
#include "nsHTMLCanvasElement.h"
#include "mozilla/Base64.h"
#include "mozilla/CheckedInt.h"
#include "nsNetUtil.h"
#include "prmem.h"
#include "nsDOMFile.h"
#include "CheckedInt.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h"

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

@ -40,12 +40,13 @@
#define VideoUtils_h
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/CheckedInt.h"
#include "nsRect.h"
#include "nsIThreadManager.h"
#include "nsThreadUtils.h"
#include "CheckedInt.h"
using mozilla::CheckedInt64;
using mozilla::CheckedUint64;
using mozilla::CheckedInt32;

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

@ -164,8 +164,8 @@ VideoData* VideoData::Create(nsVideoInfo& aInfo,
// the frame we've been supplied without indexing out of bounds.
CheckedUint32 xLimit = aPicture.x + CheckedUint32(aPicture.width);
CheckedUint32 yLimit = aPicture.y + CheckedUint32(aPicture.height);
if (!xLimit.isValid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
!yLimit.isValid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
if (!xLimit.valid() || xLimit.value() > aBuffer.mPlanes[0].mStride ||
!yLimit.valid() || yLimit.value() > aBuffer.mPlanes[0].mHeight)
{
// The specified picture dimensions can't be contained inside the video
// frame, we'll stomp memory if we try to copy it. Fail.
@ -346,7 +346,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
break;
CheckedInt64 startFrame = UsecsToFrames(audio->mTime, mInfo.mAudioRate);
CheckedInt64 targetFrame = UsecsToFrames(aTarget, mInfo.mAudioRate);
if (!startFrame.isValid() || !targetFrame.isValid()) {
if (!startFrame.valid() || !targetFrame.valid()) {
return NS_ERROR_FAILURE;
}
if (startFrame.value() + audio->mFrames <= targetFrame.value()) {
@ -390,7 +390,7 @@ nsresult nsBuiltinDecoderReader::DecodeToTarget(PRInt64 aTarget)
audio->mAudioData.get() + (framesToPrune * channels),
frames * channels * sizeof(AudioDataValue));
CheckedInt64 duration = FramesToUsecs(frames, mInfo.mAudioRate);
if (!duration.isValid()) {
if (!duration.valid()) {
return NS_ERROR_FAILURE;
}
nsAutoPtr<AudioData> data(new AudioData(audio->mOffset,

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

@ -547,7 +547,7 @@ void nsBuiltinDecoderStateMachine::SendOutputStreamAudio(AudioData* aAudio,
CheckedInt64 audioWrittenOffset = UsecsToFrames(mInfo.mAudioRate,
aStream->mAudioFramesWrittenBaseTime + mStartTime) + aStream->mAudioFramesWritten;
CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudioRate, aAudio->mTime);
if (!audioWrittenOffset.isValid() || !frameOffset.isValid())
if (!audioWrittenOffset.valid() || !frameOffset.valid())
return;
if (audioWrittenOffset.value() < frameOffset.value()) {
// Write silence to catch up
@ -1115,7 +1115,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
// samples.
CheckedInt64 sampleTime = UsecsToFrames(s->mTime, rate);
CheckedInt64 missingFrames = sampleTime - playedFrames;
if (!missingFrames.isValid() || !sampleTime.isValid()) {
if (!missingFrames.valid() || !sampleTime.valid()) {
NS_WARNING("Int overflow adding in AudioLoop()");
break;
}
@ -1139,7 +1139,7 @@ void nsBuiltinDecoderStateMachine::AudioLoop()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
CheckedInt64 playedUsecs = FramesToUsecs(audioDuration, rate) + audioStartTime;
if (!playedUsecs.isValid()) {
if (!playedUsecs.valid()) {
NS_WARNING("Int overflow calculating audio end time");
break;
}

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

@ -353,10 +353,10 @@ PRInt64 nsTheoraState::Time(th_info* aInfo, PRInt64 aGranulepos)
ogg_int64_t pframe = aGranulepos - (iframe << shift);
PRInt64 frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1);
CheckedInt64 t = ((CheckedInt64(frameno) + 1) * USECS_PER_S) * aInfo->fps_denominator;
if (!t.isValid())
if (!t.valid())
return -1;
t /= aInfo->fps_numerator;
return t.isValid() ? t.value() : -1;
return t.valid() ? t.value() : -1;
}
PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) {
@ -364,7 +364,7 @@ PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) {
return -1;
}
CheckedInt64 t = (CheckedInt64(th_granule_frame(mCtx, granulepos)) * USECS_PER_S) * mInfo.fps_denominator;
if (!t.isValid())
if (!t.valid())
return -1;
return t.value() / mInfo.fps_numerator;
}
@ -622,7 +622,7 @@ PRInt64 nsVorbisState::Time(vorbis_info* aInfo, PRInt64 aGranulepos)
return -1;
}
CheckedInt64 t = CheckedInt64(aGranulepos) * USECS_PER_S;
if (!t.isValid())
if (!t.valid())
t = 0;
return t.value() / aInfo->rate;
}
@ -884,7 +884,7 @@ PRInt64 nsOpusState::Time(PRInt64 granulepos)
// Ogg Opus always runs at a granule rate of 48 kHz.
CheckedInt64 t = CheckedInt64(granulepos - mPreSkip) * USECS_PER_S;
return t.isValid() ? t.value() / mRate : -1;
return t.valid() ? t.value() / mRate : -1;
}
bool nsOpusState::IsHeader(ogg_packet* aPacket)
@ -1048,7 +1048,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
// Extract the start time.
CheckedInt64 t = CheckedInt64(LEInt64(p + INDEX_FIRST_NUMER_OFFSET)) * USECS_PER_S;
if (!t.isValid()) {
if (!t.valid()) {
return (mActive = false);
} else {
startTime = t.value() / timeDenom;
@ -1056,7 +1056,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
// Extract the end time.
t = LEInt64(p + INDEX_LAST_NUMER_OFFSET) * USECS_PER_S;
if (!t.isValid()) {
if (!t.valid()) {
return (mActive = false);
} else {
endTime = t.value() / timeDenom;
@ -1065,7 +1065,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
// Check the numKeyPoints value read, ensure we're not going to run out of
// memory while trying to decode the index packet.
CheckedInt64 minPacketSize = (CheckedInt64(numKeyPoints) * MIN_KEY_POINT_SIZE) + INDEX_KEYPOINT_OFFSET;
if (!minPacketSize.isValid())
if (!minPacketSize.valid())
{
return (mActive = false);
}
@ -1103,7 +1103,7 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
p = ReadVariableLengthInt(p, limit, delta);
offset += delta;
if (p == limit ||
!offset.isValid() ||
!offset.valid() ||
offset.value() > mLength ||
offset.value() < 0)
{
@ -1111,14 +1111,14 @@ bool nsSkeletonState::DecodeIndex(ogg_packet* aPacket)
}
p = ReadVariableLengthInt(p, limit, delta);
time += delta;
if (!time.isValid() ||
if (!time.valid() ||
time.value() > endTime ||
time.value() < startTime)
{
return (mActive = false);
}
CheckedInt64 timeUsecs = time * USECS_PER_S;
if (!timeUsecs.isValid())
if (!timeUsecs.valid())
return mActive = false;
timeUsecs /= timeDenom;
keyPoints->Add(offset.value(), timeUsecs.value());
@ -1228,8 +1228,8 @@ nsresult nsSkeletonState::GetDuration(const nsTArray<PRUint32>& aTracks,
}
NS_ASSERTION(endTime > startTime, "Duration must be positive");
CheckedInt64 duration = CheckedInt64(endTime) - startTime;
aDuration = duration.isValid() ? duration.value() : 0;
return duration.isValid() ? NS_OK : NS_ERROR_FAILURE;
aDuration = duration.valid() ? duration.value() : 0;
return duration.valid() ? NS_OK : NS_ERROR_FAILURE;
}
bool nsSkeletonState::DecodeHeader(ogg_packet* aPacket)

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

@ -87,7 +87,7 @@ nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo)
CheckedUint32 dummy = CheckedUint32(static_cast<PRUint32>(mMetadata.frameWidth)) *
static_cast<PRUint32>(mMetadata.frameHeight);
NS_ENSURE_TRUE(dummy.isValid(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(dummy.valid(), NS_ERROR_FAILURE);
if (mMetadata.aspectDenominator == 0 ||
mMetadata.framerateDenominator == 0)
@ -268,7 +268,7 @@ nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime,
CheckedUint32 offset = CheckedUint32(mCurrentFrame) * mFrameSize;
offset += sizeof(nsRawVideoHeader);
NS_ENSURE_TRUE(offset.isValid(), NS_ERROR_FAILURE);
NS_ENSURE_TRUE(offset.valid(), NS_ERROR_FAILURE);
nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, offset.value());
NS_ENSURE_SUCCESS(rv, rv);

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

@ -448,12 +448,12 @@ bool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
// from after the gap.
CheckedInt64 tstamp_frames = UsecsToFrames(tstamp_usecs, rate);
CheckedInt64 decoded_frames = UsecsToFrames(mAudioStartUsec, rate);
if (!tstamp_frames.isValid() || !decoded_frames.isValid()) {
if (!tstamp_frames.valid() || !decoded_frames.valid()) {
NS_WARNING("Int overflow converting WebM times to frames");
return false;
}
decoded_frames += mAudioFrames;
if (!decoded_frames.isValid()) {
if (!decoded_frames.valid()) {
NS_WARNING("Int overflow adding decoded_frames");
return false;
}
@ -461,7 +461,7 @@ bool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
#ifdef DEBUG
CheckedInt64 usecs = FramesToUsecs(tstamp_frames.value() - decoded_frames.value(), rate);
LOG(PR_LOG_DEBUG, ("WebMReader detected gap of %lld, %lld frames, in audio stream\n",
usecs.isValid() ? usecs.value() : -1,
usecs.valid() ? usecs.value(): -1,
tstamp_frames.value() - decoded_frames.value()));
#endif
mPacketCount++;
@ -501,18 +501,18 @@ bool nsWebMReader::DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset)
}
CheckedInt64 duration = FramesToUsecs(frames, rate);
if (!duration.isValid()) {
if (!duration.valid()) {
NS_WARNING("Int overflow converting WebM audio duration");
return false;
}
CheckedInt64 total_duration = FramesToUsecs(total_frames, rate);
if (!total_duration.isValid()) {
if (!total_duration.valid()) {
NS_WARNING("Int overflow converting WebM audio total_duration");
return false;
}
CheckedInt64 time = total_duration + tstamp_usecs;
if (!time.isValid()) {
if (!time.valid()) {
NS_WARNING("Int overflow adding total_duration and tstamp_usecs");
nestegg_free_packet(aPacket);
return false;

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

@ -39,7 +39,7 @@
#include <math.h>
#include <string.h>
#include "mozilla/CheckedInt.h"
#include "CheckedInt.h"
#include "mozilla/Util.h"
#ifndef M_PI
@ -81,7 +81,7 @@ BoxBlurHorizontal(unsigned char* aInput,
memcpy(aOutput, aInput, aWidth*aRows);
return;
}
uint32_t reciprocal = (uint64_t(1) << 32) / boxSize;
PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize;
for (int32_t y = 0; y < aRows; y++) {
// Check whether the skip rect intersects this row. If the skip
@ -128,7 +128,7 @@ BoxBlurHorizontal(unsigned char* aInput,
int32_t last = max(tmp, 0);
int32_t next = min(tmp + boxSize, aWidth - 1);
aOutput[aWidth * y + x] = (uint64_t(alphaSum) * reciprocal) >> 32;
aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32;
alphaSum += aInput[aWidth * y + next] -
aInput[aWidth * y + last];
@ -159,7 +159,7 @@ BoxBlurVertical(unsigned char* aInput,
memcpy(aOutput, aInput, aWidth*aRows);
return;
}
uint32_t reciprocal = (uint64_t(1) << 32) / boxSize;
PRUint32 reciprocal = (PRUint64(1) << 32)/boxSize;
for (int32_t x = 0; x < aWidth; x++) {
bool inSkipRectX = x >= aSkipRect.x &&
@ -199,7 +199,7 @@ BoxBlurVertical(unsigned char* aInput,
int32_t last = max(tmp, 0);
int32_t next = min(tmp + boxSize, aRows - 1);
aOutput[aWidth * y + x] = (uint64_t(alphaSum) * reciprocal) >> 32;
aOutput[aWidth * y + x] = (PRUint64(alphaSum)*reciprocal) >> 32;
alphaSum += aInput[aWidth * next + x] -
aInput[aWidth * last + x];
@ -409,12 +409,12 @@ AlphaBoxBlur::AlphaBoxBlur(const Rect& aRect,
mRect = IntRect(rect.x, rect.y, rect.width, rect.height);
CheckedInt<int32_t> stride = RoundUpToMultipleOf4(mRect.width);
if (stride.isValid()) {
if (stride.valid()) {
mStride = stride.value();
CheckedInt<int32_t> size = CheckedInt<int32_t>(mStride) * mRect.height *
sizeof(unsigned char);
if (size.isValid()) {
if (size.valid()) {
mData = static_cast<unsigned char*>(malloc(size.value()));
memset(mData, 0, size.value());
}

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

@ -38,7 +38,7 @@
#include "nsIMemoryReporter.h"
#include "nsMemory.h"
#include "mozilla/CheckedInt.h"
#include "CheckedInt.h"
#include "gfxASurface.h"
#include "gfxContext.h"
@ -378,7 +378,7 @@ gfxASurface::CheckSurfaceSize(const gfxIntSize& sz, PRInt32 limit)
// make sure the surface area doesn't overflow a PRInt32
CheckedInt<PRInt32> tmp = sz.width;
tmp *= sz.height;
if (!tmp.isValid()) {
if (!tmp.valid()) {
NS_WARNING("Surface size too large (would overflow)!");
return false;
}
@ -386,7 +386,7 @@ gfxASurface::CheckSurfaceSize(const gfxIntSize& sz, PRInt32 limit)
// assuming 4-byte stride, make sure the allocation size
// doesn't overflow a PRInt32 either
tmp *= 4;
if (!tmp.isValid()) {
if (!tmp.valid()) {
NS_WARNING("Allocation too large (would overflow)!");
return false;
}

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

@ -1,789 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
/* Provides checked integers, detecting integer overflow and divide-by-0. */
#ifndef mozilla_CheckedInt_h_
#define mozilla_CheckedInt_h_
/*
* Build options. Comment out these #defines to disable the corresponding
* optional feature. Disabling features may be useful for code using
* CheckedInt outside of Mozilla (e.g. WebKit)
*/
// Enable usage of MOZ_STATIC_ASSERT to check for unsupported types.
// If disabled, static asserts are replaced by regular assert().
#define MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
/*
* End of build options
*/
#ifdef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
# include "mozilla/Assertions.h"
#else
# ifndef MOZ_STATIC_ASSERT
# include <cassert>
# define MOZ_STATIC_ASSERT(cond, reason) assert((cond) && reason)
# define MOZ_ASSERT(cond, reason) assert((cond) && reason)
# endif
#endif
#include "mozilla/StandardInteger.h"
#include <climits>
#include <cstddef>
namespace mozilla {
namespace detail {
/*
* Step 1: manually record supported types
*
* What's nontrivial here is that there are different families of integer
* types: basic integer types and stdint types. It is merrily undefined which
* types from one family may be just typedefs for a type from another family.
*
* For example, on GCC 4.6, aside from the basic integer types, the only other
* type that isn't just a typedef for some of them, is int8_t.
*/
struct UnsupportedType {};
template<typename IntegerType>
struct IsSupportedPass2
{
static const bool value = false;
};
template<typename IntegerType>
struct IsSupported
{
static const bool value = IsSupportedPass2<IntegerType>::value;
};
template<>
struct IsSupported<int8_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint8_t>
{ static const bool value = true; };
template<>
struct IsSupported<int16_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint16_t>
{ static const bool value = true; };
template<>
struct IsSupported<int32_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint32_t>
{ static const bool value = true; };
template<>
struct IsSupported<int64_t>
{ static const bool value = true; };
template<>
struct IsSupported<uint64_t>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned char>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<short>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned short>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<int>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned int>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<long>
{ static const bool value = true; };
template<>
struct IsSupportedPass2<unsigned long>
{ static const bool value = true; };
/*
* Step 2: some integer-traits kind of stuff.
*/
template<size_t Size, bool Signedness>
struct StdintTypeForSizeAndSignedness
{};
template<>
struct StdintTypeForSizeAndSignedness<1, true>
{ typedef int8_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<1, false>
{ typedef uint8_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<2, true>
{ typedef int16_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<2, false>
{ typedef uint16_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<4, true>
{ typedef int32_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<4, false>
{ typedef uint32_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<8, true>
{ typedef int64_t Type; };
template<>
struct StdintTypeForSizeAndSignedness<8, false>
{ typedef uint64_t Type; };
template<typename IntegerType>
struct UnsignedType
{
typedef typename StdintTypeForSizeAndSignedness<sizeof(IntegerType),
false>::Type Type;
};
template<typename IntegerType>
struct IsSigned
{
static const bool value = IntegerType(-1) <= IntegerType(0);
};
template<typename IntegerType, size_t Size = sizeof(IntegerType)>
struct TwiceBiggerType
{
typedef typename StdintTypeForSizeAndSignedness<
sizeof(IntegerType) * 2,
IsSigned<IntegerType>::value
>::Type Type;
};
template<typename IntegerType>
struct TwiceBiggerType<IntegerType, 8>
{
typedef UnsupportedType Type;
};
template<typename IntegerType>
struct PositionOfSignBit
{
static const size_t value = CHAR_BIT * sizeof(IntegerType) - 1;
};
template<typename IntegerType>
struct MinValue
{
static IntegerType value()
{
// Bitwise ops may return a larger type, that's why we cast explicitly.
// In C++, left bit shifts on signed values is undefined by the standard
// unless the shifted value is representable.
// Notice that signed-to-unsigned conversions are always well-defined in
// the standard as the value congruent to 2**n, as expected. By contrast,
// unsigned-to-signed is only well-defined if the value is representable.
return IsSigned<IntegerType>::value
? IntegerType(typename UnsignedType<IntegerType>::Type(1)
<< PositionOfSignBit<IntegerType>::value)
: IntegerType(0);
}
};
template<typename IntegerType>
struct MaxValue
{
static IntegerType value()
{
// Tricksy, but covered by the unit test.
// Relies heavily on the return type of MinValue<IntegerType>::value()
// being IntegerType.
return ~MinValue<IntegerType>::value();
}
};
/*
* Step 3: Implement the actual validity checks.
*
* Ideas taken from IntegerLib, code different.
*/
// Bitwise ops may return a larger type, so it's good to use these inline
// helpers guaranteeing that the result is really of type T.
template<typename T>
inline T
HasSignBit(T x)
{
// In C++, right bit shifts on negative values is undefined by the standard.
// Notice that signed-to-unsigned conversions are always well-defined in the
// standard, as the value congruent modulo 2**n as expected. By contrast,
// unsigned-to-signed is only well-defined if the value is representable.
// Here the unsigned-to-signed conversion is OK because the value
// (the result of the shift) is 0 or 1.
return T(typename UnsignedType<T>::Type(x)
>> PositionOfSignBit<T>::value);
}
template<typename T>
inline T
BinaryComplement(T x)
{
return ~x;
}
template<typename T,
typename U,
bool IsTSigned = IsSigned<T>::value,
bool IsUSigned = IsSigned<U>::value>
struct IsInRangeImpl {};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, true>
{
static bool run(U x)
{
return x <= MaxValue<T>::value() &&
x >= MinValue<T>::value();
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, false, false>
{
static bool run(U x)
{
return x <= MaxValue<T>::value();
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, true, false>
{
static bool run(U x)
{
return sizeof(T) > sizeof(U)
? true
: x <= U(MaxValue<T>::value());
}
};
template<typename T, typename U>
struct IsInRangeImpl<T, U, false, true>
{
static bool run(U x)
{
return sizeof(T) >= sizeof(U)
? x >= 0
: x >= 0 && x <= U(MaxValue<T>::value());
}
};
template<typename T, typename U>
inline bool
IsInRange(U x)
{
return IsInRangeImpl<T, U>::run(x);
}
template<typename T>
inline bool
IsAddValid(T x, T y, T result)
{
// Addition is valid if the sign of x+y is equal to either that of x or that
// of y. Beware! These bitwise operations can return a larger integer type,
// if T was a small type like int8_t, so we explicitly cast to T.
return IsSigned<T>::value
? HasSignBit(BinaryComplement(T((result ^ x) & (result ^ y))))
: BinaryComplement(x) >= y;
}
template<typename T>
inline bool
IsSubValid(T x, T y, T result)
{
// Subtraction is valid if either x and y have same sign, or x-y and x have
// same sign.
return IsSigned<T>::value
? HasSignBit(BinaryComplement(T((result ^ x) & (x ^ y))))
: x >= y;
}
template<typename T,
bool IsSigned = IsSigned<T>::value,
bool TwiceBiggerTypeIsSupported =
IsSupported<typename TwiceBiggerType<T>::Type>::value>
struct IsMulValidImpl {};
template<typename T, bool IsSigned>
struct IsMulValidImpl<T, IsSigned, true>
{
static bool run(T x, T y)
{
typedef typename TwiceBiggerType<T>::Type TwiceBiggerType;
TwiceBiggerType product = TwiceBiggerType(x) * TwiceBiggerType(y);
return IsInRange<T>(product);
}
};
template<typename T>
struct IsMulValidImpl<T, true, false>
{
static bool run(T x, T y)
{
const T max = MaxValue<T>::value();
const T min = MinValue<T>::value();
if (x == 0 || y == 0)
return true;
if (x > 0) {
return y > 0
? x <= max / y
: y >= min / x;
}
// If we reach this point, we know that x < 0.
return y > 0
? x >= min / y
: y >= max / x;
}
};
template<typename T>
struct IsMulValidImpl<T, false, false>
{
static bool run(T x, T y)
{
return y == 0 ||
x <= MaxValue<T>::value() / y;
}
};
template<typename T>
inline bool
IsMulValid(T x, T y, T /* result not used */)
{
return IsMulValidImpl<T>::run(x, y);
}
template<typename T>
inline bool
IsDivValid(T x, T y)
{
// Keep in mind that in the signed case, min/-1 is invalid because abs(min)>max.
return IsSigned<T>::value
? (y != 0) && (x != MinValue<T>::value() || y != T(-1))
: y != 0;
}
// This is just to shut up msvc warnings about negating unsigned ints.
template<typename T, bool IsSigned = IsSigned<T>::value>
struct OppositeIfSignedImpl
{
static T run(T x) { return -x; }
};
template<typename T>
struct OppositeIfSignedImpl<T, false>
{
static T run(T x) { return x; }
};
template<typename T>
inline T
OppositeIfSigned(T x)
{
return OppositeIfSignedImpl<T>::run(x);
}
} // namespace detail
/*
* Step 4: Now define the CheckedInt class.
*/
/**
* @class CheckedInt
* @brief Integer wrapper class checking for integer overflow and other errors
* @param T the integer type to wrap. Can be any type among the following:
* - any basic integer type such as |int|
* - any stdint type such as |int8_t|
*
* This class implements guarded integer arithmetic. Do a computation, check
* that isValid() returns true, you then have a guarantee that no problem, such
* as integer overflow, happened during this computation, and you can call
* value() to get the plain integer value.
*
* The arithmetic operators in this class are guaranteed not to raise a signal
* (e.g. in case of a division by zero).
*
* For example, suppose that you want to implement a function that computes
* (x+y)/z, that doesn't crash if z==0, and that reports on error (divide by
* zero or integer overflow). You could code it as follows:
@code
bool computeXPlusYOverZ(int x, int y, int z, int *result)
{
CheckedInt<int> checkedResult = (CheckedInt<int>(x) + y) / z;
if (checkedResult.isValid()) {
*result = checkedResult.value();
return true;
} else {
return false;
}
}
@endcode
*
* Implicit conversion from plain integers to checked integers is allowed. The
* plain integer is checked to be in range before being casted to the
* destination type. This means that the following lines all compile, and the
* resulting CheckedInts are correctly detected as valid or invalid:
* @code
// 1 is of type int, is found to be in range for uint8_t, x is valid
CheckedInt<uint8_t> x(1);
// -1 is of type int, is found not to be in range for uint8_t, x is invalid
CheckedInt<uint8_t> x(-1);
// -1 is of type int, is found to be in range for int8_t, x is valid
CheckedInt<int8_t> x(-1);
// 1000 is of type int16_t, is found not to be in range for int8_t,
// x is invalid
CheckedInt<int8_t> x(int16_t(1000));
// 3123456789 is of type uint32_t, is found not to be in range for int32_t,
// x is invalid
CheckedInt<int32_t> x(uint32_t(3123456789));
* @endcode
* Implicit conversion from
* checked integers to plain integers is not allowed. As shown in the
* above example, to get the value of a checked integer as a normal integer,
* call value().
*
* Arithmetic operations between checked and plain integers is allowed; the
* result type is the type of the checked integer.
*
* Checked integers of different types cannot be used in the same arithmetic
* expression.
*
* There are convenience typedefs for all stdint types, of the following form
* (these are just 2 examples):
@code
typedef CheckedInt<int32_t> CheckedInt32;
typedef CheckedInt<uint16_t> CheckedUint16;
@endcode
*/
template<typename T>
class CheckedInt
{
protected:
T mValue;
bool mIsValid;
template<typename U>
CheckedInt(U value, bool isValid) : mValue(value), mIsValid(isValid)
{
MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
public:
/**
* Constructs a checked integer with given @a value. The checked integer is
* initialized as valid or invalid depending on whether the @a value
* is in range.
*
* This constructor is not explicit. Instead, the type of its argument is a
* separate template parameter, ensuring that no conversion is performed
* before this constructor is actually called. As explained in the above
* documentation for class CheckedInt, this constructor checks that its
* argument is valid.
*/
template<typename U>
CheckedInt(U value)
: mValue(T(value)),
mIsValid(detail::IsInRange<T>(value))
{
MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
/** Constructs a valid checked integer with initial value 0 */
CheckedInt() : mValue(0), mIsValid(true)
{
MOZ_STATIC_ASSERT(detail::IsSupported<T>::value,
"This type is not supported by CheckedInt");
}
/** @returns the actual value */
T value() const
{
MOZ_ASSERT(mIsValid, "Invalid checked integer (division by zero or integer overflow)");
return mValue;
}
/**
* @returns true if the checked integer is valid, i.e. is not the result
* of an invalid operation or of an operation involving an invalid checked
* integer
*/
bool isValid() const
{
return mIsValid;
}
template<typename U>
friend CheckedInt<U> operator +(const CheckedInt<U>& lhs,
const CheckedInt<U>& rhs);
template<typename U>
CheckedInt& operator +=(U rhs);
template<typename U>
friend CheckedInt<U> operator -(const CheckedInt<U>& lhs,
const CheckedInt<U> &rhs);
template<typename U>
CheckedInt& operator -=(U rhs);
template<typename U>
friend CheckedInt<U> operator *(const CheckedInt<U>& lhs,
const CheckedInt<U> &rhs);
template<typename U>
CheckedInt& operator *=(U rhs);
template<typename U>
friend CheckedInt<U> operator /(const CheckedInt<U>& lhs,
const CheckedInt<U> &rhs);
template<typename U>
CheckedInt& operator /=(U rhs);
CheckedInt operator -() const
{
// Circumvent msvc warning about - applied to unsigned int.
// if we're unsigned, the only valid case anyway is 0
// in which case - is a no-op.
T result = detail::OppositeIfSigned(mValue);
/* Help the compiler perform RVO (return value optimization). */
return CheckedInt(result,
mIsValid && detail::IsSubValid(T(0),
mValue,
result));
}
/**
* @returns true if the left and right hand sides are valid
* and have the same value.
*
* Note that these semantics are the reason why we don't offer
* a operator!=. Indeed, we'd want to have a!=b be equivalent to !(a==b)
* but that would mean that whenever a or b is invalid, a!=b
* is always true, which would be very confusing.
*
* For similar reasons, operators <, >, <=, >= would be very tricky to
* specify, so we just avoid offering them.
*
* Notice that these == semantics are made more reasonable by these facts:
* 1. a==b implies equality at the raw data level
* (the converse is false, as a==b is never true among invalids)
* 2. This is similar to the behavior of IEEE floats, where a==b
* means that a and b have the same value *and* neither is NaN.
*/
bool operator ==(const CheckedInt& other) const
{
return mIsValid && other.mIsValid && mValue == other.mValue;
}
/** prefix ++ */
CheckedInt& operator++()
{
*this += 1;
return *this;
}
/** postfix ++ */
CheckedInt operator++(int)
{
CheckedInt tmp = *this;
*this += 1;
return tmp;
}
/** prefix -- */
CheckedInt& operator--()
{
*this -= 1;
return *this;
}
/** postfix -- */
CheckedInt operator--(int)
{
CheckedInt tmp = *this;
*this -= 1;
return tmp;
}
private:
/**
* The !=, <, <=, >, >= operators are disabled:
* see the comment on operator==.
*/
template<typename U>
bool operator !=(U other) const MOZ_DELETE;
template<typename U>
bool operator <(U other) const MOZ_DELETE;
template<typename U>
bool operator <=(U other) const MOZ_DELETE;
template<typename U>
bool operator >(U other) const MOZ_DELETE;
template<typename U>
bool operator >=(U other) const MOZ_DELETE;
};
#define MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
template<typename T> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, \
const CheckedInt<T> &rhs) \
{ \
T x = lhs.mValue; \
T y = rhs.mValue; \
T result = x OP y; \
T isOpValid \
= detail::Is##NAME##Valid(x, y, result); \
/* Help the compiler perform RVO (return value optimization). */ \
return CheckedInt<T>(result, \
lhs.mIsValid && rhs.mIsValid && isOpValid); \
}
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Add, +)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Sub, -)
MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR(Mul, *)
#undef MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
// Division can't be implemented by MOZ_CHECKEDINT_BASIC_BINARY_OPERATOR
// because if rhs == 0, we are not allowed to even try to compute the quotient.
template<typename T>
inline CheckedInt<T> operator /(const CheckedInt<T> &lhs,
const CheckedInt<T> &rhs)
{
T x = lhs.mValue;
T y = rhs.mValue;
bool isOpValid = detail::IsDivValid(x, y);
T result = isOpValid ? (x / y) : 0;
/* give the compiler a good chance to perform RVO */
return CheckedInt<T>(result,
lhs.mIsValid && rhs.mIsValid && isOpValid);
}
// Implement castToCheckedInt<T>(x), making sure that
// - it allows x to be either a CheckedInt<T> or any integer type
// that can be casted to T
// - if x is already a CheckedInt<T>, we just return a reference to it,
// instead of copying it (optimization)
namespace detail {
template<typename T, typename U>
struct CastToCheckedIntImpl
{
typedef CheckedInt<T> ReturnType;
static CheckedInt<T> run(U u) { return u; }
};
template<typename T>
struct CastToCheckedIntImpl<T, CheckedInt<T> >
{
typedef const CheckedInt<T>& ReturnType;
static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
};
} // namespace detail
template<typename T, typename U>
inline typename detail::CastToCheckedIntImpl<T, U>::ReturnType
castToCheckedInt(U u)
{
return detail::CastToCheckedIntImpl<T, U>::run(u);
}
#define MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
{ \
*this = *this OP castToCheckedInt<T>(rhs); \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
{ \
return lhs OP castToCheckedInt<T>(rhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
{ \
return castToCheckedInt<T>(lhs) OP rhs; \
}
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
#undef MOZ_CHECKEDINT_CONVENIENCE_BINARY_OPERATORS
template<typename T, typename U>
inline bool
operator ==(const CheckedInt<T> &lhs, U rhs)
{
return lhs == castToCheckedInt<T>(rhs);
}
template<typename T, typename U>
inline bool
operator ==(U lhs, const CheckedInt<T> &rhs)
{
return castToCheckedInt<T>(lhs) == rhs;
}
// Convenience typedefs.
typedef CheckedInt<int8_t> CheckedInt8;
typedef CheckedInt<uint8_t> CheckedUint8;
typedef CheckedInt<int16_t> CheckedInt16;
typedef CheckedInt<uint16_t> CheckedUint16;
typedef CheckedInt<int32_t> CheckedInt32;
typedef CheckedInt<uint32_t> CheckedUint32;
typedef CheckedInt<int64_t> CheckedInt64;
typedef CheckedInt<uint64_t> CheckedUint64;
} // namespace mozilla
#endif /* mozilla_CheckedInt_h_ */

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

@ -47,9 +47,7 @@ LIBRARY_NAME = mfbt
FORCE_STATIC_LIB = 1
STL_FLAGS =
TEST_DIRS = \
tests \
$(NULL)
DIRS =
# exported_headers.mk defines the headers exported by mfbt. It is included by
# mfbt itself and by the JS engine, which, when built standalone, must do the

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

@ -45,7 +45,6 @@ EXPORTS_mozilla += \
Assertions.h \
Attributes.h \
BloomFilter.h \
CheckedInt.h \
FloatingPoint.h \
GuardObjects.h \
HashFunctions.h \

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

@ -1,21 +0,0 @@
# 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/.
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
STL_FLAGS =
CPP_UNIT_TESTS = \
TestCheckedInt.cpp \
$(NULL)
include $(topsrcdir)/config/rules.mk
LIBS=
MOZ_GLUE_PROGRAM_LDFLAGS=

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

@ -1,492 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "mozilla/CheckedInt.h"
#include <iostream>
#include <climits>
#ifndef MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS
# error MOZ_CHECKEDINT_ENABLE_MOZ_ASSERTS should be defined by CheckedInt.h
#endif
using namespace mozilla;
int gIntegerTypesTested = 0;
int gTestsPassed = 0;
int gTestsFailed = 0;
void verifyImplFunction(bool x, bool expected,
const char* file, int line,
int size, bool isTSigned)
{
if (x == expected) {
gTestsPassed++;
} else {
gTestsFailed++;
std::cerr << "Test failed at " << file << ":" << line;
std::cerr << " with T a ";
if (isTSigned)
std::cerr << "signed";
else
std::cerr << "unsigned";
std::cerr << " " << CHAR_BIT*size << "-bit integer type" << std::endl;
}
}
#define VERIFY_IMPL(x, expected) \
verifyImplFunction((x), \
(expected), \
__FILE__, \
__LINE__, \
sizeof(T), \
detail::IsSigned<T>::value)
#define VERIFY(x) VERIFY_IMPL(x, true)
#define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
#define VERIFY_IS_VALID(x) VERIFY_IMPL((x).isValid(), true)
#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).isValid(), false)
#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).isValid(), (condition))
template<typename T, size_t Size = sizeof(T)>
struct testTwiceBiggerType
{
static void run()
{
VERIFY(detail::IsSupported<typename detail::TwiceBiggerType<T>::Type>::value);
VERIFY(sizeof(typename detail::TwiceBiggerType<T>::Type)
== 2 * sizeof(T));
VERIFY(bool(detail::IsSigned<typename detail::TwiceBiggerType<T>::Type>::value)
== bool(detail::IsSigned<T>::value));
}
};
template<typename T>
struct testTwiceBiggerType<T, 8>
{
static void run()
{
VERIFY_IS_FALSE(detail::IsSupported<
typename detail::TwiceBiggerType<T>::Type
>::value);
}
};
template<typename T>
void test()
{
static bool alreadyRun = false;
// Integer types from different families may just be typedefs for types from other families.
// e.g. int32_t might be just a typedef for int. No point re-running the same tests then.
if (alreadyRun)
return;
alreadyRun = true;
VERIFY(detail::IsSupported<T>::value);
const bool isTSigned = detail::IsSigned<T>::value;
VERIFY(bool(isTSigned) == !bool(T(-1) > T(0)));
testTwiceBiggerType<T>::run();
typedef typename detail::UnsignedType<T>::Type unsignedT;
VERIFY(sizeof(unsignedT) == sizeof(T));
VERIFY(detail::IsSigned<unsignedT>::value == false);
const CheckedInt<T> max(detail::MaxValue<T>::value());
const CheckedInt<T> min(detail::MinValue<T>::value());
// Check min() and max(), since they are custom implementations and a mistake there
// could potentially NOT be caught by any other tests... while making everything wrong!
T bit = 1;
for (size_t i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
{
VERIFY((min.value() & bit) == 0);
bit <<= 1;
}
VERIFY((min.value() & bit) == (isTSigned ? bit : T(0)));
VERIFY(max.value() == T(~(min.value())));
const CheckedInt<T> zero(0);
const CheckedInt<T> one(1);
const CheckedInt<T> two(2);
const CheckedInt<T> three(3);
const CheckedInt<T> four(4);
/* Addition / substraction checks */
VERIFY_IS_VALID(zero + zero);
VERIFY(zero + zero == zero);
VERIFY_IS_FALSE(zero + zero == one); // Check that == doesn't always return true
VERIFY_IS_VALID(zero + one);
VERIFY(zero + one == one);
VERIFY_IS_VALID(one + one);
VERIFY(one + one == two);
const CheckedInt<T> maxMinusOne = max - one;
const CheckedInt<T> maxMinusTwo = max - two;
VERIFY_IS_VALID(maxMinusOne);
VERIFY_IS_VALID(maxMinusTwo);
VERIFY_IS_VALID(maxMinusOne + one);
VERIFY_IS_VALID(maxMinusTwo + one);
VERIFY_IS_VALID(maxMinusTwo + two);
VERIFY(maxMinusOne + one == max);
VERIFY(maxMinusTwo + one == maxMinusOne);
VERIFY(maxMinusTwo + two == max);
VERIFY_IS_VALID(max + zero);
VERIFY_IS_VALID(max - zero);
VERIFY_IS_INVALID(max + one);
VERIFY_IS_INVALID(max + two);
VERIFY_IS_INVALID(max + maxMinusOne);
VERIFY_IS_INVALID(max + max);
const CheckedInt<T> minPlusOne = min + one;
const CheckedInt<T> minPlusTwo = min + two;
VERIFY_IS_VALID(minPlusOne);
VERIFY_IS_VALID(minPlusTwo);
VERIFY_IS_VALID(minPlusOne - one);
VERIFY_IS_VALID(minPlusTwo - one);
VERIFY_IS_VALID(minPlusTwo - two);
VERIFY(minPlusOne - one == min);
VERIFY(minPlusTwo - one == minPlusOne);
VERIFY(minPlusTwo - two == min);
const CheckedInt<T> minMinusOne = min - one;
VERIFY_IS_VALID(min + zero);
VERIFY_IS_VALID(min - zero);
VERIFY_IS_INVALID(min - one);
VERIFY_IS_INVALID(min - two);
VERIFY_IS_INVALID(min - minMinusOne);
VERIFY_IS_VALID(min - min);
const CheckedInt<T> maxOverTwo = max / two;
VERIFY_IS_VALID(maxOverTwo + maxOverTwo);
VERIFY_IS_VALID(maxOverTwo + one);
VERIFY((maxOverTwo + one) - one == maxOverTwo);
VERIFY_IS_VALID(maxOverTwo - maxOverTwo);
VERIFY(maxOverTwo - maxOverTwo == zero);
const CheckedInt<T> minOverTwo = min / two;
VERIFY_IS_VALID(minOverTwo + minOverTwo);
VERIFY_IS_VALID(minOverTwo + one);
VERIFY((minOverTwo + one) - one == minOverTwo);
VERIFY_IS_VALID(minOverTwo - minOverTwo);
VERIFY(minOverTwo - minOverTwo == zero);
VERIFY_IS_INVALID(min - one);
VERIFY_IS_INVALID(min - two);
if (isTSigned) {
VERIFY_IS_INVALID(min + min);
VERIFY_IS_INVALID(minOverTwo + minOverTwo + minOverTwo);
VERIFY_IS_INVALID(zero - min + min);
VERIFY_IS_INVALID(one - min + min);
}
/* Unary operator- checks */
const CheckedInt<T> negOne = -one;
const CheckedInt<T> negTwo = -two;
if (isTSigned) {
VERIFY_IS_VALID(-max);
VERIFY_IS_VALID(-max - one);
VERIFY_IS_VALID(negOne);
VERIFY_IS_VALID(-max + negOne);
VERIFY_IS_VALID(negOne + one);
VERIFY(negOne + one == zero);
VERIFY_IS_VALID(negTwo);
VERIFY_IS_VALID(negOne + negOne);
VERIFY(negOne + negOne == negTwo);
} else {
VERIFY_IS_INVALID(negOne);
}
/* multiplication checks */
VERIFY_IS_VALID(zero * zero);
VERIFY(zero * zero == zero);
VERIFY_IS_VALID(zero * one);
VERIFY(zero * one == zero);
VERIFY_IS_VALID(one * zero);
VERIFY(one * zero == zero);
VERIFY_IS_VALID(one * one);
VERIFY(one * one == one);
VERIFY_IS_VALID(one * three);
VERIFY(one * three == three);
VERIFY_IS_VALID(two * two);
VERIFY(two * two == four);
VERIFY_IS_INVALID(max * max);
VERIFY_IS_INVALID(maxOverTwo * max);
VERIFY_IS_INVALID(maxOverTwo * maxOverTwo);
const CheckedInt<T> maxApproxSqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
VERIFY_IS_VALID(maxApproxSqrt);
VERIFY_IS_VALID(maxApproxSqrt * two);
VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt);
VERIFY_IS_INVALID(maxApproxSqrt * maxApproxSqrt * maxApproxSqrt);
if (isTSigned) {
VERIFY_IS_INVALID(min * min);
VERIFY_IS_INVALID(minOverTwo * min);
VERIFY_IS_INVALID(minOverTwo * minOverTwo);
const CheckedInt<T> minApproxSqrt = -maxApproxSqrt;
VERIFY_IS_VALID(minApproxSqrt);
VERIFY_IS_VALID(minApproxSqrt * two);
VERIFY_IS_INVALID(minApproxSqrt * maxApproxSqrt);
VERIFY_IS_INVALID(minApproxSqrt * minApproxSqrt);
}
// make sure to check all 4 paths in signed multiplication validity check.
// test positive * positive
VERIFY_IS_VALID(max * one);
VERIFY(max * one == max);
VERIFY_IS_INVALID(max * two);
VERIFY_IS_VALID(maxOverTwo * two);
VERIFY((maxOverTwo + maxOverTwo) == (maxOverTwo * two));
if (isTSigned) {
// test positive * negative
VERIFY_IS_VALID(max * negOne);
VERIFY_IS_VALID(-max);
VERIFY(max * negOne == -max);
VERIFY_IS_VALID(one * min);
VERIFY_IS_INVALID(max * negTwo);
VERIFY_IS_VALID(maxOverTwo * negTwo);
VERIFY_IS_VALID(two * minOverTwo);
VERIFY_IS_VALID((maxOverTwo + one) * negTwo);
VERIFY_IS_INVALID((maxOverTwo + two) * negTwo);
VERIFY_IS_INVALID(two * (minOverTwo - one));
// test negative * positive
VERIFY_IS_VALID(min * one);
VERIFY_IS_VALID(minPlusOne * one);
VERIFY_IS_INVALID(min * two);
VERIFY_IS_VALID(minOverTwo * two);
VERIFY(minOverTwo * two == min);
VERIFY_IS_INVALID((minOverTwo - one) * negTwo);
VERIFY_IS_INVALID(negTwo * max);
VERIFY_IS_VALID(minOverTwo * two);
VERIFY(minOverTwo * two == min);
VERIFY_IS_VALID(negTwo * maxOverTwo);
VERIFY_IS_INVALID((minOverTwo - one) * two);
VERIFY_IS_VALID(negTwo * (maxOverTwo + one));
VERIFY_IS_INVALID(negTwo * (maxOverTwo + two));
// test negative * negative
VERIFY_IS_INVALID(min * negOne);
VERIFY_IS_VALID(minPlusOne * negOne);
VERIFY(minPlusOne * negOne == max);
VERIFY_IS_INVALID(min * negTwo);
VERIFY_IS_INVALID(minOverTwo * negTwo);
VERIFY_IS_INVALID(negOne * min);
VERIFY_IS_VALID(negOne * minPlusOne);
VERIFY(negOne * minPlusOne == max);
VERIFY_IS_INVALID(negTwo * min);
VERIFY_IS_INVALID(negTwo * minOverTwo);
}
/* Division checks */
VERIFY_IS_VALID(one / one);
VERIFY(one / one == one);
VERIFY_IS_VALID(three / three);
VERIFY(three / three == one);
VERIFY_IS_VALID(four / two);
VERIFY(four / two == two);
VERIFY((four*three)/four == three);
// Check that div by zero is invalid
VERIFY_IS_INVALID(zero / zero);
VERIFY_IS_INVALID(one / zero);
VERIFY_IS_INVALID(two / zero);
VERIFY_IS_INVALID(negOne / zero);
VERIFY_IS_INVALID(max / zero);
VERIFY_IS_INVALID(min / zero);
if (isTSigned) {
// Check that min / -1 is invalid
VERIFY_IS_INVALID(min / negOne);
// Check that the test for div by -1 isn't banning other numerators than min
VERIFY_IS_VALID(one / negOne);
VERIFY_IS_VALID(zero / negOne);
VERIFY_IS_VALID(negOne / negOne);
VERIFY_IS_VALID(max / negOne);
}
/* Check that invalidity is correctly preserved by arithmetic ops */
const CheckedInt<T> someInvalid = max + max;
VERIFY_IS_INVALID(someInvalid + zero);
VERIFY_IS_INVALID(someInvalid - zero);
VERIFY_IS_INVALID(zero + someInvalid);
VERIFY_IS_INVALID(zero - someInvalid);
VERIFY_IS_INVALID(-someInvalid);
VERIFY_IS_INVALID(someInvalid * zero);
VERIFY_IS_INVALID(someInvalid * one);
VERIFY_IS_INVALID(zero * someInvalid);
VERIFY_IS_INVALID(one * someInvalid);
VERIFY_IS_INVALID(someInvalid / zero);
VERIFY_IS_INVALID(someInvalid / one);
VERIFY_IS_INVALID(zero / someInvalid);
VERIFY_IS_INVALID(one / someInvalid);
VERIFY_IS_INVALID(someInvalid + someInvalid);
VERIFY_IS_INVALID(someInvalid - someInvalid);
VERIFY_IS_INVALID(someInvalid * someInvalid);
VERIFY_IS_INVALID(someInvalid / someInvalid);
/* Check that mixing checked integers with plain integers in expressions is allowed */
VERIFY(one + T(2) == three);
VERIFY(2 + one == three);
{
CheckedInt<T> x = one;
x += 2;
VERIFY(x == three);
}
VERIFY(two - 1 == one);
VERIFY(2 - one == one);
{
CheckedInt<T> x = two;
x -= 1;
VERIFY(x == one);
}
VERIFY(one * 2 == two);
VERIFY(2 * one == two);
{
CheckedInt<T> x = one;
x *= 2;
VERIFY(x == two);
}
VERIFY(four / 2 == two);
VERIFY(4 / two == two);
{
CheckedInt<T> x = four;
x /= 2;
VERIFY(x == two);
}
VERIFY(one == 1);
VERIFY(1 == one);
VERIFY_IS_FALSE(two == 1);
VERIFY_IS_FALSE(1 == two);
VERIFY_IS_FALSE(someInvalid == 1);
VERIFY_IS_FALSE(1 == someInvalid);
/* Check that construction of CheckedInt from an integer value of a mismatched type is checked */
#define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
{ \
bool isUSigned = detail::IsSigned<U>::value; \
VERIFY_IS_VALID(CheckedInt<T>(U(0))); \
VERIFY_IS_VALID(CheckedInt<T>(U(1))); \
VERIFY_IS_VALID(CheckedInt<T>(U(100))); \
if (isUSigned) \
VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), isTSigned); \
if (sizeof(U) > sizeof(T)) \
VERIFY_IS_INVALID(CheckedInt<T>(U(detail::MaxValue<T>::value())+1)); \
VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MaxValue<U>::value()), \
(sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (isUSigned || !isTSigned)))); \
VERIFY_IS_VALID_IF(CheckedInt<T>(detail::MinValue<U>::value()), \
isUSigned == false ? 1 : \
bool(isTSigned) == false ? 0 : \
sizeof(T) >= sizeof(U)); \
}
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int8_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint8_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int16_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint16_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int32_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint32_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int64_t)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(uint64_t)
typedef unsigned char unsignedChar;
typedef unsigned short unsignedShort;
typedef unsigned int unsignedInt;
typedef unsigned long unsignedLong;
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(char)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedChar)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(short)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedShort)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(int)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedInt)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(long)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(unsignedLong)
/* Test increment/decrement operators */
CheckedInt<T> x, y;
x = one;
y = x++;
VERIFY(x == two);
VERIFY(y == one);
x = one;
y = ++x;
VERIFY(x == two);
VERIFY(y == two);
x = one;
y = x--;
VERIFY(x == zero);
VERIFY(y == one);
x = one;
y = --x;
VERIFY(x == zero);
VERIFY(y == zero);
x = max;
VERIFY_IS_VALID(x++);
x = max;
VERIFY_IS_INVALID(++x);
x = min;
VERIFY_IS_VALID(x--);
x = min;
VERIFY_IS_INVALID(--x);
gIntegerTypesTested++;
}
int main()
{
test<int8_t>();
test<uint8_t>();
test<int16_t>();
test<uint16_t>();
test<int32_t>();
test<uint32_t>();
test<int64_t>();
test<uint64_t>();
test<char>();
test<unsigned char>();
test<short>();
test<unsigned short>();
test<int>();
test<unsigned int>();
test<long>();
test<unsigned long>();
if (gIntegerTypesTested < 8) {
std::cerr << "Only " << gIntegerTypesTested << " have been tested. "
<< "This should not be less than 8." << std::endl;
gTestsFailed++;
}
std::cerr << gTestsFailed << " tests failed, "
<< gTestsPassed << " tests passed out of "
<< gTestsFailed + gTestsPassed
<< " tests, covering " << gIntegerTypesTested
<< " distinct integer types." << std::endl;
return gTestsFailed > 0;
}

595
xpcom/ds/CheckedInt.h Normal file
Просмотреть файл

@ -0,0 +1,595 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Jacob <bjacob@mozilla.com>
* Jeff Muizelaar <jmuizelaar@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_CheckedInt_h
#define mozilla_CheckedInt_h
#include "prtypes.h"
#include <climits>
namespace mozilla {
namespace CheckedInt_internal {
/* we don't want to use std::numeric_limits here because PRInt... types may not support it,
* depending on the platform, e.g. on certain platforms they use nonstandard built-in types
*/
/*** Step 1: manually record information for all the types that we want to support
***/
struct unsupported_type {};
template<typename T> struct integer_type_manually_recorded_info
{
enum { is_supported = 0 };
typedef unsupported_type twice_bigger_type;
typedef unsupported_type unsigned_type;
};
#define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type,_unsigned_type) \
template<> struct integer_type_manually_recorded_info<T> \
{ \
enum { is_supported = 1 }; \
typedef _twice_bigger_type twice_bigger_type; \
typedef _unsigned_type unsigned_type; \
static void TYPE_NOT_SUPPORTED_BY_CheckedInt() {} \
};
// Type Twice Bigger Type Unsigned Type
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt8, PRInt16, PRUint8)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint8, PRUint16, PRUint8)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt16, PRInt32, PRUint16)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint16, PRUint32, PRUint16)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt32, PRInt64, PRUint32)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint32, PRUint64, PRUint32)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt64, unsupported_type, PRUint64)
CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint64, unsupported_type, PRUint64)
/*** Step 2: record some info about a given integer type,
*** including whether it is supported, whether a twice bigger integer type
*** is supported, what that twice bigger type is, and some stuff as found
*** in std::numeric_limits (which we don't use because PRInt.. types may
*** not support it, if they are defined directly from compiler built-in types).
*** We use function names min_value() and max_value() instead of min() and max()
*** because of stupid min/max macros in Windows headers.
***/
template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
template<typename T> struct integer_traits
{
typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
typedef typename integer_type_manually_recorded_info<T>::unsigned_type unsigned_type;
enum {
is_supported = integer_type_manually_recorded_info<T>::is_supported,
twice_bigger_type_is_supported
= is_unsupported_type<
typename integer_type_manually_recorded_info<T>::twice_bigger_type
>::answer ? 0 : 1,
size = sizeof(T),
position_of_sign_bit = CHAR_BIT * size - 1,
is_signed = (T(-1) > T(0)) ? 0 : 1
};
static T min_value()
{
// bitwise ops may return a larger type, that's why we cast explicitly to T
// in C++, left bit shifts on signed values is undefined by the standard unless the shifted value is representable.
// notice that signed-to-unsigned conversions are always well-defined in the standard,
// as the value congruent to 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
// representable.
return is_signed ? T(unsigned_type(1) << position_of_sign_bit) : T(0);
}
static T max_value()
{
return ~min_value();
}
};
/*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
***/
// bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
// the result is really of type T
template<typename T> inline T has_sign_bit(T x)
{
// in C++, right bit shifts on negative values is undefined by the standard.
// notice that signed-to-unsigned conversions are always well-defined in the standard,
// as the value congruent modulo 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
// representable. Here the unsigned-to-signed conversion is OK because the value (the result of the shift) is 0 or 1.
typedef typename integer_traits<T>::unsigned_type unsigned_T;
return T(unsigned_T(x) >> integer_traits<T>::position_of_sign_bit);
}
template<typename T> inline T binary_complement(T x)
{
return ~x;
}
template<typename T, typename U,
bool is_T_signed = integer_traits<T>::is_signed,
bool is_U_signed = integer_traits<U>::is_signed>
struct is_in_range_impl {};
template<typename T, typename U>
struct is_in_range_impl<T, U, true, true>
{
static T run(U x)
{
return (x <= integer_traits<T>::max_value()) &&
(x >= integer_traits<T>::min_value());
}
};
template<typename T, typename U>
struct is_in_range_impl<T, U, false, false>
{
static T run(U x)
{
return x <= integer_traits<T>::max_value();
}
};
template<typename T, typename U>
struct is_in_range_impl<T, U, true, false>
{
static T run(U x)
{
if (sizeof(T) > sizeof(U))
return 1;
else
return x <= U(integer_traits<T>::max_value());
}
};
template<typename T, typename U>
struct is_in_range_impl<T, U, false, true>
{
static T run(U x)
{
if (sizeof(T) >= sizeof(U))
return x >= 0;
else
return (x >= 0) && (x <= U(integer_traits<T>::max_value()));
}
};
template<typename T, typename U> inline T is_in_range(U x)
{
return is_in_range_impl<T, U>::run(x);
}
template<typename T> inline T is_add_valid(T x, T y, T result)
{
return integer_traits<T>::is_signed ?
// addition is valid if the sign of x+y is equal to either that of x or that of y.
// Beware! These bitwise operations can return a larger integer type, if T was a
// small type like int8, so we explicitly cast to T.
has_sign_bit(binary_complement(T((result^x) & (result^y))))
:
binary_complement(x) >= y;
}
template<typename T> inline T is_sub_valid(T x, T y, T result)
{
return integer_traits<T>::is_signed ?
// substraction is valid if either x and y have same sign, or x-y and x have same sign
has_sign_bit(binary_complement(T((result^x) & (x^y))))
:
x >= y;
}
template<typename T,
bool is_signed = integer_traits<T>::is_signed,
bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
struct is_mul_valid_impl {};
template<typename T, bool is_signed>
struct is_mul_valid_impl<T, is_signed, true>
{
static T run(T x, T y)
{
typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
return is_in_range<T>(product);
}
};
template<typename T>
struct is_mul_valid_impl<T, true, false>
{
static T run(T x, T y)
{
const T max_value = integer_traits<T>::max_value();
const T min_value = integer_traits<T>::min_value();
if (x == 0 || y == 0) return true;
if (x > 0) {
if (y > 0)
return x <= max_value / y;
else
return y >= min_value / x;
} else {
if (y > 0)
return x >= min_value / y;
else
return y >= max_value / x;
}
}
};
template<typename T>
struct is_mul_valid_impl<T, false, false>
{
static T run(T x, T y)
{
const T max_value = integer_traits<T>::max_value();
if (x == 0 || y == 0) return true;
return x <= max_value / y;
}
};
template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
{
return is_mul_valid_impl<T>::run(x, y);
}
template<typename T> inline T is_div_valid(T x, T y)
{
return integer_traits<T>::is_signed ?
// keep in mind that min/-1 is invalid because abs(min)>max
(y != 0) && (x != integer_traits<T>::min_value() || y != T(-1))
:
y != 0;
}
// this is just to shut up msvc warnings about negating unsigned ints.
template<typename T, bool is_signed = integer_traits<T>::is_signed>
struct opposite_if_signed_impl
{
static T run(T x) { return -x; }
};
template<typename T>
struct opposite_if_signed_impl<T, false>
{
static T run(T x) { return x; }
};
template<typename T>
inline T opposite_if_signed(T x) { return opposite_if_signed_impl<T>::run(x); }
} // end namespace CheckedInt_internal
/*** Step 4: Now define the CheckedInt class.
***/
/** \class CheckedInt
* \brief Integer wrapper class checking for integer overflow and other errors
* \param T the integer type to wrap. Can be any of PRInt8, PRUint8, PRInt16, PRUint16,
* PRInt32, PRUint32, PRInt64, PRUint64.
*
* This class implements guarded integer arithmetic. Do a computation, check that
* valid() returns true, you then have a guarantee that no problem, such as integer overflow,
* happened during this computation.
*
* The arithmetic operators in this class are guaranteed not to crash your app
* in case of a division by zero.
*
* For example, suppose that you want to implement a function that computes (x+y)/z,
* that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
* You could code it as follows:
\code
bool compute_x_plus_y_over_z(PRInt32 x, PRInt32 y, PRInt32 z, PRInt32 *result)
{
CheckedInt<PRInt32> checked_result = (CheckedInt<PRInt32>(x) + y) / z;
*result = checked_result.value();
return checked_result.valid();
}
\endcode
*
* Implicit conversion from plain integers to checked integers is allowed. The plain integer
* is checked to be in range before being casted to the destination type. This means that the following
* lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
* \code
CheckedInt<PRUint8> x(1); // 1 is of type int, is found to be in range for PRUint8, x is valid
CheckedInt<PRUint8> x(-1); // -1 is of type int, is found not to be in range for PRUint8, x is invalid
CheckedInt<PRInt8> x(-1); // -1 is of type int, is found to be in range for PRInt8, x is valid
CheckedInt<PRInt8> x(PRInt16(1000)); // 1000 is of type PRInt16, is found not to be in range for PRInt8, x is invalid
CheckedInt<PRInt32> x(PRUint32(3123456789)); // 3123456789 is of type PRUint32, is found not to be in range
// for PRInt32, x is invalid
* \endcode
* Implicit conversion from
* checked integers to plain integers is not allowed. As shown in the
* above example, to get the value of a checked integer as a normal integer, call value().
*
* Arithmetic operations between checked and plain integers is allowed; the result type
* is the type of the checked integer.
*
* Checked integers of different types cannot be used in the same arithmetic expression.
*
* There are convenience typedefs for all PR integer types, of the following form (these are just 2 examples):
\code
typedef CheckedInt<PRInt32> CheckedInt32;
typedef CheckedInt<PRUint16> CheckedUint16;
\endcode
*/
template<typename T>
class CheckedInt
{
protected:
T mValue;
T mIsValid; // stored as a T to limit the number of integer conversions when
// evaluating nested arithmetic expressions.
template<typename U>
CheckedInt(U value, T isValid) : mValue(value), mIsValid(isValid)
{
CheckedInt_internal::integer_type_manually_recorded_info<T>
::TYPE_NOT_SUPPORTED_BY_CheckedInt();
}
public:
/** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
* depending on whether the \a value is in range.
*
* This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
* ensuring that no conversion is performed before this constructor is actually called.
* As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
* valid.
*/
template<typename U>
CheckedInt(U value)
: mValue(T(value)),
mIsValid(CheckedInt_internal::is_in_range<T>(value))
{
CheckedInt_internal::integer_type_manually_recorded_info<T>
::TYPE_NOT_SUPPORTED_BY_CheckedInt();
}
/** Constructs a valid checked integer with initial value 0 */
CheckedInt() : mValue(0), mIsValid(1)
{
CheckedInt_internal::integer_type_manually_recorded_info<T>
::TYPE_NOT_SUPPORTED_BY_CheckedInt();
}
/** \returns the actual value */
T value() const { return mValue; }
/** \returns true if the checked integer is valid, i.e. is not the result
* of an invalid operation or of an operation involving an invalid checked integer
*/
bool valid() const
{
return bool(mIsValid);
}
/** \returns the sum. Checks for overflow. */
template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
/** Adds. Checks for overflow. \returns self reference */
template<typename U> CheckedInt& operator +=(U rhs);
/** \returns the difference. Checks for overflow. */
template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
/** Substracts. Checks for overflow. \returns self reference */
template<typename U> CheckedInt& operator -=(U rhs);
/** \returns the product. Checks for overflow. */
template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
/** Multiplies. Checks for overflow. \returns self reference */
template<typename U> CheckedInt& operator *=(U rhs);
/** \returns the quotient. Checks for overflow and for divide-by-zero. */
template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
/** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
template<typename U> CheckedInt& operator /=(U rhs);
/** \returns the opposite value. Checks for overflow. */
CheckedInt operator -() const
{
// circumvent msvc warning about - applied to unsigned int.
// if we're unsigned, the only valid case anyway is 0 in which case - is a no-op.
T result = CheckedInt_internal::opposite_if_signed(value());
/* give the compiler a good chance to perform RVO */
return CheckedInt(result,
mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
}
/** \returns true if the left and right hand sides are valid and have the same value. */
bool operator ==(const CheckedInt& other) const
{
return bool(mIsValid & other.mIsValid & (value() == other.mValue));
}
/** prefix ++ */
CheckedInt& operator++()
{
*this = *this + 1;
return *this;
}
/** postfix ++ */
CheckedInt operator++(int)
{
CheckedInt tmp = *this;
*this = *this + 1;
return tmp;
}
/** prefix -- */
CheckedInt& operator--()
{
*this = *this - 1;
return *this;
}
/** postfix -- */
CheckedInt operator--(int)
{
CheckedInt tmp = *this;
*this = *this - 1;
return tmp;
}
private:
/** operator!= is disabled. Indeed, (a!=b) should be the same as !(a==b) but that
* would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
*/
template<typename U>
bool operator !=(U other) const { return !(*this == other); }
};
#define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
template<typename T> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
{ \
T x = lhs.mValue; \
T y = rhs.mValue; \
T result = x OP y; \
T is_op_valid \
= CheckedInt_internal::is_##NAME##_valid(x, y, result); \
/* give the compiler a good chance to perform RVO */ \
return CheckedInt<T>(result, \
lhs.mIsValid & rhs.mIsValid & is_op_valid); \
}
CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
// division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
// because if rhs == 0, we are not allowed to even try to compute the quotient.
template<typename T>
inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
{
T x = lhs.mValue;
T y = rhs.mValue;
T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
T result = is_op_valid ? (x / y) : 0;
/* give the compiler a good chance to perform RVO */
return CheckedInt<T>(result,
lhs.mIsValid & rhs.mIsValid & is_op_valid);
}
// implement cast_to_CheckedInt<T>(x), making sure that
// - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
// - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
template<typename T, typename U>
struct cast_to_CheckedInt_impl
{
typedef CheckedInt<T> return_type;
static CheckedInt<T> run(U u) { return u; }
};
template<typename T>
struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
{
typedef const CheckedInt<T>& return_type;
static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
};
template<typename T, typename U>
inline typename cast_to_CheckedInt_impl<T, U>::return_type
cast_to_CheckedInt(U u)
{
return cast_to_CheckedInt_impl<T, U>::run(u);
}
#define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
template<typename T> \
template<typename U> \
CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(U rhs) \
{ \
*this = *this OP cast_to_CheckedInt<T>(rhs); \
return *this; \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, U rhs) \
{ \
return lhs OP cast_to_CheckedInt<T>(rhs); \
} \
template<typename T, typename U> \
inline CheckedInt<T> operator OP(U lhs, const CheckedInt<T> &rhs) \
{ \
return cast_to_CheckedInt<T>(lhs) OP rhs; \
}
CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
template<typename T, typename U>
inline bool operator ==(const CheckedInt<T> &lhs, U rhs)
{
return lhs == cast_to_CheckedInt<T>(rhs);
}
template<typename T, typename U>
inline bool operator ==(U lhs, const CheckedInt<T> &rhs)
{
return cast_to_CheckedInt<T>(lhs) == rhs;
}
// convenience typedefs.
// the use of a macro here helps make sure that we don't let a typo slip into some of these.
#define CHECKEDINT_MAKE_TYPEDEF(Type) \
typedef CheckedInt<PR##Type> Checked##Type;
CHECKEDINT_MAKE_TYPEDEF(Int8)
CHECKEDINT_MAKE_TYPEDEF(Uint8)
CHECKEDINT_MAKE_TYPEDEF(Int16)
CHECKEDINT_MAKE_TYPEDEF(Uint16)
CHECKEDINT_MAKE_TYPEDEF(Int32)
CHECKEDINT_MAKE_TYPEDEF(Uint32)
CHECKEDINT_MAKE_TYPEDEF(Int64)
CHECKEDINT_MAKE_TYPEDEF(Uint64)
} // end namespace mozilla
#endif /* mozilla_CheckedInt_h */

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

@ -110,6 +110,7 @@ EXPORTS = \
nsHashPropertyBag.h \
nsWhitespaceTokenizer.h \
nsCharSeparatedTokenizer.h \
CheckedInt.h \
$(NULL)
XPIDLSRCS = \

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

@ -105,6 +105,7 @@ CPP_UNIT_TESTS = \
TestRefPtr.cpp \
TestSettingsAPI.cpp \
TestTextFormatter.cpp \
TestCheckedInt.cpp \
TestTArray.cpp \
$(NULL)

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

@ -0,0 +1,488 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Jacob <bjacob@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CheckedInt.h"
#include <iostream>
namespace CheckedInt_test {
using namespace mozilla::CheckedInt_internal;
using mozilla::CheckedInt;
int g_tests_passed = 0;
int g_tests_failed = 0;
void verify_impl_function(bool x, bool expected,
const char* file, int line,
int T_size, bool T_is_signed)
{
if (x == expected) {
g_tests_passed++;
} else {
g_tests_failed++;
std::cerr << "Test failed at " << file << ":" << line;
std::cerr << " with T a ";
if(T_is_signed)
std::cerr << "signed";
else
std::cerr << "unsigned";
std::cerr << " " << CHAR_BIT*T_size << "-bit integer type" << std::endl;
}
}
#define VERIFY_IMPL(x, expected) \
verify_impl_function((x), (expected), __FILE__, __LINE__, sizeof(T), integer_traits<T>::is_signed)
#define VERIFY(x) VERIFY_IMPL(x, true)
#define VERIFY_IS_FALSE(x) VERIFY_IMPL(x, false)
#define VERIFY_IS_VALID(x) VERIFY_IMPL((x).valid(), true)
#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).valid(), false)
#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).valid(), (condition))
template<typename T, unsigned int size = sizeof(T)>
struct test_twice_bigger_type
{
static void run()
{
VERIFY(integer_traits<T>::twice_bigger_type_is_supported);
VERIFY(sizeof(typename integer_traits<T>::twice_bigger_type)
== 2 * sizeof(T));
VERIFY(bool(integer_traits<
typename integer_traits<T>::twice_bigger_type
>::is_signed) == bool(integer_traits<T>::is_signed));
}
};
template<typename T>
struct test_twice_bigger_type<T, 8>
{
static void run()
{
VERIFY_IS_FALSE(integer_traits<T>::twice_bigger_type_is_supported);
}
};
template<typename T>
void test()
{
static bool already_run = false;
if (already_run) {
g_tests_failed++;
std::cerr << "You already tested this type. Copy/paste typo??" << std::endl;
return;
}
already_run = true;
VERIFY(integer_traits<T>::is_supported);
VERIFY(integer_traits<T>::size == sizeof(T));
enum{ is_signed = integer_traits<T>::is_signed };
VERIFY(bool(is_signed) == !bool(T(-1) > T(0)));
test_twice_bigger_type<T>::run();
typedef typename integer_traits<T>::unsigned_type unsigned_T;
VERIFY(sizeof(unsigned_T) == sizeof(T));
VERIFY(integer_traits<unsigned_T>::is_signed == false);
CheckedInt<T> max_value(integer_traits<T>::max_value());
CheckedInt<T> min_value(integer_traits<T>::min_value());
// check min_value() and max_value(), since they are custom implementations and a mistake there
// could potentially NOT be caught by any other tests... while making everything wrong!
T bit = 1;
for(unsigned int i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
{
VERIFY((min_value.value() & bit) == 0);
bit <<= 1;
}
VERIFY((min_value.value() & bit) == (is_signed ? bit : T(0)));
VERIFY(max_value.value() == T(~(min_value.value())));
CheckedInt<T> zero(0);
CheckedInt<T> one(1);
CheckedInt<T> two(2);
CheckedInt<T> three(3);
CheckedInt<T> four(4);
/* addition / substraction checks */
VERIFY_IS_VALID(zero+zero);
VERIFY(zero+zero == zero);
VERIFY_IS_FALSE(zero+zero == one); // check that == doesn't always return true
VERIFY_IS_VALID(zero+one);
VERIFY(zero+one == one);
VERIFY_IS_VALID(one+one);
VERIFY(one+one == two);
CheckedInt<T> max_value_minus_one = max_value - one;
CheckedInt<T> max_value_minus_two = max_value - two;
VERIFY_IS_VALID(max_value_minus_one);
VERIFY_IS_VALID(max_value_minus_two);
VERIFY_IS_VALID(max_value_minus_one + one);
VERIFY_IS_VALID(max_value_minus_two + one);
VERIFY_IS_VALID(max_value_minus_two + two);
VERIFY(max_value_minus_one + one == max_value);
VERIFY(max_value_minus_two + one == max_value_minus_one);
VERIFY(max_value_minus_two + two == max_value);
VERIFY_IS_VALID(max_value + zero);
VERIFY_IS_VALID(max_value - zero);
VERIFY_IS_INVALID(max_value + one);
VERIFY_IS_INVALID(max_value + two);
VERIFY_IS_INVALID(max_value + max_value_minus_one);
VERIFY_IS_INVALID(max_value + max_value);
CheckedInt<T> min_value_plus_one = min_value + one;
CheckedInt<T> min_value_plus_two = min_value + two;
VERIFY_IS_VALID(min_value_plus_one);
VERIFY_IS_VALID(min_value_plus_two);
VERIFY_IS_VALID(min_value_plus_one - one);
VERIFY_IS_VALID(min_value_plus_two - one);
VERIFY_IS_VALID(min_value_plus_two - two);
VERIFY(min_value_plus_one - one == min_value);
VERIFY(min_value_plus_two - one == min_value_plus_one);
VERIFY(min_value_plus_two - two == min_value);
CheckedInt<T> min_value_minus_one = min_value - one;
VERIFY_IS_VALID(min_value + zero);
VERIFY_IS_VALID(min_value - zero);
VERIFY_IS_INVALID(min_value - one);
VERIFY_IS_INVALID(min_value - two);
VERIFY_IS_INVALID(min_value - min_value_minus_one);
VERIFY_IS_VALID(min_value - min_value);
CheckedInt<T> max_value_over_two = max_value / two;
VERIFY_IS_VALID(max_value_over_two + max_value_over_two);
VERIFY_IS_VALID(max_value_over_two + one);
VERIFY((max_value_over_two + one) - one == max_value_over_two);
VERIFY_IS_VALID(max_value_over_two - max_value_over_two);
VERIFY(max_value_over_two - max_value_over_two == zero);
CheckedInt<T> min_value_over_two = min_value / two;
VERIFY_IS_VALID(min_value_over_two + min_value_over_two);
VERIFY_IS_VALID(min_value_over_two + one);
VERIFY((min_value_over_two + one) - one == min_value_over_two);
VERIFY_IS_VALID(min_value_over_two - min_value_over_two);
VERIFY(min_value_over_two - min_value_over_two == zero);
VERIFY_IS_INVALID(min_value - one);
VERIFY_IS_INVALID(min_value - two);
if (is_signed) {
VERIFY_IS_INVALID(min_value + min_value);
VERIFY_IS_INVALID(min_value_over_two + min_value_over_two + min_value_over_two);
VERIFY_IS_INVALID(zero - min_value + min_value);
VERIFY_IS_INVALID(one - min_value + min_value);
}
/* unary operator- checks */
CheckedInt<T> neg_one = -one;
CheckedInt<T> neg_two = -two;
if (is_signed) {
VERIFY_IS_VALID(-max_value);
VERIFY_IS_VALID(-max_value - one);
VERIFY_IS_VALID(neg_one);
VERIFY_IS_VALID(-max_value + neg_one);
VERIFY_IS_VALID(neg_one + one);
VERIFY(neg_one + one == zero);
VERIFY_IS_VALID(neg_two);
VERIFY_IS_VALID(neg_one + neg_one);
VERIFY(neg_one + neg_one == neg_two);
} else {
VERIFY_IS_INVALID(neg_one);
}
/* multiplication checks */
VERIFY_IS_VALID(zero*zero);
VERIFY(zero*zero == zero);
VERIFY_IS_VALID(zero*one);
VERIFY(zero*one == zero);
VERIFY_IS_VALID(one*zero);
VERIFY(one*zero == zero);
VERIFY_IS_VALID(one*one);
VERIFY(one*one == one);
VERIFY_IS_VALID(one*three);
VERIFY(one*three == three);
VERIFY_IS_VALID(two*two);
VERIFY(two*two == four);
VERIFY_IS_INVALID(max_value * max_value);
VERIFY_IS_INVALID(max_value_over_two * max_value);
VERIFY_IS_INVALID(max_value_over_two * max_value_over_two);
CheckedInt<T> max_value_approx_sqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
VERIFY_IS_VALID(max_value_approx_sqrt);
VERIFY_IS_VALID(max_value_approx_sqrt * two);
VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt);
VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt * max_value_approx_sqrt);
if (is_signed) {
VERIFY_IS_INVALID(min_value * min_value);
VERIFY_IS_INVALID(min_value_over_two * min_value);
VERIFY_IS_INVALID(min_value_over_two * min_value_over_two);
CheckedInt<T> min_value_approx_sqrt = -max_value_approx_sqrt;
VERIFY_IS_VALID(min_value_approx_sqrt);
VERIFY_IS_VALID(min_value_approx_sqrt * two);
VERIFY_IS_INVALID(min_value_approx_sqrt * max_value_approx_sqrt);
VERIFY_IS_INVALID(min_value_approx_sqrt * min_value_approx_sqrt);
}
// make sure to check all 4 paths in signed multiplication validity check.
// test positive * positive
VERIFY_IS_VALID(max_value * one);
VERIFY(max_value * one == max_value);
VERIFY_IS_INVALID(max_value * two);
VERIFY_IS_VALID(max_value_over_two * two);
VERIFY((max_value_over_two + max_value_over_two) == (max_value_over_two * two));
if (is_signed) {
// test positive * negative
VERIFY_IS_VALID(max_value * neg_one);
VERIFY_IS_VALID(-max_value);
VERIFY(max_value * neg_one == -max_value);
VERIFY_IS_VALID(one * min_value);
VERIFY_IS_INVALID(max_value * neg_two);
VERIFY_IS_VALID(max_value_over_two * neg_two);
VERIFY_IS_VALID(two * min_value_over_two);
VERIFY_IS_VALID((max_value_over_two + one) * neg_two);
VERIFY_IS_INVALID((max_value_over_two + two) * neg_two);
VERIFY_IS_INVALID(two * (min_value_over_two - one));
// test negative * positive
VERIFY_IS_VALID(min_value * one);
VERIFY_IS_VALID(min_value_plus_one * one);
VERIFY_IS_INVALID(min_value * two);
VERIFY_IS_VALID(min_value_over_two * two);
VERIFY(min_value_over_two * two == min_value);
VERIFY_IS_INVALID((min_value_over_two - one) * neg_two);
VERIFY_IS_INVALID(neg_two * max_value);
VERIFY_IS_VALID(min_value_over_two * two);
VERIFY(min_value_over_two * two == min_value);
VERIFY_IS_VALID(neg_two * max_value_over_two);
VERIFY_IS_INVALID((min_value_over_two - one) * two);
VERIFY_IS_VALID(neg_two * (max_value_over_two + one));
VERIFY_IS_INVALID(neg_two * (max_value_over_two + two));
// test negative * negative
VERIFY_IS_INVALID(min_value * neg_one);
VERIFY_IS_VALID(min_value_plus_one * neg_one);
VERIFY(min_value_plus_one * neg_one == max_value);
VERIFY_IS_INVALID(min_value * neg_two);
VERIFY_IS_INVALID(min_value_over_two * neg_two);
VERIFY_IS_INVALID(neg_one * min_value);
VERIFY_IS_VALID(neg_one * min_value_plus_one);
VERIFY(neg_one * min_value_plus_one == max_value);
VERIFY_IS_INVALID(neg_two * min_value);
VERIFY_IS_INVALID(neg_two * min_value_over_two);
}
/* division checks */
VERIFY_IS_VALID(one / one);
VERIFY(one / one == one);
VERIFY_IS_VALID(three / three);
VERIFY(three / three == one);
VERIFY_IS_VALID(four / two);
VERIFY(four / two == two);
VERIFY((four*three)/four == three);
// check that div by zero is invalid
VERIFY_IS_INVALID(zero / zero);
VERIFY_IS_INVALID(one / zero);
VERIFY_IS_INVALID(two / zero);
VERIFY_IS_INVALID(neg_one / zero);
VERIFY_IS_INVALID(max_value / zero);
VERIFY_IS_INVALID(min_value / zero);
if (is_signed) {
// check that min_value / -1 is invalid
VERIFY_IS_INVALID(min_value / neg_one);
// check that the test for div by -1 isn't banning other numerators than min_value
VERIFY_IS_VALID(one / neg_one);
VERIFY_IS_VALID(zero / neg_one);
VERIFY_IS_VALID(neg_one / neg_one);
VERIFY_IS_VALID(max_value / neg_one);
}
/* check that invalidity is correctly preserved by arithmetic ops */
CheckedInt<T> some_invalid = max_value + max_value;
VERIFY_IS_INVALID(some_invalid + zero);
VERIFY_IS_INVALID(some_invalid - zero);
VERIFY_IS_INVALID(zero + some_invalid);
VERIFY_IS_INVALID(zero - some_invalid);
VERIFY_IS_INVALID(-some_invalid);
VERIFY_IS_INVALID(some_invalid * zero);
VERIFY_IS_INVALID(some_invalid * one);
VERIFY_IS_INVALID(zero * some_invalid);
VERIFY_IS_INVALID(one * some_invalid);
VERIFY_IS_INVALID(some_invalid / zero);
VERIFY_IS_INVALID(some_invalid / one);
VERIFY_IS_INVALID(zero / some_invalid);
VERIFY_IS_INVALID(one / some_invalid);
VERIFY_IS_INVALID(some_invalid + some_invalid);
VERIFY_IS_INVALID(some_invalid - some_invalid);
VERIFY_IS_INVALID(some_invalid * some_invalid);
VERIFY_IS_INVALID(some_invalid / some_invalid);
/* check that mixing checked integers with plain integers in expressions is allowed */
VERIFY(one + T(2) == three);
VERIFY(2 + one == three);
{
CheckedInt<T> x = one;
x += 2;
VERIFY(x == three);
}
VERIFY(two - 1 == one);
VERIFY(2 - one == one);
{
CheckedInt<T> x = two;
x -= 1;
VERIFY(x == one);
}
VERIFY(one * 2 == two);
VERIFY(2 * one == two);
{
CheckedInt<T> x = one;
x *= 2;
VERIFY(x == two);
}
VERIFY(four / 2 == two);
VERIFY(4 / two == two);
{
CheckedInt<T> x = four;
x /= 2;
VERIFY(x == two);
}
VERIFY(one == 1);
VERIFY(1 == one);
VERIFY_IS_FALSE(two == 1);
VERIFY_IS_FALSE(1 == two);
VERIFY_IS_FALSE(some_invalid == 1);
VERIFY_IS_FALSE(1 == some_invalid);
/* Check that construction of CheckedInt from an integer value of a mismatched type is checked */
#define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
{ \
bool is_U_signed = integer_traits<U>::is_signed; \
VERIFY_IS_VALID(CheckedInt<T>(U(0))); \
VERIFY_IS_VALID(CheckedInt<T>(U(1))); \
VERIFY_IS_VALID(CheckedInt<T>(U(100))); \
if (is_U_signed) \
VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), is_signed); \
if (sizeof(U) > sizeof(T)) \
VERIFY_IS_INVALID(CheckedInt<T>(U(integer_traits<T>::max_value())+1)); \
VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::max_value()), \
(sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (is_U_signed || !is_signed)))); \
VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::min_value()), \
is_U_signed == false ? 1 : \
bool(is_signed) == false ? 0 : \
sizeof(T) >= sizeof(U)); \
}
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt8)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint8)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt16)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint16)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt32)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint32)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt64)
VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint64)
/* Test increment/decrement operators */
CheckedInt<T> x, y;
x = one;
y = x++;
VERIFY(x == two);
VERIFY(y == one);
x = one;
y = ++x;
VERIFY(x == two);
VERIFY(y == two);
x = one;
y = x--;
VERIFY(x == zero);
VERIFY(y == one);
x = one;
y = --x;
VERIFY(x == zero);
VERIFY(y == zero);
x = max_value;
VERIFY_IS_VALID(x++);
x = max_value;
VERIFY_IS_INVALID(++x);
x = min_value;
VERIFY_IS_VALID(x--);
x = min_value;
VERIFY_IS_INVALID(--x);
}
} // end namespace CheckedInt_test
int main()
{
CheckedInt_test::test<PRInt8>();
CheckedInt_test::test<PRUint8>();
CheckedInt_test::test<PRInt16>();
CheckedInt_test::test<PRUint16>();
CheckedInt_test::test<PRInt32>();
CheckedInt_test::test<PRUint32>();
CheckedInt_test::test<PRInt64>();
CheckedInt_test::test<PRUint64>();
std::cerr << CheckedInt_test::g_tests_failed << " tests failed, "
<< CheckedInt_test::g_tests_passed << " tests passed out of "
<< CheckedInt_test::g_tests_failed + CheckedInt_test::g_tests_passed
<< " tests." << std::endl;
return CheckedInt_test::g_tests_failed > 0;
}