diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkBitmap.cpp | 8 | ||||
-rw-r--r-- | src/core/SkBitmapProcState.cpp | 2 | ||||
-rw-r--r-- | src/core/SkFlattenableBuffers.cpp | 3 | ||||
-rw-r--r-- | src/core/SkFlattenableSerialization.cpp | 12 | ||||
-rw-r--r-- | src/core/SkImageFilter.cpp | 2 | ||||
-rw-r--r-- | src/core/SkOrderedWriteBuffer.cpp | 13 | ||||
-rw-r--r-- | src/core/SkValidatingReadBuffer.cpp | 290 | ||||
-rw-r--r-- | src/core/SkValidatingReadBuffer.h | 141 | ||||
-rw-r--r-- | src/core/SkValidationUtils.h | 46 | ||||
-rw-r--r-- | src/core/SkXfermode.cpp | 5 |
10 files changed, 510 insertions, 12 deletions
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index d3bbecd706..762abc0bf1 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -19,6 +19,7 @@ #include "SkThread.h" #include "SkUnPreMultiply.h" #include "SkUtils.h" +#include "SkValidationUtils.h" #include "SkPackBits.h" #include <new> @@ -1607,9 +1608,11 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { int width = buffer.readInt(); int height = buffer.readInt(); int rowBytes = buffer.readInt(); - int config = buffer.readInt(); + Config config = (Config)buffer.readInt(); + buffer.validate((width >= 0) && (height >= 0) && (rowBytes >= 0) && + SkIsValidConfig(config)); - this->setConfig((Config)config, width, height, rowBytes); + this->setConfig(config, width, height, rowBytes); this->setIsOpaque(buffer.readBool()); int reftype = buffer.readInt(); @@ -1623,6 +1626,7 @@ void SkBitmap::unflatten(SkFlattenableReadBuffer& buffer) { case SERIALIZE_PIXELTYPE_NONE: break; default: + buffer.validate(false); SkDEBUGFAIL("unrecognized pixeltype in serialized data"); sk_throw(); } diff --git a/src/core/SkBitmapProcState.cpp b/src/core/SkBitmapProcState.cpp index 9ecfc2280b..2b0e557610 100644 --- a/src/core/SkBitmapProcState.cpp +++ b/src/core/SkBitmapProcState.cpp @@ -332,7 +332,7 @@ bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) { return false; } } - + SkASSERT(fBitmap); bool trivialMatrix = (fInvMatrix.getType() & ~SkMatrix::kTranslate_Mask) == 0; diff --git a/src/core/SkFlattenableBuffers.cpp b/src/core/SkFlattenableBuffers.cpp index 50a47d5c47..72cd492cd8 100644 --- a/src/core/SkFlattenableBuffers.cpp +++ b/src/core/SkFlattenableBuffers.cpp @@ -9,7 +9,8 @@ #include "SkPaint.h" #include "SkTypeface.h" -SkFlattenableReadBuffer::SkFlattenableReadBuffer() { +SkFlattenableReadBuffer::SkFlattenableReadBuffer() : + fError(false) { // Set default values. These should be explicitly set by our client // via setFlags() if the buffer came from serialization. fFlags = 0; diff --git a/src/core/SkFlattenableSerialization.cpp b/src/core/SkFlattenableSerialization.cpp index b74c82f051..63180532d9 100644 --- a/src/core/SkFlattenableSerialization.cpp +++ b/src/core/SkFlattenableSerialization.cpp @@ -9,12 +9,12 @@ #include "SkData.h" #include "SkFlattenable.h" -#include "SkOrderedReadBuffer.h" +#include "SkValidatingReadBuffer.h" #include "SkOrderedWriteBuffer.h" -SkData* SkSerializeFlattenable(SkFlattenable* flattenable) { +SkData* SkValidatingSerializeFlattenable(SkFlattenable* flattenable) { SkOrderedWriteBuffer writer(1024); - writer.setFlags(SkOrderedWriteBuffer::kCrossProcess_Flag); + writer.setFlags(SkOrderedWriteBuffer::kValidation_Flag); writer.writeFlattenable(flattenable); uint32_t size = writer.bytesWritten(); void* data = sk_malloc_throw(size); @@ -22,7 +22,7 @@ SkData* SkSerializeFlattenable(SkFlattenable* flattenable) { return SkData::NewFromMalloc(data, size); } -SkFlattenable* SkDeserializeFlattenable(const void* data, size_t size) { - SkOrderedReadBuffer buffer(data, size); - return buffer.readFlattenable(); +SkFlattenable* SkValidatingDeserializeFlattenable(const void* data, size_t size) { + SkValidatingReadBuffer reader(data, size); + return reader.readFlattenable(); } diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp index 502613bb68..89b2cc50d8 100644 --- a/src/core/SkImageFilter.cpp +++ b/src/core/SkImageFilter.cpp @@ -10,6 +10,7 @@ #include "SkBitmap.h" #include "SkFlattenableBuffers.h" #include "SkRect.h" +#include "SkValidationUtils.h" #if SK_SUPPORT_GPU #include "GrContext.h" #include "GrTexture.h" @@ -62,6 +63,7 @@ SkImageFilter::SkImageFilter(SkFlattenableReadBuffer& buffer) } } buffer.readIRect(&fCropRect); + buffer.validate(SkIsValidRect(fCropRect)); } void SkImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { diff --git a/src/core/SkOrderedWriteBuffer.cpp b/src/core/SkOrderedWriteBuffer.cpp index 64f52193ac..708a7067bd 100644 --- a/src/core/SkOrderedWriteBuffer.cpp +++ b/src/core/SkOrderedWriteBuffer.cpp @@ -270,7 +270,9 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { factory = flattenable->getFactory(); } if (NULL == factory) { - if (fFactorySet != NULL || fNamedFactorySet != NULL) { + if (this->isValidating()) { + this->writeString(NULL); + } else if (fFactorySet != NULL || fNamedFactorySet != NULL) { this->write32(0); } else { this->writeFunctionPtr(NULL); @@ -290,7 +292,14 @@ void SkOrderedWriteBuffer::writeFlattenable(SkFlattenable* flattenable) { * name. SkGPipe uses this technique so it can write the name to its * stream before writing the flattenable. */ - if (fFactorySet) { + if (this->isValidating()) { + const char* name = SkFlattenable::FactoryToName(factory); + this->writeString(name); + if (NULL == name) { + SkASSERT(0); // Missing factory name + return; + } + } else if (fFactorySet) { this->write32(fFactorySet->add(factory)); } else if (fNamedFactorySet) { int32_t index = fNamedFactorySet->find(factory); diff --git a/src/core/SkValidatingReadBuffer.cpp b/src/core/SkValidatingReadBuffer.cpp new file mode 100644 index 0000000000..b8247ab566 --- /dev/null +++ b/src/core/SkValidatingReadBuffer.cpp @@ -0,0 +1,290 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkBitmap.h" +#include "SkErrorInternals.h" +#include "SkValidatingReadBuffer.h" +#include "SkStream.h" +#include "SkTypeface.h" + +SkValidatingReadBuffer::SkValidatingReadBuffer() : INHERITED() { + fMemoryPtr = NULL; + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; + fBitmapDecoder = NULL; +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + fDecodedBitmapIndex = -1; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + setFlags(SkFlattenableReadBuffer::kValidation_Flag); +} + +SkValidatingReadBuffer::SkValidatingReadBuffer(const void* data, size_t size) : INHERITED() { + this->setMemory(data, size); + fMemoryPtr = NULL; + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; + fBitmapDecoder = NULL; +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + fDecodedBitmapIndex = -1; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + setFlags(SkFlattenableReadBuffer::kValidation_Flag); +} + +SkValidatingReadBuffer::SkValidatingReadBuffer(SkStream* stream) { + const size_t length = stream->getLength(); + fMemoryPtr = sk_malloc_throw(length); + stream->read(fMemoryPtr, length); + this->setMemory(fMemoryPtr, length); + + fBitmapStorage = NULL; + fTFArray = NULL; + fTFCount = 0; + + fFactoryTDArray = NULL; + fFactoryArray = NULL; + fFactoryCount = 0; + fBitmapDecoder = NULL; +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + fDecodedBitmapIndex = -1; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + setFlags(SkFlattenableReadBuffer::kValidation_Flag); +} + +SkValidatingReadBuffer::~SkValidatingReadBuffer() { + sk_free(fMemoryPtr); + SkSafeUnref(fBitmapStorage); +} + +void SkValidatingReadBuffer::setMemory(const void* data, size_t size) { + fError |= (!ptr_align_4(data) || (SkAlign4(size) != size)); + if (!fError) { + fReader.setMemory(data, size); + } +} + +const void* SkValidatingReadBuffer::skip(size_t size) { + size_t inc = SkAlign4(size); + const void* addr = fReader.peek(); + fError |= !ptr_align_4(addr) || !fReader.isAvailable(inc); + if (!fError) { + fReader.skip(size); + } + return addr; +} + +bool SkValidatingReadBuffer::readBool() { + return this->readInt() != 0; +} + +SkColor SkValidatingReadBuffer::readColor() { + return this->readInt(); +} + +SkFixed SkValidatingReadBuffer::readFixed() { + return this->readInt(); +} + +int32_t SkValidatingReadBuffer::readInt() { + size_t inc = sizeof(int32_t); + fError |= !ptr_align_4(fReader.peek()) || !fReader.isAvailable(inc); + return fError ? 0 : fReader.readInt(); +} + +SkScalar SkValidatingReadBuffer::readScalar() { + size_t inc = sizeof(SkScalar); + fError |= !ptr_align_4(fReader.peek()) || !fReader.isAvailable(inc); + return fError ? 0 : fReader.readScalar(); +} + +uint32_t SkValidatingReadBuffer::readUInt() { + return this->readInt(); +} + +int32_t SkValidatingReadBuffer::read32() { + return this->readInt(); +} + +void SkValidatingReadBuffer::readString(SkString* string) { + size_t len = this->readInt(); + const void* ptr = fReader.peek(); + + // skip over the string + '\0' and then pad to a multiple of 4 + size_t alignedSize = SkAlign4(len + 1); + this->skip(alignedSize); + if (!fError) { + string->set((const char*)ptr, len); + } +} + +void* SkValidatingReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) { + int32_t encodingType = fReader.readInt(); + if (encodingType == encoding) { + fError = true; + } + *length = this->readInt(); + const void* ptr = this->skip(SkAlign4(*length)); + void* data = NULL; + if (!fError) { + data = sk_malloc_throw(*length); + memcpy(data, ptr, *length); + } + return data; +} + +void SkValidatingReadBuffer::readPoint(SkPoint* point) { + point->fX = fReader.readScalar(); + point->fY = fReader.readScalar(); +} + +void SkValidatingReadBuffer::readMatrix(SkMatrix* matrix) { + size_t size = matrix->readFromMemory(fReader.peek()); + fError |= (SkAlign4(size) != size); + if (!fError) { + (void)this->skip(size); + } +} + +void SkValidatingReadBuffer::readIRect(SkIRect* rect) { + memcpy(rect, this->skip(sizeof(SkIRect)), sizeof(SkIRect)); +} + +void SkValidatingReadBuffer::readRect(SkRect* rect) { + memcpy(rect, this->skip(sizeof(SkRect)), sizeof(SkRect)); +} + +void SkValidatingReadBuffer::readRegion(SkRegion* region) { + size_t size = region->readFromMemory(fReader.peek()); + fError |= (SkAlign4(size) != size); + if (!fError) { + (void)this->skip(size); + } +} + +void SkValidatingReadBuffer::readPath(SkPath* path) { + size_t size = path->readFromMemory(fReader.peek()); + fError |= (SkAlign4(size) != size); + if (!fError) { + (void)this->skip(size); + } +} + +uint32_t SkValidatingReadBuffer::readByteArray(void* value) { + const uint32_t length = this->readUInt(); + memcpy(value, this->skip(SkAlign4(length)), length); + return fError ? 0 : length; +} + +uint32_t SkValidatingReadBuffer::readColorArray(SkColor* colors) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(SkColor); + memcpy(colors, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::readIntArray(int32_t* values) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(int32_t); + memcpy(values, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::readPointArray(SkPoint* points) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(SkPoint); + memcpy(points, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::readScalarArray(SkScalar* values) { + const uint32_t count = this->readUInt(); + const uint32_t byteLength = count * sizeof(SkScalar); + memcpy(values, this->skip(SkAlign4(byteLength)), byteLength); + return fError ? 0 : count; +} + +uint32_t SkValidatingReadBuffer::getArrayCount() { + return *(uint32_t*)fReader.peek(); +} + +void SkValidatingReadBuffer::readBitmap(SkBitmap* bitmap) { + const int width = this->readInt(); + const int height = this->readInt(); + const size_t length = this->readUInt(); + // A size of zero means the SkBitmap was simply flattened. + if (length != 0) { + fError = true; + } + if (fError) { + return; + } + bitmap->unflatten(*this); + if ((bitmap->width() != width) || (bitmap->height() != height)) { + fError = true; + } +} + +SkTypeface* SkValidatingReadBuffer::readTypeface() { + + uint32_t index = this->readUInt(); + if (0 == index || index > (unsigned)fTFCount || fError) { + if (index) { + SkDebugf("====== typeface index %d\n", index); + } + return NULL; + } else { + SkASSERT(fTFArray); + return fTFArray[index - 1]; + } +} + +SkFlattenable* SkValidatingReadBuffer::readFlattenable() { + SkString string; + this->readString(&string); + if (fError) { + return NULL; + } + SkFlattenable::Factory factory = SkFlattenable::NameToFactory(string.c_str()); + if (NULL == factory) { + return NULL; // writer failed to give us the flattenable + } + + // if we get here, factory may still be null, but if that is the case, the + // failure was ours, not the writer. + SkFlattenable* obj = NULL; + uint32_t sizeRecorded = this->readUInt(); + if (factory) { + uint32_t offset = fReader.offset(); + obj = (*factory)(*this); + // check that we read the amount we expected + uint32_t sizeRead = fReader.offset() - offset; + if (sizeRecorded != sizeRead) { + // we could try to fix up the offset... + fError = true; + delete obj; + obj = NULL; + } + } else { + // we must skip the remaining data + this->skip(sizeRecorded); + } + return obj; +} diff --git a/src/core/SkValidatingReadBuffer.h b/src/core/SkValidatingReadBuffer.h new file mode 100644 index 0000000000..accf5d75f9 --- /dev/null +++ b/src/core/SkValidatingReadBuffer.h @@ -0,0 +1,141 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkValidatingReadBuffer_DEFINED +#define SkValidatingReadBuffer_DEFINED + +#include "SkRefCnt.h" +#include "SkBitmapHeap.h" +#include "SkFlattenableBuffers.h" +#include "SkPath.h" +#include "SkPicture.h" +#include "SkReader32.h" + +class SkBitmap; + +#if defined(SK_DEBUG) && defined(SK_BUILD_FOR_MAC) + #define DEBUG_NON_DETERMINISTIC_ASSERT +#endif + +class SkValidatingReadBuffer : public SkFlattenableReadBuffer { +public: + SkValidatingReadBuffer(); + SkValidatingReadBuffer(const void* data, size_t size); + SkValidatingReadBuffer(SkStream* stream); + virtual ~SkValidatingReadBuffer(); + + SkReader32* getReader32() { return &fReader; } + + uint32_t size() { return fReader.size(); } + uint32_t offset() { return fReader.offset(); } + bool eof() { return fReader.eof(); } + const void* skip(size_t size); + + // primitives + virtual bool readBool() SK_OVERRIDE; + virtual SkColor readColor() SK_OVERRIDE; + virtual SkFixed readFixed() SK_OVERRIDE; + virtual int32_t readInt() SK_OVERRIDE; + virtual SkScalar readScalar() SK_OVERRIDE; + virtual uint32_t readUInt() SK_OVERRIDE; + virtual int32_t read32() SK_OVERRIDE; + + // strings -- the caller is responsible for freeing the string contents + virtual void readString(SkString* string) SK_OVERRIDE; + virtual void* readEncodedString(size_t* length, SkPaint::TextEncoding encoding) SK_OVERRIDE; + + // common data structures + virtual SkFlattenable* readFlattenable() SK_OVERRIDE; + virtual void readPoint(SkPoint* point) SK_OVERRIDE; + virtual void readMatrix(SkMatrix* matrix) SK_OVERRIDE; + virtual void readIRect(SkIRect* rect) SK_OVERRIDE; + virtual void readRect(SkRect* rect) SK_OVERRIDE; + virtual void readRegion(SkRegion* region) SK_OVERRIDE; + virtual void readPath(SkPath* path) SK_OVERRIDE; + + // binary data and arrays + virtual uint32_t readByteArray(void* value) SK_OVERRIDE; + virtual uint32_t readColorArray(SkColor* colors) SK_OVERRIDE; + virtual uint32_t readIntArray(int32_t* values) SK_OVERRIDE; + virtual uint32_t readPointArray(SkPoint* points) SK_OVERRIDE; + virtual uint32_t readScalarArray(SkScalar* values) SK_OVERRIDE; + + // helpers to get info about arrays and binary data + virtual uint32_t getArrayCount() SK_OVERRIDE; + + virtual void readBitmap(SkBitmap* bitmap) SK_OVERRIDE; + virtual SkTypeface* readTypeface() SK_OVERRIDE; + + void setBitmapStorage(SkBitmapHeapReader* bitmapStorage) { + SkRefCnt_SafeAssign(fBitmapStorage, bitmapStorage); + } + + void setTypefaceArray(SkTypeface* array[], int count) { + fTFArray = array; + fTFCount = count; + } + + /** + * Call this with a pre-loaded array of Factories, in the same order as + * were created/written by the writer. SkPicture uses this. + */ + void setFactoryPlayback(SkFlattenable::Factory array[], int count) { + fFactoryTDArray = NULL; + fFactoryArray = array; + fFactoryCount = count; + } + + /** + * Call this with an initially empty array, so the reader can cache each + * factory it sees by name. Used by the pipe code in conjunction with + * SkOrderedWriteBuffer::setNamedFactoryRecorder. + */ + void setFactoryArray(SkTDArray<SkFlattenable::Factory>* array) { + fFactoryTDArray = array; + fFactoryArray = NULL; + fFactoryCount = 0; + } + + /** + * Provide a function to decode an SkBitmap from encoded data. Only used if the writer + * encoded the SkBitmap. If the proper decoder cannot be used, a red bitmap with the + * appropriate size will be used. + */ + void setBitmapDecoder(SkPicture::InstallPixelRefProc bitmapDecoder) { + fBitmapDecoder = bitmapDecoder; + } + +private: + void setMemory(const void* data, size_t size); + + static bool ptr_align_4(const void* ptr) { + return (((const char*)ptr - (const char*)NULL) & 3) == 0; + } + + SkReader32 fReader; + void* fMemoryPtr; + + SkBitmapHeapReader* fBitmapStorage; + SkTypeface** fTFArray; + int fTFCount; + + SkTDArray<SkFlattenable::Factory>* fFactoryTDArray; + SkFlattenable::Factory* fFactoryArray; + int fFactoryCount; + + SkPicture::InstallPixelRefProc fBitmapDecoder; + +#ifdef DEBUG_NON_DETERMINISTIC_ASSERT + // Debugging counter to keep track of how many bitmaps we + // have decoded. + int fDecodedBitmapIndex; +#endif // DEBUG_NON_DETERMINISTIC_ASSERT + + typedef SkFlattenableReadBuffer INHERITED; +}; + +#endif // SkValidatingReadBuffer_DEFINED diff --git a/src/core/SkValidationUtils.h b/src/core/SkValidationUtils.h new file mode 100644 index 0000000000..f31d86ce22 --- /dev/null +++ b/src/core/SkValidationUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkValidationUtils_DEFINED +#define SkValidationUtils_DEFINED + +#include "SkBitmap.h" +#include "SkXfermode.h" + +/** Returns true if coeff's value is in the SkXfermode::Coeff enum. + */ +static inline bool SkIsValidCoeff(SkXfermode::Coeff coeff) { + return coeff >= 0 && coeff < SkXfermode::kCoeffCount; +} + +/** Returns true if mode's value is in the SkXfermode::Mode enum. + */ +static inline bool SkIsValidMode(SkXfermode::Mode mode) { + return (mode >= 0) && (mode <= SkXfermode::kLastMode); +} + +/** Returns true if config's value is in the SkBitmap::Config enum. + */ +static inline bool SkIsValidConfig(SkBitmap::Config config) { + return (config >= 0) && (config <= SkBitmap::kLastConfig); +} + +/** Returns true if the rect's dimensions are between 0 and SK_MaxS32 + */ +static inline bool SkIsValidRect(const SkIRect& rect) { + return rect.width() >= 0 && rect.height() >= 0; +} + +/** Returns true if the rect's dimensions are between 0 and SK_ScalarMax + */ +static inline bool SkIsValidRect(const SkRect& rect) { + return !rect.isInverted() && + SkScalarIsFinite(rect.width()) && + SkScalarIsFinite(rect.height()); +} + +#endif diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index ac5cee4e35..9c5ccccd92 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -12,6 +12,7 @@ #include "SkFlattenableBuffers.h" #include "SkMathPriv.h" #include "SkString.h" +#include "SkValidationUtils.h" SK_DEFINE_INST_COUNT(SkXfermode) @@ -1438,6 +1439,10 @@ protected: fDstCoeff = rec.fDC; // now update our function-ptr in the super class this->INHERITED::setProc(rec.fProc); + + buffer.validate(SkIsValidMode(fMode) && + SkIsValidCoeff(fSrcCoeff) && + SkIsValidCoeff(fDstCoeff)); } virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE { |